EDIT: Updated the JSFiddle link as it wasn't rendering correctly in Chrome on Windows 7.
Context
I'm playing around with particles in THREE.JS and using a frame buffer / render target (double buffered) to write positions to a texture. This texture is affected by its own ShaderMaterial, and then read by the PointCloud's ShaderMaterial to position the particles. All well and good so far; everything works as expected.
What I'm trying to do now is use my scene's depth texture to see if any of the particles are intersecting my scene's geometry.
The first thing I did was to reference my depth texture in the PointCloud's fragment shader, using gl_FragCoord.xy / screenResolution.xy
to generate my uv
for the depth texture lookup.
There's a JSFiddle of this here. It's working well - when a particle is behind something in the scene, I tell the particle to be rendered red, not white.
My issue arises when I try to do the same depth comparison in the position texture shader. In the draw fragment shader, I can use the value of gl_FragCoord
to get the particle's position in screen space and use that for the depth uv
lookup, since in the draw vertex shader I use the modelViewMatrix
and projectionMatrix
to set the value of gl_Position
.
I've tried doing this in the position fragment shader, but to no avail. By the way, what I'm aiming to do with this is particle collision with the scene on the GPU.
So... the question (finally!):
- Given a texture where each pixel/texel is a world-space 3d vector representing a particle's position, how can I project this vector to screen-space in the fragment shader, with the end goal of using the
.xy
properties of this vector as auv
lookup in the depth texture?
What I've tried
In the position texture shader, using the same transformations as the draw shader to transform a particle's position to (what I think is) screen-space using the model-view and projection matrices:
// Position texture's fragment shader: void main() { vec2 uv = gl_FragCoord.xy / textureResolution.xy; vec4 particlePosition = texture2D( tPosition, uv ); vec2 screenspacePosition = modelViewMatrix * projectionMatrix * vec4( particlePosition, 1.0 ); vec2 depthUV = vec2( screenspacePosition.xy / screenResolution.xy ); float depth = texture2D( tDepth, depthUV ).x; if( depth < screenspacePosition.z ) { // Particle is behind something in the scene, // so do something... } gl_FragColor = vec4( particlePosition.xyz, 1.0 ); }
Variations on a theme of the above:
- Offsetting the depth's
uv
by doing0.5 - depthUV
- Using the tPosition texture resolution instead of the screen resolution to scale the depthUV.
- Another depth
uv
variation: doingdepthUV = (depthUV - 1.0) * 2.0;
. This helps a little, but the scale is completely off.
- Offsetting the depth's
Help! And thanks in advance.
screenspacePosition.z
byscreenspacePosition.w
? – ovikoomikko