Skip to content

Improve light render parity with blender #2549

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

riccardobl
Copy link
Member

When importing a gltf model, lights look nothing like in blender.
Turns out jme doesn't use proper physically based light attenuation, and that blender might be doing some shenanigans in spot lights.

In this PR i've patched jme to make it much more closer to blender lighting.
See screenshot below:

Blender:

Screenshot_20250806_180541

JME Without this PR:

Screenshot_20250806_180514

JME With this PR:

Screenshot_20250806_180414

It is still not perfect, but much better i think.

This PR needs more work, mostly to figure out how to merge it, since it will break all the existing scenes setup.
I am looking for suggestions on this regard (maybe we can make it toggleable with a PBRLight param?)

Copy link

github-actions bot commented Aug 10, 2025

🖼️ Screenshot tests have failed.

The purpose of these tests is to ensure that changes introduced in this PR don't break visual features. They are visual unit tests.

📄 Where to find the report:

  • Go to the (failed run) > Summary > Artifacts > screenshot-test-report
  • Download the zip and open jme3-screenshot-tests/build/reports/ScreenshotDiffReport.html

⚠️ If you didn't expect to change anything visual:
Fix your changes so the screenshot tests pass.

If you did mean to change things:
Review the replacement images in jme3-screenshot-tests/build/changed-images to make sure they really are improvements and then replace and commit the replacement images at jme3-screenshot-tests/src/test/resources.

If you are creating entirely new tests:
Find the new images in jme3-screenshot-tests/build/changed-images and commit the new images at jme3-screenshot-tests/src/test/resources.

Note; it is very important that the committed reference images are created on the build pipeline, locally created images are not reliable. Similarly tests will fail locally but you can look at the report to check they are "visually similar".

See https://github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-screenshot-tests/README.md for more information

Contact @richardTingle (aka richtea) for guidance if required

float clampedDist = max(dist, 0.00001);
light.fallOff = clamp(1.0 / (clampedDist * clampedDist), 0.0, 1.0);
light.fallOff = clamp(light.fallOff, 1.0 - posLight, 1.0);
light.fallOff *= step(dist, radius);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the inverse square falloff used by blender with a radius cut-off, since jme allows to set the radius of lights

@@ -739,7 +739,9 @@ public static ColorRGBA getAsColor(JsonObject parent, String name) {
return null;
}
JsonArray color = el.getAsJsonArray();
return new ColorRGBA(color.get(0).getAsFloat(), color.get(1).getAsFloat(), color.get(2).getAsFloat(), color.size() > 3 ? color.get(3).getAsFloat() : 1f);
return new ColorRGBA().setAsSrgb(
color.get(0).getAsFloat(), color.get(1).getAsFloat(), color.get(2).getAsFloat(), color.size() > 3 ? color.get(3).getAsFloat() : 1f
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gltf colors are srgb

@@ -56,6 +56,9 @@
* Created by Trevor Flynn - 3/23/2021
*/
public class LightsPunctualExtensionLoader implements ExtensionLoader {
private static final boolean COMPUTE_LIGHT_RANGE = true;
private static final boolean APPLY_INTENSITY_CONVERSION = true;
private static final boolean SKIP_HDR_CONVERSION = true;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use these toggles to test with and without the patches

intensity = intensity / solidAngle;
}

float range = obj.has("range") ? obj.get("range").getAsFloat() : (COMPUTE_LIGHT_RANGE ? getCutoffDistance(color, intensity) : Float.POSITIVE_INFINITY);
Copy link
Member Author

@riccardobl riccardobl Aug 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The POSITIVE_INFINITY range was an error to begin with and required a patch to turn it into FLOAT_MAX_VALUE #2058 , but it ends up introducing some floating point errors with large numbers that makes the light calculation a bit off.

Truth is: jme doesn't support infinite lights very well.
So this patch calculates the right range based on the falloff function.

vec3 spotDir = normalize(light.spotDirection);
float cosA = dot(-L, spotDir) ;
float spotAtten = clamp((cosA - outerAngleCos) / (innerAngleCos - outerAngleCos), 0.0, 1.0);
light.fallOff *= pow(spotAtten, sharpnessFactor);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This smooths out the angular attenuation. It doesn't look exactly like blender's.

@richardTingle
Copy link
Member

Screenshots look much nicer. With the exception of my comment on the println: looks good!

@richardTingle
Copy link
Member

richardTingle commented Aug 10, 2025

I am looking for suggestions on this regard (maybe we can make it toggleable with a PBRLight param?)

Maybe in the short term a parameter that defaults to false and at some point (on a major version change) the default flips to true and then a few versions later the parameter gets deleted

@riccardobl riccardobl added the defect Something that is supposed to work, but doesn't. Less severe than a "bug" label Aug 10, 2025
@yaRnMcDonuts
Copy link
Member

yaRnMcDonuts commented Aug 18, 2025

I never knew this was an issue, but I have certainly noticed that JME's point lights illuminate the scene way too much, and it is near impossible to tweak them properly in dark scenes without ruining the darkness.

I could never make a proper bright torch in a dark room without it completely brightening the entire room. Then if I turn the brightness or radius down to fix that issue, the torch becomes too dim close up and looks bad. Its like I could never properly tweak point lights.

So I am very excited for this PR!

Maybe in the short term a parameter that defaults to false and at some point (on a major version change) the default flips to true and then a few versions later the parameter gets deleted

This sounds like a good solution. We could probably even make it true by default right away in the next alpha version, that would be beneficial in the short term for alpha and beta testing, that way testers will be forced to test this (in my experience with 3.8, its better to force new changes on people using alpha versions, otherwise people will overlook the togglable option and it won't get tested as much). Then (depending on feedback) we can decide whether it should default to true/false for the next stable release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
defect Something that is supposed to work, but doesn't. Less severe than a "bug"
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants