Set texture to blender exported plane shows black

Hi,

I created a plane in blender 2.9 and exported it to bam with blend2bam. Then I loaded it in the code and try to set texture for it, but it is always black.

Below is the code I used. Is there any special setting in Blender/Panda3D I missed?

import numpy as np
import glob
from direct.showbase.ShowBase import ShowBase

from panda3d.core import PerspectiveLens, TextureStage, CardMaker, Filename
from panda3d.core import Material, AmbientLight, VBase3, Spotlight, VBase4
import simplepbr


class App(ShowBase):
  def __init__(self):
    ShowBase.__init__(self)
    simplepbr.init()
    
    ppt_slides = glob.glob('textures' + "/*.png") + glob.glob('textures' + "/*.jpg")
    self.ppt_tex = [self.loader.loadTexture(Filename.fromOsSpecific(f)) for f in ppt_slides]

    model = self.loader.loadModel("plane.bam")
    model.reparentTo(self.render)
    test_plane = self.render.find("**/Plane")

    if test_plane:
      test_plane.setTexScale(TextureStage.getDefault(), -1, 1)
      test_plane.setShaderAuto(False)
      test_plane.setTexture(self.ppt_tex[0])

    card = CardMaker('ppt')
    self.ppt_board = self.render.attachNewNode(card.generate())
    self.ppt_board.setTwoSided(True)
    self.ppt_board.setPos(1, 1, 1)
    self.ppt_board.reparentTo(self.render)
    self.ppt_board.setTexScale(TextureStage.getDefault(), -1, 1)
    self.ppt_board.setShaderAuto(True)
    self.ppt_board.setTexture(self.ppt_tex[0])

    lens = PerspectiveLens()
    lens.set_film_size(1920, 1080)
    lens.set_fov(45, 30)
    pos = (0, -20, 0)
    self.cam.set_pos(*pos)
    self.cam.look_at(0, 0, 0)

if __name__ == '__main__':
  app = App()
  app.run()

Hmm… I see that you’re using “simplepbr”–what happens if you remove it?

Another thought: Does your Blender-made plane have UV-coordinates?

Remove simplepbr is still the same :frowning: .

I added an image texture for that plane in Blender, if I don’t set my texture in the code, it can show correctly. Does this mean it has UV-coordinates? Sorry, I am also very new to Blender.

Fair enough–that was a bit of a guess.

Hmm, very odd! That does seem to imply that it has UV-coordinates, indeed. (Unless the exporter is doing something that I’m unaware of, which is very possible.)

When you add a texture in Blender, do you also add a material? If you do, what happens if, in Blender, you add a material but not a texture, and then in code add a texture…?

Another thought: In your code above, what happens if you remove the call to “setTexScale”? Is your plane still rendered in black?

If you set the texture with a priority, do you see it then? Like so:

   test_plane.setTexture(self.ppt_tex[0], 1)

You can get some useful info about your loaded model by calling ls on it:

   test_plane.ls()

This could show that there is perhaps a default texture applied to a Geom (instead of to the GeomNode) by the Panda loader, in case you didn’t apply one in Blender. Using a priority value would make the texture in your set_texture call override that already existing texture.

As a last resort you could upload your .blend file so others can take a look at it.

And just out of curiosity, is there any difference if you export the plane from Blender to .gltf and load that instead?

I tried all those options, still can’t make it work.

test_plane.setTexture(self.ppt_tex[0], 1) also does not work. test_palne.ls() return None, this is weird. Actually I tried gltf at the very beginning, it does not work, then I switch to bam. Here is the blender file: data/projector-screen-test.blend at main · Hao-Yan/data (github.com). My goal is to set texture to the cube on the projector screen, but it failed, then I tried adding a simple plane, but still failed.

This, at least, is normal I do believe: the “ls()” method doesn’t return a value, but instead prints to the console. Thus, when calling “ls()”, look to the console for the resultant output!

Could you do me a favour please and run the “bam” version of your file through “bam2egg”, and then post the resultant egg-file?

I can’t open your blend-file due to my version of Blender being an older one, but I should be able to view the contents of an egg-file.

It printed None in console actually.

Here is the egg file, thanks for the help.
data/Projector_Screen.egg at main · Hao-Yan/data (github.com)

That’s odd!

Unless you were perhaps running something like print (test_palne.ls()) instead of just test_palne.ls()?

But even so, there should have been other printout!

Ah, thank you!

Hmm, it’s strange. If I’m reading correctly, your model does have UV-coordinates. However, when I experiment with applying textures, it seems that it’s only taking colour from a point on the texture–as though the UV-coordinates were messed up in some way.

And indeed, a quick bit of hacking with a shader indicates that the texture-coordinates across the whole thing are ending up as (1, 0)–hence only taking colour from that one point.

I’m not sure of how your coordinates are ending up that way, but it might be worth looking at how Blender displays them.

Ah, having used blend2bam on it myself, I found that the model uses 4 different TextureStages ("0", "1", "2" and "3"), and it seems that the texture is applied to TextureStage "0", which is the only one that makes use of the correct UV-coordinates.
(Doing some more research, these TextureStages would be created for the UV-sets that have those same names.)

You can find the TextureStages in use like this:

        tex_stages = test_plane.find_all_texture_stages()
        print("Texture stages:", tex_stages)

Since you are applying your new textures to TextureStage.default instead, the wrong UV-set is being used.

So what worked for me is this:

        ts = test_plane.find_texture_stage("0")  # instead of a specific name, "*" might also work
        test_plane.set_texture(ts, tex, 1)

Hopefully this will work for you as well!

2 Likes

I did some random change in Blender’s UV editor for the UV coordinates to make sure the plane contain UV-coordinates, sorry for the confusion.

1 Like

This works like a charm, thanks a lot for your help. Just curious, why there are 4 different TextureStages and what are they used for?

2 Likes

It’s my pleasure! :slight_smile:

Multiple TextureStages are used for multi-texturing, but I’m not sure why those additional stages are added when your model only has a single texture applied. Perhaps someone who knows more about Blender/.gltf/blend2bam than I do will be able to clarify.