Light Control Fixes and GLTF Punctual Light and Unlit Material Extensions

If I understand the GLTF format correctly, this contains the positioning, rotation, and scaling. Without it, I suspect that the LightControl has difficulty understanding how to properly ascertain the direction of the DirectionalLight.

My model in Blender:



My model when loaded by your loader:


My model when I effectivly disable the lightsToLumens code (if (true) return color;)


Scene hierarchy:

Scene
	Point.001 - com.jme3.light.PointLight@4e2fc626
	Point.002 - com.jme3.light.PointLight@6efb741
	Sun - DirectionalLight[name=Sun, direction=(-0.0, -0.0, -1.0), color=Color[1.0, 1.0, 1.0, 1.0], enabled=true]
	Point - com.jme3.light.PointLight@7c0723ba
	Point.003 - com.jme3.light.PointLight@7a9c6c4
	Spot - com.jme3.light.SpotLight@765cebb1
	Spot.002 - com.jme3.light.SpotLight@22261b73
	Camera
	Floor - Material[name=Floor, def=PBR Lighting, tech=null]
	Lamp - Material[name=Metal, def=PBR Lighting, tech=null]
	Point
		Point_Orientation
			com.jme3.scene.control.LightControl@33b66de5
	Lamp - Material[name=Metal, def=PBR Lighting, tech=null]
	Point.001
		Point.001_Orientation
			com.jme3.scene.control.LightControl@61d6423b
	Floor - Material[name=Floor, def=PBR Lighting, tech=null]
	Cylinder.001 - Material[name=Metal, def=PBR Lighting, tech=null]
	Spot
		Spot_Orientation
			com.jme3.scene.control.LightControl@937d0a9
	Sphere - Material[name=Disko, def=PBR Lighting, tech=null]
	Sun
		Sun_Orientation
			com.jme3.scene.control.LightControl@1b58bf7f
	Lamp - Material[name=Metal, def=PBR Lighting, tech=null]
	Point.002
		Point.002_Orientation
			com.jme3.scene.control.LightControl@1b0120b4
	Lamp - Material[name=Metal, def=PBR Lighting, tech=null]
	Point.003
		Point.003_Orientation
			com.jme3.scene.control.LightControl@48156e75
	Cylinder.001 - Material[name=Metal, def=PBR Lighting, tech=null]
	Spot.001
		Spot.001_Orientation
			com.jme3.scene.control.LightControl@7f904d46
	Sphere - Material[name=Disko, def=PBR Lighting, tech=null]
	Cylinder.002 - Material[name=Shadeless, def=PBR Lighting, tech=null]

You can get the model punctual.gltf at my original Git branch.

Ah, I understand by what you mean by the matrix now. I would expect the light control to still properly set the direction, does your model also have this issue or just the test model from Khronos?

I will use your test model to see if I can get the lumens closer.

Actually, my model seems to use regular translation and rotation fields to the same effect. Probably just another quirk of blender vs whatever program exported your model, but it seems to get the job done.

That particular model was right from khronos group’s punctual test.

I found a math mistake on my part:

This is supposed to be:
double Le = 2f * Math.log(lumens * epsilon) / Math.log(2) + 127.0; Take note the +127 on the end.

A little better

Edit: The spot light is acting very odd:

And I am not sure what is going wrong here:

Edit 2: it makes me wonder if the light control works for these correctly…

Yes, much better.
I’ve had some difficulty with the directions of spot lights, myself (there are two in my scene, with their postions and directions theoretically indicated by the light projector model).


The green spotlight is supposed to be shining on the ball. In my code, I had to do some funky stuff with the vectors to get it to work.

However, I’m not sure if this is a bug with the LightControl in JME, a quirk with GLTF, or a quirk with Blender. Do you have any GLTF models that have spotlights?

Not sure where the issue is, perhaps it is something with blender.
I can confirm that the positions are wrong. I will push my current changes. I think the intensity is correct now though, or at least very close. I tried making your changes for positioning to the LightControl, the positions were closer, but still very far off for rotation.

Edit, I don’t have a model on hand as I am having difficulty with the one I was working on in blender. I will see if I can get it working again for more testing… But I can confirm that we do have a rotation issue somewhere. It looks like point lights have the correct position though, but they are not lighting the lamps in your model the way I would expect them to.

Yeah, the point lights have really been a pain…
At some point, though, we should also try to merge the unlit plugin I also have in the branch. That one has been a bit more straightforward, and works pretty well.

1 Like

I think I finally got it:


The trick is that lights are oriented in -Z direction in the gltf coordinate system. So I created a new light control that re-orients as expected.

