Screen position accuracy problem in shader

Hi,
I’m trying to port this shadertoy lensflare effect to my three.js scene Shader - Shadertoy BETA by replacing the mouse coordinates with the light position of my scene converted to screen space using this method:

const sunPosition = light.position.clone();
sunPosition.project(camera);
lensflarePass.screen.material.uniforms.sunPosition.value.copy(sunPosition);

and I updated this part in the shadertoy code:
vec2 uv = gl_FragCoord.xy / (resolution.xy * .5); //Add to change resolution.xy - 0.5 to resolution.xy * .5
uv.x *= resolution.x / resolution.y;

  vec3 lightPos = vec3(sunPosition) + 1.;
  lightPos.x *= resolution.x / resolution.y;
  
  vec3 color = texDiffuse.rgb + lensflare(uv, lightPos.xy);

It works, the flare follows my light the way I want, but the effect jitter and shake a lots while I move the camera around, even at relatively low distance (in the range [1 - 800]).
I tried setting logarithmicDepthBuffer to true but it doesn’t help in my case.

It looks like the calculation of the screenspace relative to the viewport in px in the fragment shader results in floating point precision issues.

My guess is that I need to get the actual pixel screen position calculated in the js code, and send it to the shader for better precision, but my GLSL knowledge is pretty limited, and since it’s really hard to debug the values in the shader, I’m a bit lost on how to adapt the shadertoy shader to use pre-calculated pixel view position instead of a [-1, 1] range as an input value for the light position.

Any tips ?

Thanks !

Without a demonstration with code (codepen or jsfiddle) it is hard to help. Also notice this shadertoy shader is quite expensive, about the same visual effect can be archived with textures slightly modified with the shader to not look static.

2 Likes

You can refer to SSAOPass to see how it got the precise screen space position. Related functions are getDepth, getLinearDepth, getViewZ, getViewPosition.

I also commented and linked some resources in this SSRPass, might help a bit too.
The main resources is this tut, and key steps clip, NDC, view(eye), screen are commented in code.

1 Like

So after isolating the code for the lensflare effect, I wasn’t able to reproduce the problem.
The effect appears to work correctly, so my code is apparently OK.
http://jsfiddle.net/vajhm7gt/47/
It must be related to something else in my code, but it’s pretty straightforward, the major difference is the use of ES Modules and a Class structure.
Closing for now.
Thanks for your replies.

So I managed to reproduce the problem by updating the controls after sending the sun position to the shader: http://jsfiddle.net/t4x1jLfg/

I also managed to fix this in my current code base by adding
camera.updateMatrixWorld();
before
sunPosition.project(camera);

Updating the controls before the accessing the light position sounds like the cleanest way to solve my problem, but I was curious to know if there are any advantages to go with the camera.updateMatrixWorld() solution ?

Thanks