okay no problem
Directional Lighting not working when imported with panda3d-gltf, but does when imported with assimp
I think Iâll try to expand my function to convert the material to the standard.
minimiun exampll
Asset:
playground3.bam (42.4 KB)
from direct.showbase.ShowBase import ShowBase, TextureStage, TexGenAttrib
from direct.filter.CommonFilters import CommonFilters
from direct.showbase.InputStateGlobal import inputState
from panda3d.core import (loadPrcFileData,
WindowProperties,
AmbientLight,
DirectionalLight,
LightRampAttrib,
Vec3,
MaterialAttrib)
from panda3d.bullet import (BulletDebugNode,
BulletWorld)
import sys
loadPrcFileData("", "show-frame-rate-meter #t")
loadPrcFileData("", "sync-video #t")
loadPrcFileData("", "frame-rate-meter-milliseconds true")
loadPrcFileData("", "show-scene-graph-analyzer-meter true")
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
props = WindowProperties()
props.setTitle("bad_lighting")
base.win.requestProperties(props)
self._set_up_environment_lighting()
self._set_up_toon_shading()
self._setup_level()
self.accept("q", self.exit)
self._debug_bullet()
def exit(self):
sys.exit()
def _set_up_toon_shading(self):
self.separation = 1.2 # Pixels
self.filters = CommonFilters(self.win, self.cam)
filterok = self.filters.setCartoonInk(separation=self.separation)
if (filterok == False):
print(
"Toon Shader: Video card not powerful enough to do image postprocessing")
return
def _set_up_environment_lighting(self):
base.render.setShaderAuto()
base.render.setAttrib(LightRampAttrib.makeSingleThreshold(0.2,0.6))
self.sun = DirectionalLight("sun")
self.sun.setColor((0.8, 0.8, 0.8, 1))
base.sunnp = self.render.attachNewNode( self.sun)
base.sunnp.setZ(base.sunnp, 50)
base.sunnp.setY(base.sunnp, -30)
base.sunnp.setP(base.sunnp, -90)
base.sunnp.node().setShadowCaster(True, 512, 512)
base.sunnp.node().getLens().setFilmSize(2,2)
base.sunnp.node().showFrustum()
base.render.setLight(base.sunnp)
self.ambient_light = AmbientLight('alight')
self.ambient_light.setColor((0.9, 0.9, 0.9, 1))
self.alnp = self.render.attachNewNode(self.ambient_light)
self.render.setLight(self.alnp)
def _debug_bullet(self):
debugNode = BulletDebugNode('Debug')
debugNode.showWireframe(True)
debugNode.showConstraints(True)
debugNode.showBoundingBoxes(True)
debugNode.showNormals(True)
debugNP = render.attachNewNode(debugNode)
debugNP.show()
base.bullet_world.setDebugNode(debugNP.node())
def _setup_level(self):
base.bullet_world_node_path = self.render.attachNewNode('World')
base.bullet_world = BulletWorld()
base.bullet_world.setGravity(Vec3(0, 0, 0)) # (0,0,-14)
playground = loader.loadModel("playground3.bam")
for node_path in playground.find_all_matches('**/+GeomNode'):
geom_states = node_path.node().get_geom_states()
for geom_state in geom_states:
if geom_state.has_attrib(MaterialAttrib):
mat = geom_state.get_attrib(MaterialAttrib).get_material()
mat.clear_emission()
for node_path in playground.find_all_matches('**/+BulletRigidBodyNode'):
base.bullet_world.attachRigidBody(node_path.node())
playground.reparentTo(base.bullet_world_node_path)
self.taskMgr.add(self.update, sort=-2)
def update(self, task):
dt = globalClock.getDt()
base.bullet_world.doPhysics(dt, 5, 1.0/180.0)
return task.cont
app = MyApp()
app.run()
remember to install gltf so it overtakes assimp:
pip install panda3d-blend2bam
pip install panda3d-gltf
Panda3D==1.10.13
panda3d-blend2bam==0.21
panda3d-gltf==0.15.0
panda3d-simplepbr==0.10
Hmm, itâs strange that this works with a textured model⌠I think it is necessary to conduct digital excavations in this direction.
What do you mean? It doesnt work with a textured model to my knolwedge. That example does not rspond to directional light nor shadows. I do appreciate the research!
I mean my example works with a textured model. But it does not work with a model that was exported only with the material. When the auto shader is turned on, the lighting disappears.
Yeah, i suspect, but cant confirm that the added fallback textures play a role. I have one instance where applying those textures results in lighting working. But another where it didnt.
With texture, it starts working with my fix function, which removes the emission parameter from materials. If there is no texture, the object turns white.
Oh gotcha. I need to read up on the rendering related stuff so i can go down the rabbit hole.
Based on a quick examination, I find that the problem can be seen even in PView, like so:
- Load the above-linked bam-file in PView
- Press âLâ to activate lighting.
- Note thatâat least on my machineâthe material colours become visible, and the objects are shaded
- Press âPâ to activate per-pixel shading
- Note thatâagain, at least on my machineâthe objects suddenly become flat grey.
However, converting the bam-file to an egg-file via âbam2eggâ seems to cause the problem to go awayâŚ
My suspicion, then, is that thereâs a problem with the material, and that the light-ramping is perhaps a false lead.
Via the minimal example given above I did try the rendering of the model both with and without the emission-clearing code, but in neither case did the problem seem to go away.
Hmm⌠But investigating the material doesnât seem to lead anywhereâŚ
And I notice something else: In the âbamâ version, thereâs a strange broad, flat block under the half-sphere, which flickers in a way that suggests that it somehow has collision geometry thatâs visible by defaultâwhich is unexpected.
And I note that in the âeggâ version, that surface goes away; viewing the âeggâ version in PView, I see that the collision-geometry is still there, but is invisible by default, as I would expect.
So, perhaps the problem is that this strange object is in some way interfering with things? What happens if you re-export your model without that platform�
The problem is indicated, the gltf loader does not analyze texture inputs for the presence of maps. And it always creates empty texture stages, so panda does not load textures and replaces them with the default value.
In this connection, the lighting breaks down, since instead of a normal map, one vector is always obtained, since the calculation is performed from these data (0.5, 0.5, 1, 0)
The empty emission map also breaks the rendering.
But this is happening with a âbamâ file, not a âglTFâ fileâŚ
It doesnât matter, so panda3d-gltf/panda3d-blend2bam creates it.
Ah, I see: youâre saying that âblend2bamâ uses panda3d-gltf, and so itâs going through the glTF pipeline. Hmâit could be so. Indeed, a quick printing out of texture-stages does indicate a bunch of themâall of which have a colour of (0, 0, 0, 1), which may be part of the problem.
I have created a module that converts the output file panda3d-gltf/panda3d-blend2bam
in accordance with the standard auto shader.
fix_gltf_bam.py
from panda3d.core import MaterialAttrib, Vec4, TextureAttrib, RenderState, TextureStage
def render_stage_convert(node, use_modulate = False, use_normal = False, use_selector = False, use_emission = False):
for node_path in node.find_all_matches('**/+GeomNode'):
geom_node = node_path.node()
new_render_state = RenderState.make_empty()
for index_geom in range(geom_node.get_num_geoms()):
render_state = geom_node.get_geom_state(index_geom)
if render_state.has_attrib(MaterialAttrib):
material = render_state.get_attrib(MaterialAttrib).get_material()
#material.set_diffuse(Vec4(*material.get_base_color()))
material.set_twoside(False)
material.set_refractive_index(1)
material.set_shininess(0)
material.clear_metallic()
#material.clear_diffuse()
#material.clear_base_color()
material.clear_ambient()
material.clear_emission()
new_render_state = new_render_state.add_attrib(MaterialAttrib.make(material))
if render_state.has_attrib(TextureAttrib):
new_texture_attrib = TextureAttrib.make_default()
texture_attrib = render_state.get_attrib(TextureAttrib)
count_stages = texture_attrib.get_num_on_stages()
for index_texture_stage in range(count_stages):
texture_stage = texture_attrib.get_on_stage(index_texture_stage)
texture = render_state.get_attrib(TextureAttrib).get_on_texture(texture_stage)
sampler = render_state.get_attrib(TextureAttrib).get_on_sampler(texture_stage)
if texture_stage.get_mode() == TextureStage.M_modulate:
if use_modulate:
new_texture_attrib = new_texture_attrib.add_on_stage(texture_stage, texture, sampler)
if texture_stage.get_mode() == TextureStage.M_normal:
if use_normal:
new_texture_attrib = new_texture_attrib.add_on_stage(texture_stage, texture, sampler)
if texture_stage.get_mode() == TextureStage.M_selector:
if use_selector:
new_texture_attrib = new_texture_attrib.add_on_stage(texture_stage, texture, sampler)
if texture_stage.get_mode() == TextureStage.M_emission:
if use_emission:
new_texture_attrib = new_texture_attrib.add_on_stage(texture_stage, texture, sampler)
if new_texture_attrib.get_num_on_stages() > 0:
new_render_state = new_render_state.add_attrib(new_texture_attrib)
geom_node.set_geom_state(index_geom, new_render_state)
Use flags to disable unnecessary texture stages.
render_stage_convert(gltf, use_modulate = False, use_normal = False, use_selector = False, use_emission = False)
If you want to use a base texture for the color:
render_stage_convert(gltf, use_modulate = True, use_normal = False, use_selector = False, use_emission = False)
And so on, as for the selector mode, it is unlikely that it will ever come in handy, but I left it.
Usage example based on code from user @CeyaSpaceCowboy
source.zip (22.4 KB)
Donât forget to check the Backface Culling
box in the material. This will save you from shadow acne.
Also consider using anti-aliasing.
https://docs.panda3d.org/1.10/python/programming/render-attributes/antialiasing
I replaced your model with mine. I also set the ambient light to this value (0.2, 0.2, 0.2, 1)
And I adjusted the lens size so that it covered my model. setFilmSize(200,200)
Looking at this one, I thought it was possible to implement it as a NodePath method. Flags can be calculated automatically without any problems.
Thanks man, ill try this soon.
Donât rush to use it, Iâm working on improving it at the moment.