package com.jme3.scene.plugins.gltf;

import com.jme3.light.DirectionalLight;
import com.jme3.light.Light;
import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.control.LightControl;
import com.jme3.util.TempVars;

/**
 * This Control maintains a reference to a Camera,
 * which will be synced with the position (worldTranslation)
 * of the current spatial. Rotations are relative to the
 * negative Z direction.
 *
 * @author Trevor Flynn
 */
public class GltfLightControl extends LightControl {

    public GltfLightControl() {

    }

    public GltfLightControl(Light light) {
        this.setLight(light);
    }

    @Override
    protected void controlUpdate(float tpf) {
        if (spatial != null && this.getLight() != null) {
            switch (this.getControlDir()) {
                case SpatialToLight:
                    spatialToLight(this.getLight());
                    break;
                case LightToSpatial:
                    lightToSpatial(this.getLight());
                    break;
            }
        }
    }

    private void spatialToLight(Light light) {

        final Vector3f worldTranslation = spatial.getWorldTranslation();

        if (light instanceof PointLight) {
            ((PointLight) light).setPosition(worldTranslation);
        } else if (light instanceof DirectionalLight) {
            ((DirectionalLight) light).setDirection(spatial.getLocalRotation().multLocal(new Vector3f(1f, -1f, 0f)));
        } else if (light instanceof SpotLight) {
            final SpotLight spotLight = (SpotLight) light;
            spotLight.setPosition(worldTranslation);
            spotLight.setDirection(spatial.getLocalRotation().multLocal(new Vector3f(1f, -1f, 0f)));
        }
    }

    private void lightToSpatial(Light light) {
        TempVars vars = TempVars.get();
        if (light instanceof PointLight) {

            PointLight pLight = (PointLight) light;

            Vector3f vecDiff = vars.vect1.set(pLight.getPosition()).subtractLocal(spatial.getWorldTranslation());
            spatial.setLocalTranslation(vecDiff.addLocal(spatial.getLocalTranslation()));
        }

        if (light instanceof DirectionalLight) {
            DirectionalLight dLight = (DirectionalLight) light;
            vars.vect1.set(dLight.getDirection()).multLocal(-1.0f);
            Vector3f vecDiff = vars.vect1.subtractLocal(spatial.getWorldTranslation());
            spatial.setLocalTranslation(vecDiff.addLocal(spatial.getLocalTranslation()));
        }
        vars.release();
        //TODO add code for Spot light here when it's done
    }
}
3 Likes

@Markil3 can test and make sure that rotations work properly, perhaps put together some more test models with different rotations?
As for the unlit materials, would you be willing to open a PR for those?

Tomorrow I am flying back up to work, I will be there for 3 weeks this time. I have very limited internet at work and will try my best to keep up to date with this thread, but will probably not have much capacity to make code changes.

This looks odd. A 45 degree angle?

It seems that way. I want to put together some more tests first, but that fixes the orientation of both spot lights in the example scene. But I agree, it was not what I was expecting initially, but that is what made them work… Perhaps you have an idea as to why?

It just doesn’t match your ‘negative Z’ explanation since it jumps outside of orthogonal axes.

You may need more tests as I suspect it will fail in different ways… but I don’t know what the values were in Blender, what we see in gltf, etc… It also shouldn’t require a special control just to reorient the axes.

I agree.
One example from the GLTF:

{
            "children" : [
                10
            ],
            "name" : "Spot",
            "rotation" : [
                -0.5433530807495117,
                0.33025217056274414,
                0.1699628382921219,
                0.7528702616691589
            ],
            "translation" : [
                -12.743064880371094,
                13.054357528686523,
                -14.003191947937012
            ]
        }

...

{
            "extensions" : {
                "KHR_lights_punctual" : {
                    "light" : 2
                }
            },
            "name" : "Spot_Orientation",
            "rotation" : [
                -0.7071067690849304,
                0,
                0,
                0.7071067690849304
            ]
        }

Which in the scene:

Spot (Node) / (-12.743065, 13.054358, -14.003192), (-0.5433531, 0.33025217, 0.16996284, 0.75287026), (1.0, 1.0, 1.0)
				Spot_Orientation (Node) / (0.0, 0.0, 0.0), (-0.70710677, 0.0, 0.0, 0.70710677), (1.0, 1.0, 1.0)

You can see the two nodes that make up this spot light look to have the correct orientation in the scene to the gltf file.

The lights orientation in the scene:

(SpotLight) (-12.743065, 13.054358, -14.003192), (0.99999994, 0.0, 0.99999994)

