Light Scattering failure

Hi @all,

I recently tried to implement the Light Scattering Effect, following this sample code:
TestLightScattering

Basically, the whole thing is just adding those lines, isn´t it?
[java]
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
LightScatteringFilter filter = new LightScatteringFilter(skyManager.sunDirection.mult(-3000));
fpp.addFilter(filter);
viewPort.addProcessor(fpp);
[/java]
“sunDirection” of is the direction of my directional light, pretty straightforward.

The problem is, what I get is not at all Light Scattering…
When I look at the sun, the whole scene goes darker and darker.
When I change the camera from looking down to looking at the sun, it is a smooth transition;
it´s not smooth at all when I look up first and then at the sun.

It´s really weird and I hope you have an idea what the cause of this could be.
In order to visualize the problem, I have uploaded a little video, demonstrating the issue:
[video]http://www.youtube.com/watch?v=QpJwBGLLyYU&feature=youtu.be[/video]

Thanks for any suggestions in advance!

That’s weird.
Is the TestLightScattering producing a similar effect for you?

I´m sort of in a hurry right now, I´ll do extensive testing later, but when I simply tried to run it, it just gave some errors:

warning: [options] bootstrap class path not set in conjunction with -source 1.5
D:\Software\JMonkey\misc\JmeTests\src\jme3test\audio\TestMusicPlayer.java:228: error: incomparable types: com.jme3.audio.AudioSource.Status and com.jme3.audio.AudioNode.Status
if (musicSource.getStatus() == Status.Playing){
D:\Software\JMonkey\misc\JmeTests\src\jme3test\audio\TestMusicPlayer.java:254: error: incomparable types: com.jme3.audio.AudioSource.Status and com.jme3.audio.AudioNode.Status
if (musicSource.getStatus() == Status.Playing){
D:\Software\JMonkey\misc\JmeTests\src\jme3test\audio\TestOgg.java:57: error: incomparable types: com.jme3.audio.AudioSource.Status and com.jme3.audio.AudioNode.Status
if (audioSource.getStatus() != AudioNode.Status.Playing){
D:\Software\JMonkey\misc\JmeTests\src\jme3test\bullet\PhysicsHoverControl.java:180: error: cannot find symbol
if (debugShape == null) {
symbol: variable debugShape
location: class PhysicsHoverControl

and so on…

Also the SSAO effect has a strange outcome as well; don´t know if those are related, just thought the more info the better…

ok…
I tried to investigate that error, but I wasn´t really successfull…
Do Java versions have something to do with it? I´m running jdk 1.7.0_21 if it matters.

But back to the original problem:
I have not really advanced on the problem with the Light Scattering, but the SSAO I mentioned looks like this:

I don´t know if the issues are even related, but maybe it helps finding the mistake.

OH MAN!
I got it.
The Sky was not in the right render bucket; this line was missing:
[java]
skybox.setQueueBucket(Bucket.Sky);
[/java]
Therefore when I looked at the sky, I really saw the shadow-side of the sky ^^

But anyways, I still have a little problem.
Is it normal for the framerate to drop from 104 fps to merely 33 fps ?!

That seems quite a lot for a little effect…

I´ll try to deal with it by setting setNbSamples(…);

Well it’s an expensive effect yeah, because it does a radial blurs on some parts of the scene.
I did it a long time ago and I guess it could use some optimization.
lowering the sample number does increase the perf but decrease the visual quality (as usual i’d say).

One optimization could be to render the blur to a frame buffer twice as small as the actual resolution and stretch it full screen.
I’ve seen this in Darksiders 2, and the result was somehow a bit blocky, but was totally acceptable.

2 Likes
<cite>@nehon said:</cite> I've seen this in Darksiders 2, and the result was somehow a bit blocky, but was totally acceptable.

…and friends think me crazy for playing games just to see these. :smiley:

<cite>@nehon said:</cite> One optimization could be to render the blur to a frame buffer twice as small as the actual resolution and stretch it full screen.

Yeah, that may pretty neat.

<cite>@iamcreasy said:</cite> ...and friends think me crazy for playing games just to see these. :D

I actually have a friend that does 3D Graphics and he sometimes just stops playing BF3, stands still and looks at textures… XD

Trust me tahts a infinite loophole you are falling into, it ends with being frustrated when you see uv map erros in cinema films ^^

1 Like

Heheh… my 10 year old son gets frustrated with me sometimes when he’s watching me play games… as I stand there moving the camera at weird angles trying to work out exactly how some game has done water streaming down the sides of things or something.

…kind of thing happened a lot in the Uncharted games.

1 Like
@pspeed said: ...kind of thing happened a lot in the Uncharted games.
I stared at footprints in the sand for hours in uncharted 3... they were just perfect...
1 Like

Not only Uncharted…
Assassins Creed´s snow is pretty awesome as well when you walk through it

<cite>@nehon said:</cite> render the blur to a frame buffer twice as small as the actual resolution and stretch it full screen.

I´ve looked into FBOs a bit but decided I don´t know enough about them ^^
It would be a nice little thing in terms of performance, but of course its not top priority

<cite>@m41q said:</cite> Not only Uncharted... Assassins Creed´s snow is pretty awesome as well when you walk through it

I find myself wandering around the city for no reason. They are just so full of stuff to watch and wonder.

Hi light scattering users. I thought I’d be posting a neat feature I developped a few days ago in this thread, altough it’s not 100% related to your original problem, but it does have the same effect. The problem I’m solving today is when the camera looks at the sun but if the sun is BEHIND a node. Normally, the human eye would adapt within a second and the contrast should become normal again (not “blinded” by the sun, of course) but the problem with the original version is that the whole viewport would be BLACK/DARK or if you will, an almost plain color with no contrast at all. I think this solution was lacking in the Light Scattering Filter, so I made this code snippet that you can put in your simpleUpdate() function loop:

(PLEASE NOTE: this is probably unoptimized and maybe even wrong, but it works for me, please feel free to adapt it and share it back with the JME3 community guys!)

[java]

CollisionResults results = new CollisionResults();
Vector3f s = rootNode.getChild(“Sun container”).getLocalTranslation();
Ray ray = new Ray(cam.getLocation(), new Vector3f(s.getX() - cam.getLocation().getX(), s.getY() - cam.getLocation().getY(), s.getZ() - cam.getLocation().getZ()).normalize());
rayTraceablesRootNode.collideWith(ray, results);
if (results.size() > 0) {
CollisionResult closest = results.getClosestCollision();
System.out.println("closest.getDistance() = " + closest.getDistance() + " / cam.getLocation().distance(s) = " + cam.getLocation().distance(s));
if(closest.getDistance() == cam.getLocation().distance(s)){
System.out.println(“WE STAND IN LIGHT”);
sun_light_scattering_filter.setLightDensity(1.4f);
}
else{
System.out.println(“WE STAND IN SHADOW”);
sun_light_scattering_filter.setLightDensity(0f);
}
} else {
// On some occasions, especially if your sun is out of bounds, there may be no collision at all
if(sun_light_scattering_filter.getLightDensity() == 0f){
System.out.println(“WE’RE NOT SURE, SO DEFAULT TO STAND IN LIGHT”);
sun_light_scattering_filter.setLightDensity(1.4f);
}
}
[/java]

So here’s what the code does in words:

  1. It gets the sun node distance, of course, replace the getChild() parameter with your actual sun node name here. Do not use a light node. Instead, wrap your light node in a generic node and put this generic name as the getChild() parameter here.

  2. It draws a ray between the sun node and the camera node (here it’s “cam_node”, but again, replace this by your camera node)

  3. In this line, pay attention: rayTraceablesRootNode.collideWith(ray, results); You will notice it’s not “rootNode” but “rayTraceablesRootNode” which is simply a wrapper node I made in the simpleInitApp() function of my project so that the rootNode is still there, but inside it there is a wrapper node that wraps all elements that I want to be ray traceable (and also in my app those are casting shadows as well). So lights, particles, effects, light scattering effects and all those “not solid” and often translucent things in my project are NOT in “rayTraceablesRootNode” but are in fact sitting directly as children of “rootNode”. This is very important, because if you do not put volumetric light for instance apart from the other ray traceable nodes, then the ray tracer will always collide with the volumetric cone, because it basically fills the viewport if you look at the light source or such situations so it’s very important you separate what is traceable and what’s not.

  4. So if we found anything, then isolate the closest thing we’ve found and if the distance between the sun and the camera (which we already computed earlier) is not the same as the distance between the camera and what we’ve found in between, then it means the sun is hidden behind an object, so we must be standing in the shadow! Else we’re in the sun. So when we’re in the sun, set the Light Scattering Filter opacity to full (default is 1.4f but feel free to change it to whatever fits your needs) and if we stand in shadow, then reduce it to 0 to maximize contrast (cancel the BLACK/DARK overflow in the viewport) or whatever fits your project like 0.3f or whatever if you still want to keep it showing just a little.

  5. If the ray trace collision did not find anything, on some occasions, like if your sun is out of bounds or something, then assume we’re in the light. The IF branching looks overkill especially in this statement I just explained, but in my project, I do more than this, I have set up timers to animate the fade in/out of the filter opacity, so that it transitions smoothly. Get creative with it! Hope it helps anyone out there.

Here is the effect looks like when it runs:

///// When we look directly at the sun, the original Light Scattering Filter is active and at full opacity.

///// Then if we hide in the shade, meaning there is a node in between the camera and the sun, then the Light Scattering Filter opacity is reduced, making the contrast normal. Else the whole viewport would be compltely black/dark.

Thank you so much for reading me. Please continue to support the JME3 community and share your ideas and concepts with us all.

5 Likes

Brilliant!
thanks a lot.

1 Like

This is really neat. I struggled with this before eventually just abandoning use of scattering completely.

One thing I had a problem with is that for a ray trace it doesn’t count the size of the sun… so if the sun’s center is clipped then the effect disappears even though a lot of the sun is still visible. Did you solve this problem in yours?

What I actually wish is that there was a way to accumulate a counter for the number of sun pixels showing through in the final render so that we could adjust the contrast dynamically based on actual sun peaking through. Easier said than done.

Hey no problem, I also think somebody with greater maths skills should take a look and add to it. Here’s my idea that I don’t know how to program (yet?):

The same ray logic goes, but instead of a point to a point ray, it would be a cylinder or (even better?) an array of points shaped in a cylinder or a grid ray and depending on how many points are colliding with the sun, fade the opacity to X percent, if you know what I mean. So basically, when you’re on the edge, it would not be totally off or totally on, it would be “gradually” fading I guess. Well, that’s just an idea, but I’m not sure how to program this exactly. Maybe make a grid of 16 points or something, like 4 accross by 4 high and use the sun quad shape as the boundaries for this array of points to be distributed about. Like:

X X X X
X X X X
X X X X
X X X X

So if we trace and collide with the sun on these points (the C points) for example:

X X C C
X X C C
X X X C
X X X C

Then we know opacity could be = 6 / 16 * 14f for instance.

Well… explaining it I think gave me the clue as to how to program it! :smiley: Didn’t botter editing the post back hahaha! >.< Anybody’s up to optimize this logic? Else I think I’ll have a try at writing a function for this :smiley:

I meant that if we could see what the framebuffer sees then the contrast adjustment would still work even through leafy tree canopies and so on.

As I recall, colliding a cylinder with mesh data is non-trivial anyway… and still wouldn’t cover transparency.

Oh yeah for sure it’s not perfect all. I would also like to see the scattering effect on the sides of the rock WHILE the camera stands in shadow but without the black/dark viewport overflow but I’m not maths savvy enough to develop such a thing yet. I mean, I agree when you say it’s easier said than done lol… but surely, somebody here on these forums has the knowledge power to make this happen. I would be really grateful! :smiley:

maybe make the radial blur, only blur bright pixels…could be an idea…