how to display an image on a wall 3D?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By dmarques42

Sorry for the beginner question, but I am spinning my wheels.

I am an experienced programmer, in python and in 2D game engines, new to 3D and to Godot. I have read through the docs and API especially quite a bit, followed a few tutorials, but cannot find an example that helps or find anything with search. Apologies if I have missed it.

Context: Simple room with 4 walls, and a signal (that I created) should change the image (via texture, I think) on a wall.

What works: The signal works, the image load works, texture creation, no error spit out.

Problem: The wall just turns white, no image on it that I can detect. I am not understanding how to use an image as a texture. Maybe I have to create the wall as a different kind of surface? (I also tried putting the image on a plane, same result.)

Relevant code: (excuse the naive code, array, this is just to get it working)
[full source code for a newer version of this simple test is available at https://www.ideategames.org/Rooms1.zip]

var mats = []

func _set_image(wnum,inum):
    print("setting image wall: "+str(wnum)+":"+str(inum))
    var tex = ImageTexture.new()
	tex.create_from_image(mats[inum],1)
    # this next line makes no difference that I can see, 
    # no matter the values, 0.25 - 200
	tex.set_size_override(Vector2(200,200))

	var wnode = "../Wall"+str(wnum)+"/WallMesh"
    # both methods below have the same result
    # changing the surface number results in no error but no change
	get_node(wnode).set_surface_material(0,tex)
	# get_node(wnode).texture = tex


# Called when the node enters the scene tree for the first time.
func _ready():
    mats.append(Image.new())
    mats[-1].load("images/Birth_Of_Venus.jpg")
    # this doesn't seem to make any difference no matter the values
    mats[-1].resize(0.25,0.25)
    get_node("../Player").connect("wall_image", self, "_set_image")
:bust_in_silhouette: Reply From: sash-rc

You’re over-complicating things.

Mostly (except special cases) you don’t need “Texture from Image”. You need simply imported Texture.

To display picture on a surface of mesh-based node, you should use its Material (SpatialMaterial) and set Texture for Albedo for very basic cases.

func _ready():  
  var boxNode : CSGBox = "../path/to/node" # with type hinting
  var texture = load("res://path/to/your/texture.png") #imported texture
  var mat : SpatialMaterial = boxNode.material
  if !mat : # in case no material created (in editor / elsewhere)
    mat = SpatialMaterial.new()
    boxNode.material = mat
  mat.albedo_texture = texture

But in case you really need an image, try this: https://forum.godotengine.org/50876/load-texture-from-file-and-assign-to-texture

p.s. Also, didn’t get why do you need a signal, instead of plain function call.

Thank you, sorry, didn’t see your answer before I wrote, though I did refresh. Apologies. You have the SpatialMateral.new() which is what I was missing.

I know the textures can be loaded directly. I had the design that way originally, but as it didn’t work, doing the two steps was just trying something to see if that was a problem. Now that I have it working, I can go back and simplify.

For the P.S.:
I use signals because I like the structure and independence of signals (or event-driven) design. In theory, the same type of event (eg in a multi-person economics game) can be triggered by a variety of causes and actions.

Of course, as far as I can tell so far, I cannot send an event from an anonymous source (such as all events from the top node), so kind of reduces the value, events can only be sent by self and recognized by source. So I am rethinking that.

dmarques42 | 2020-11-22 00:46

:bust_in_silhouette: Reply From: dmarques42

I figured it out – I have to make a new SpatialMaterial first, then put the texture on it, then replace the Material on the wall with the new Spatial Material

	var tex = ImageTexture.new()
	tex.create_from_image(thisimg,0)

	var cmat = SpatialMaterial.new()
	cmat.albedo_texture = tex

	wnode.set_surface_material(0,cmat)