Printed using:

private void dumpScene(Spatial s, int indent) {
        System.err.println(indentString.substring(0, indent) + s.getName() + " (" + s.getClass().getSimpleName() + ") / " +
                s.getLocalTransform().getTranslation().toString() + ", " +
                s.getLocalTransform().getRotation().toString() + ", " +
                s.getLocalTransform().getScale().toString());
        for (Light light : s.getLocalLightList()) {
            System.err.print(indentString.substring(0, indent + 1) + " (" + light.getClass().getSimpleName() + ")");
            if (light instanceof SpotLight) {
                Vector3f pos = ((SpotLight) light).getPosition();
                Vector3f dir = ((SpotLight) light).getDirection();
                System.err.println(" " + pos.toString() + ", " + dir.toString());
            } else if (light instanceof PointLight) {
                Vector3f pos = ((PointLight) light).getPosition();
                System.err.println(" " + pos.toString());
            } else if (light instanceof DirectionalLight) {
                Vector3f dir = ((DirectionalLight) light).getDirection();
                System.err.println(" " + dir.toString());
            }
        }
        if (s instanceof Node) {
            Node n = (Node) s;
            for (Spatial spatial : n.getChildren()) {
                dumpScene(spatial, indent + 1);
            }
        }
    }

A full dump of the scene and the gltf. (The full gltf is here: jmonkeyengine/jme3-examples/src/main/resources/jme3test/scenes at 8306bf8d730cfe663aaa17a960b3b4b34eb5e87b · Markil3/jmonkeyengine (github.com) )

Root Node (Node) / (0.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
	 (LightProbe)	world (Node) / (0.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
		Scene (Node) / (0.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
			 (PointLight) (-10.315898, 10.631717, 11.913646)
			 (PointLight) (8.953469, 24.6333, 12.535986)
			 (DirectionalLight) (0.70710677, 0.0, 0.70710677)
			 (PointLight) (9.684102, 10.631717, -10.086354)
			 (SpotLight) (-13.179915, 17.024837, -14.326368), (0.99999994, 0.0, 0.99999994)
			 (SpotLight) (-12.743065, 13.054358, -14.003192), (0.99999994, 0.0, 0.99999994)
			 (PointLight) (-9.585265, 24.6333, -10.708696)
			Camera (Node) / (-44.530895, 9.074798, -40.327118), (0.28322813, -0.6591304, 0.63653433, 0.28311303), (1.0, 1.0, 1.0)
			Floor (Geometry) / (0.0, 0.0, 0.0), (0.0, 0.0, 0.0, 1.0), (42.267365, 42.267365, 42.267365)
			Lamp (Geometry) / (-10.315899, 0.0044345856, 11.913646), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
			Point (Node) / (-10.315898, 10.631717, 11.913646), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
				Point_Orientation (Node) / (0.0, 0.0, 0.0), (-0.70710677, 0.0, 0.0, 0.70710677), (1.0, 1.0, 1.0)
			Lamp (Geometry) / (9.684101, 0.0044345856, -10.086354), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
			Point.001 (Node) / (9.684102, 10.631717, -10.086354), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
				Point.001_Orientation (Node) / (0.0, 0.0, 0.0), (-0.70710677, 0.0, 0.0, 0.70710677), (1.0, 1.0, 1.0)
			Floor (Geometry) / (0.0, 14.982909, 0.0), (0.0, 0.0, 0.0, 1.0), (53.970276, 53.970276, 53.970276)
			Cylinder.001 (Geometry) / (-13.091679, 14.984577, -14.664768), (-0.06950115, 0.37037933, -0.02780313, 0.9258596), (1.0, 1.0, 1.0)
			Spot (Node) / (-12.743065, 13.054358, -14.003192), (-0.5433531, 0.33025217, 0.16996284, 0.75287026), (1.0, 1.0, 1.0)
				Spot_Orientation (Node) / (0.0, 0.0, 0.0), (-0.70710677, 0.0, 0.0, 0.70710677), (1.0, 1.0, 1.0)
			Sphere (Geometry) / (-0.49063408, 6.1860094, 0.03940797), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
			Sun (Node) / (-12.397845, 11.035292, -9.731745), (-0.31526268, 0.0, 0.0, 0.9490045), (1.0, 1.0, 1.0)
				Sun_Orientation (Node) / (0.0, 0.0, 0.0), (-0.70710677, 0.0, 0.0, 0.70710677), (1.0, 1.0, 1.0)
			Lamp (Geometry) / (8.953468, 14.006018, 12.535987), (0.0, 0.6484369, 0.0, 0.76126844), (1.0, 1.0, 1.0)
			Point.002 (Node) / (8.953469, 24.6333, 12.535986), (0.0, 0.6484369, 0.0, 0.76126844), (1.0, 1.0, 1.0)
				Point.002_Orientation (Node) / (0.0, 0.0, 0.0), (-0.70710677, 0.0, 0.0, 0.70710677), (1.0, 1.0, 1.0)
			Lamp (Geometry) / (-9.585266, 14.006018, -10.708695), (0.0, 0.6484369, 0.0, 0.76126844), (1.0, 1.0, 1.0)
			Point.003 (Node) / (-9.585265, 24.6333, -10.708696), (0.0, 0.6484369, 0.0, 0.76126844), (1.0, 1.0, 1.0)
				Point.003_Orientation (Node) / (0.0, 0.0, 0.0), (-0.70710677, 0.0, 0.0, 0.70710677), (1.0, 1.0, 1.0)
			Cylinder.001 (Geometry) / (-13.091679, 14.984577, -14.664768), (-0.41653556, -0.04629477, -0.9016726, 0.10649625), (1.0, 1.0, 1.0)
			Spot.001 (Node) / (-13.179915, 17.024837, -14.326368), (0.41074333, -0.43200082, 0.7927999, 0.12701777), (1.0, 1.0, 1.0)
				Spot.001_Orientation (Node) / (0.0, 0.0, 0.0), (-0.70710677, 0.0, 0.0, 0.70710677), (1.0, 1.0, 1.0)
			Sphere (Geometry) / (0.6781602, 31.510551, 0.03940797), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
			Cylinder.002 (Geometry) / (-3.2201676, 5.5753946, -3.2332816), (0.0, 0.0, 0.0, 1.0), (1.0, 1.0, 1.0)
{
    "asset" : {
        "generator" : "Khronos glTF Blender I/O v1.4.40",
        "version" : "2.0"
    },
    "extensionsUsed" : [
        "KHR_lights_punctual",
        "KHR_materials_unlit"
    ],
    "extensionsRequired" : [
        "KHR_lights_punctual"
    ],
    "extensions" : {
        "KHR_lights_punctual" : {
            "lights" : [
                {
                    "color" : [
                        1,
                        1,
                        0.0012016883119940758
                    ],
                    "intensity" : 1000,
                    "type" : "point",
                    "name" : "Point"
                },
                {
                    "color" : [
                        1,
                        0,
                        1
                    ],
                    "intensity" : 1000,
                    "type" : "point",
                    "name" : "Point.001"
                },
                {
                    "color" : [
                        0,
                        1,
                        0
                    ],
                    "intensity" : 10000,
                    "spot" : {
                        "innerConeAngle" : 0.12090771262500066,
                        "outerConeAngle" : 0.1422443687915802
                    },
                    "type" : "spot",
                    "name" : "Spot"
                },
                {
                    "color" : [
                        1,
                        1,
                        1
                    ],
                    "intensity" : 1,
                    "type" : "directional",
                    "name" : "Sun"
                },
                {
                    "color" : [
                        0,
                        0,
                        1
                    ],
                    "intensity" : 1000,
                    "type" : "point",
                    "name" : "Point.003"
                },
                {
                    "color" : [
                        1,
                        0,
                        0
                    ],
                    "intensity" : 1000,
                    "type" : "point",
                    "name" : "Point.002"
                },
                {
                    "color" : [
                        0,
                        1,
                        1
                    ],
                    "intensity" : 10000,
                    "spot" : {
                        "innerConeAngle" : 0.4578386817132163,
                        "outerConeAngle" : 0.5436700582504272
                    },
                    "type" : "spot",
                    "name" : "Spot.002"
                }
            ]
        }
    },
    "scene" : 0,
    "scenes" : [
        {
            "name" : "Scene",
            "nodes" : [
                0,
                1,
                2,
                4,
                5,
                7,
                8,
                9,
                11,
                12,
                14,
                15,
                17,
                18,
                20,
                21,
                23,
                24,
                25
            ]
        }
    ],
    "nodes" : [
        {
            "name" : "Camera",
            "rotation" : [
                0.2832281291484833,
                -0.6591303944587708,
                0.6365343332290649,
                0.283113032579422
            ],
            "translation" : [
                -44.5308952331543,
                9.074797630310059,
                -40.327117919921875
            ]
        },
        {
            "mesh" : 0,
            "name" : "Plane",
            "scale" : [
                42.267364501953125,
                42.267364501953125,
                42.267364501953125
            ]
        },
        {
            "mesh" : 1,
            "name" : "Lamp",
            "translation" : [
                -10.315898895263672,
                0.0044345855712890625,
                11.91364574432373
            ]
        },
        {
            "extensions" : {
                "KHR_lights_punctual" : {
                    "light" : 0
                }
            },
            "name" : "Point_Orientation",
            "rotation" : [
                -0.7071067690849304,
                0,
                0,
                0.7071067690849304
            ]
        },
        {
            "children" : [
                3
            ],
            "name" : "Point",
            "translation" : [
                -10.315897941589355,
                10.63171672821045,
                11.91364574432373
            ]
        },
        {
            "mesh" : 1,
            "name" : "Lamp.001",
            "translation" : [
                9.684101104736328,
                0.0044345855712890625,
                -10.08635425567627
            ]
        },
        {
            "extensions" : {
                "KHR_lights_punctual" : {
                    "light" : 1
                }
            },
            "name" : "Point.001_Orientation",
            "rotation" : [
                -0.7071067690849304,
                0,
                0,
                0.7071067690849304
            ]
        },
        {
            "children" : [
                6
            ],
            "name" : "Point.001",
            "translation" : [
                9.684102058410645,
                10.63171672821045,
                -10.08635425567627
            ]
        },
        {
            "mesh" : 0,
            "name" : "Plane.001",
            "scale" : [
                53.97027587890625,
                53.97027587890625,
                53.97027587890625
            ],
            "translation" : [
                0,
                14.982909202575684,
                0
            ]
        },
        {
            "mesh" : 2,
            "name" : "Cylinder.001",
            "rotation" : [
                -0.06950114667415619,
                0.37037932872772217,
                -0.027803130447864532,
                0.9258595705032349
            ],
            "translation" : [
                -13.091678619384766,
                14.984577178955078,
                -14.66476821899414
            ]
        },
        {
            "extensions" : {
                "KHR_lights_punctual" : {
                    "light" : 2
                }
            },
            "name" : "Spot_Orientation",
            "rotation" : [
                -0.7071067690849304,
                0,
                0,
                0.7071067690849304
            ]
        },
        {
            "children" : [
                10
            ],
            "name" : "Spot",
            "rotation" : [
                -0.5433530807495117,
                0.33025217056274414,
                0.1699628382921219,
                0.7528702616691589
            ],
            "translation" : [
                -12.743064880371094,
                13.054357528686523,
                -14.003191947937012
            ]
        },
        {
            "mesh" : 3,
            "name" : "Sphere",
            "translation" : [
                -0.49063408374786377,
                6.186009407043457,
                0.039407968521118164
            ]
        },
        {
            "extensions" : {
                "KHR_lights_punctual" : {
                    "light" : 3
                }
            },
            "name" : "Sun_Orientation",
            "rotation" : [
                -0.7071067690849304,
                0,
                0,
                0.7071067690849304
            ]
        },
        {
            "children" : [
                13
            ],
            "name" : "Sun",
            "rotation" : [
                -0.31526267528533936,
                0,
                0,
                0.9490044713020325
            ],
            "translation" : [
                -12.397845268249512,
                11.03529167175293,
                -9.731744766235352
            ]
        },
        {
            "mesh" : 1,
            "name" : "Lamp.002",
            "rotation" : [
                0,
                0.6484369039535522,
                0,
                0.7612684369087219
            ],
            "translation" : [
                8.953468322753906,
                14.006017684936523,
                12.53598690032959
            ]
        },
        {
            "extensions" : {
                "KHR_lights_punctual" : {
                    "light" : 4
                }
            },
            "name" : "Point.002_Orientation",
            "rotation" : [
                -0.7071067690849304,
                0,
                0,
                0.7071067690849304
            ]
        },
        {
            "children" : [
                16
            ],
            "name" : "Point.002",
            "rotation" : [
                0,
                0.6484369039535522,
                0,
                0.7612684369087219
            ],
            "translation" : [
                8.953469276428223,
                24.63330078125,
                12.535985946655273
            ]
        },
        {
            "mesh" : 1,
            "name" : "Lamp.003",
            "rotation" : [
                0,
                0.6484369039535522,
                0,
                0.7612684369087219
            ],
            "translation" : [
                -9.58526611328125,
                14.006017684936523,
                -10.708695411682129
            ]
        },
        {
            "extensions" : {
                "KHR_lights_punctual" : {
                    "light" : 5
                }
            },
            "name" : "Point.003_Orientation",
            "rotation" : [
                -0.7071067690849304,
                0,
                0,
                0.7071067690849304
            ]
        },
        {
            "children" : [
                19
            ],
            "name" : "Point.003",
            "rotation" : [
                0,
                0.6484369039535522,
                0,
                0.7612684369087219
            ],
            "translation" : [
                -9.585265159606934,
                24.63330078125,
                -10.708696365356445
            ]
        },
        {
            "mesh" : 2,
            "name" : "Cylinder.002",
            "rotation" : [
                -0.41653555631637573,
                -0.04629477113485336,
                -0.9016726016998291,
                0.10649625211954117
            ],
            "translation" : [
                -13.091678619384766,
                14.984577178955078,
                -14.66476821899414
            ]
        },
        {
            "extensions" : {
                "KHR_lights_punctual" : {
                    "light" : 6
                }
            },
            "name" : "Spot.001_Orientation",
            "rotation" : [
                -0.7071067690849304,
                0,
                0,
                0.7071067690849304
            ]
        },
        {
            "children" : [
                22
            ],
            "name" : "Spot.001",
            "rotation" : [
                0.4107433259487152,
                -0.4320008158683777,
                0.7927998900413513,
                0.1270177662372589
            ],
            "translation" : [
                -13.179915428161621,
                17.024837493896484,
                -14.32636833190918
            ]
        },
        {
            "mesh" : 3,
            "name" : "Sphere.001",
            "translation" : [
                0.6781601905822754,
                31.51055145263672,
                0.039407968521118164
            ]
        },
        {
            "mesh" : 4,
            "name" : "Cylinder",
            "translation" : [
                -3.220167636871338,
                5.575394630432129,
                -3.2332816123962402
            ]
        }
    ],
    "materials" : [
        {
            "name" : "Floor",
            "pbrMetallicRoughness" : {
                "baseColorFactor" : [
                    0.800000011920929,
                    0.800000011920929,
                    0.800000011920929,
                    1
                ],
                "metallicFactor" : 0,
                "roughnessFactor" : 0
            }
        },
        {
            "doubleSided" : true,
            "name" : "Metal",
            "pbrMetallicRoughness" : {
                "baseColorFactor" : [
                    0.06372114270925522,
                    0.06372114270925522,
                    0.06372114270925522,
                    1
                ],
                "roughnessFactor" : 0.3240740895271301
            }
        },
        {
            "doubleSided" : true,
            "name" : "Disko",
            "pbrMetallicRoughness" : {
                "roughnessFactor" : 0.3909090757369995
            }
        },
        {
            "doubleSided" : true,
            "extensions" : {
                "KHR_materials_unlit" : {}
            },
            "name" : "Shadeless",
            "pbrMetallicRoughness" : {
                "baseColorFactor" : [
                    1,
                    0.012044749222695827,
                    0,
                    1
                ],
                "metallicFactor" : 0,
                "roughnessFactor" : 0.9
            }
        }
    ],
    "meshes" : [
        {
            "name" : "Floor",
            "primitives" : [
                {
                    "attributes" : {
                        "POSITION" : 0,
                        "NORMAL" : 1,
                        "TEXCOORD_0" : 2
                    },
                    "indices" : 3,
                    "material" : 0
                }
            ]
        },
        {
            "name" : "Lamp",
            "primitives" : [
                {
                    "attributes" : {
                        "POSITION" : 4,
                        "NORMAL" : 5,
                        "TEXCOORD_0" : 6
                    },
                    "indices" : 7,
                    "material" : 1
                }
            ]
        },
        {
            "name" : "Cylinder.001",
            "primitives" : [
                {
                    "attributes" : {
                        "POSITION" : 8,
                        "NORMAL" : 9,
                        "TEXCOORD_0" : 10
                    },
                    "indices" : 11,
                    "material" : 1
                }
            ]
        },
        {
            "name" : "Sphere",
            "primitives" : [
                {
                    "attributes" : {
                        "POSITION" : 12,
                        "NORMAL" : 13,
                        "TEXCOORD_0" : 14
                    },
                    "indices" : 15,
                    "material" : 2
                }
            ]
        },
        {
            "name" : "Cylinder.002",
            "primitives" : [
                {
                    "attributes" : {
                        "POSITION" : 16,
                        "NORMAL" : 17,
                        "TEXCOORD_0" : 18
                    },
                    "indices" : 19,
                    "material" : 3
                }
            ]
        }
    ],
    "accessors" : [
        {
            "bufferView" : 0,
            "componentType" : 5126,
            "count" : 24,
            "max" : [
                1,
                0.004745747894048691,
                1
            ],
            "min" : [
                -1,
                0,
                -1
            ],
            "type" : "VEC3"
        },
        {
            "bufferView" : 1,
            "componentType" : 5126,
            "count" : 24,
            "type" : "VEC3"
        },
        {
            "bufferView" : 2,
            "componentType" : 5126,
            "count" : 24,
            "type" : "VEC2"
        },
        {
            "bufferView" : 3,
            "componentType" : 5123,
            "count" : 36,
            "type" : "SCALAR"
        },
        {
            "bufferView" : 4,
            "componentType" : 5126,
            "count" : 832,
            "max" : [
                0.6503018140792847,
                10.486347198486328,
                0.6503019332885742
            ],
            "min" : [
                -0.6503013372421265,
                0,
                -0.6503008008003235
            ],
            "type" : "VEC3"
        },
        {
            "bufferView" : 5,
            "componentType" : 5126,
            "count" : 832,
            "type" : "VEC3"
        },
        {
            "bufferView" : 6,
            "componentType" : 5126,
            "count" : 832,
            "type" : "VEC2"
        },
        {
            "bufferView" : 7,
            "componentType" : 5123,
            "count" : 1764,
            "type" : "SCALAR"
        },
        {
            "bufferView" : 8,
            "componentType" : 5126,
            "count" : 708,
            "max" : [
                1,
                0,
                2.2022311687469482
            ],
            "min" : [
                -1,
                -3.4594199657440186,
                -1.3309168815612793
            ],
            "type" : "VEC3"
        },
        {
            "bufferView" : 9,
            "componentType" : 5126,
            "count" : 708,
            "type" : "VEC3"
        },
        {
            "bufferView" : 10,
            "componentType" : 5126,
            "count" : 708,
            "type" : "VEC2"
        },
        {
            "bufferView" : 11,
            "componentType" : 5123,
            "count" : 1512,
            "type" : "SCALAR"
        },
        {
            "bufferView" : 12,
            "componentType" : 5126,
            "count" : 559,
            "max" : [
                1.000000238418579,
                1,
                1.0000003576278687
            ],
            "min" : [
                -0.9999998211860657,
                -1,
                -1
            ],
            "type" : "VEC3"
        },
        {
            "bufferView" : 13,
            "componentType" : 5126,
            "count" : 559,
            "type" : "VEC3"
        },
        {
            "bufferView" : 14,
            "componentType" : 5126,
            "count" : 559,
            "type" : "VEC2"
        },
        {
            "bufferView" : 15,
            "componentType" : 5123,
            "count" : 2880,
            "type" : "SCALAR"
        },
        {
            "bufferView" : 16,
            "componentType" : 5126,
            "count" : 192,
            "max" : [
                1,
                1,
                1
            ],
            "min" : [
                -1,
                -1,
                -1
            ],
            "type" : "VEC3"
        },
        {
            "bufferView" : 17,
            "componentType" : 5126,
            "count" : 192,
            "type" : "VEC3"
        },
        {
            "bufferView" : 18,
            "componentType" : 5126,
            "count" : 192,
            "type" : "VEC2"
        },
        {
            "bufferView" : 19,
            "componentType" : 5123,
            "count" : 372,
            "type" : "SCALAR"
        }
    ],
    "bufferViews" : [
        {
            "buffer" : 0,
            "byteLength" : 288,
            "byteOffset" : 0
        },
        {
            "buffer" : 0,
            "byteLength" : 288,
            "byteOffset" : 288
        },
        {
            "buffer" : 0,
            "byteLength" : 192,
            "byteOffset" : 576
        },
        {
            "buffer" : 0,
            "byteLength" : 72,
            "byteOffset" : 768
        },
        {
            "buffer" : 0,
            "byteLength" : 9984,
            "byteOffset" : 840
        },
        {
            "buffer" : 0,
            "byteLength" : 9984,
            "byteOffset" : 10824
        },
        {
            "buffer" : 0,
            "byteLength" : 6656,
            "byteOffset" : 20808
        },
        {
            "buffer" : 0,
            "byteLength" : 3528,
            "byteOffset" : 27464
        },
        {
            "buffer" : 0,
            "byteLength" : 8496,
            "byteOffset" : 30992
        },
        {
            "buffer" : 0,
            "byteLength" : 8496,
            "byteOffset" : 39488
        },
        {
            "buffer" : 0,
            "byteLength" : 5664,
            "byteOffset" : 47984
        },
        {
            "buffer" : 0,
            "byteLength" : 3024,
            "byteOffset" : 53648
        },
        {
            "buffer" : 0,
            "byteLength" : 6708,
            "byteOffset" : 56672
        },
        {
            "buffer" : 0,
            "byteLength" : 6708,
            "byteOffset" : 63380
        },
        {
            "buffer" : 0,
            "byteLength" : 4472,
            "byteOffset" : 70088
        },
        {
            "buffer" : 0,
            "byteLength" : 5760,
            "byteOffset" : 74560
        },
        {
            "buffer" : 0,
            "byteLength" : 2304,
            "byteOffset" : 80320
        },
        {
            "buffer" : 0,
            "byteLength" : 2304,
            "byteOffset" : 82624
        },
        {
            "buffer" : 0,
            "byteLength" : 1536,
            "byteOffset" : 84928
        },
        {
            "buffer" : 0,
            "byteLength" : 744,
            "byteOffset" : 86464
        }
    ],
    "buffers" : [
        {
            "byteLength" : 87208,
            "uri" : "punctual.bin"
        }
    ]
}

That’s a lot more than I can drill into at the moment.

If it were me, I’d be comparing the values shown in the blender UI for the object properties (in both quaternion and euler form) for a few different orientations and then see how they turn it in JME (in the fromAngles(), etc.) and try to reconcile that with the fact that both have different concepts of Y up or Z up… and maybe even handedness. Though I think gltf normalizes some of that.

No worries, I figured I would just dump everything here for future reference.
As noted, here is the explanation from gltf:
glTF/extensions/2.0/Khronos/KHR_lights_punctual at master · KhronosGroup/glTF (github.com)

The light will inherit the transform of the node. For light types that have a position (point and spot 
lights), the light's position is defined as the node's world location. For light types that have a direction 
(directional and spot lights), the light's direction is defined as the 3-vector (0.0, 0.0, -1.0) and the 
rotation of the node orients the light accordingly. That is, an untransformed light points down the -Z 
axis. The light's transform is affected by the node's world scale, but all properties of the light (such as 
range and intensity) are unaffected.

Yeah, I will have to pull the model into blender and take a look, but I am running out of time. Perhaps @Markil3 can pickup on this while I am gone.

I actually did some testing, and it would appear that while Blender and Khronos will have the light facing down, JME will have its lights facing towards the negative Z axis. Now, this doesn’t seem to affect DirectionalLight at all. However, there does seem to be major issues with SpotLight. I’m wondering if there is a bug in the LightControl for spotlight after all. It does seem that it hasn’t receiving as much love, based on the lightToSpatial method. I’ll look over there, see if there is something suspicious going on.

Alright, this is bizarre: LightControl sets the direction of the DirectionLight based off of the location of the spatial. It basically has the light shining from the spatial to the world origin. Who thought that was a good idea?
Although it does explain why my lights weren’t working when they were at the world origin.

So, I modified the GltfLightControl#spatialToLight method to this:

    private void spatialToLight(Light light) {

        final Vector3f worldTranslation = spatial.getWorldTranslation();
        final Vector3f worldDirection = spatial.getWorldRotation().getRotationColumn(2).mult(-1);

        if (light instanceof PointLight) {
            ((PointLight) light).setPosition(worldTranslation);
        } else if (light instanceof DirectionalLight) {
            ((DirectionalLight) light).setDirection(worldDirection);
        } else if (light instanceof SpotLight) {
            final SpotLight spotLight = (SpotLight) light;
            spotLight.setPosition(worldTranslation);
            spotLight.setDirection(worldDirection);
        }
    }

Essentially, we use the 2nd rotation column of the world rotation to obtain the direction of the light. This works consitently with various angles. Furthermore, actually temporarily replaced the regular LightControl#spatialToLight method with this and ran TestLightNode, and I didn’t see a difference. I’m wondering if, rather than using this new code just for GLTF imports, we could update the LightControl in general. This code is more straightforward and intuitive, and seems to be consistent even with Blender’s axis quirks.

2 Likes

Is the same as:
Vector3f worldDirection = spatial.getWorldRotation().mult(new Vector3f(0, 0, -1));

…though the second one requires less magic knowledge.

Perhaps even clearer as:
Vector3f worldDirection = spatial.getWorldRotation().mult(Vector3f.UNIT_Z.negate());

And with one fewer garbage Vector3f:

Vector3f worldDirection = spatial.getWorldRotation().mult(Vector3f.UNIT_Z);
worldDirection.negateLocal()

…which to my eyes would be instantly crystal clear what is happening.

Originally, DirectionalLight’s direction was “direction where the light is coming from” instead of “direction that the light is traveling”. This was fixed in the early JME3 .0.0.0.0 alphas and maybe LightControl was never adjusted. Just guessing, though.

3 Likes