|
61 | 61 | uniform mat4 projectionMatrix;
|
62 | 62 | uniform vec3 cameraPos;
|
63 | 63 |
|
64 |
| - out vec3 vOrigin; |
65 |
| - out vec3 vDirection; |
| 64 | + out vec4 vScreenPosition; |
| 65 | + out mat4 vInstanceToViewMatrix; |
66 | 66 |
|
67 | 67 | void main() {
|
68 | 68 | vec4 mvPosition = modelViewMatrix * instanceMatrix * vec4( position, 1.0 );
|
69 | 69 |
|
70 |
| - vOrigin = vec3( inverse( instanceMatrix * modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz; |
71 |
| - vDirection = position - vOrigin; |
72 |
| -
|
73 | 70 | gl_Position = projectionMatrix * mvPosition;
|
| 71 | + vScreenPosition = vec4( gl_Position.xy, 0.0, gl_Position.w ); |
| 72 | + vInstanceToViewMatrix = modelViewMatrix * instanceMatrix; |
74 | 73 | }
|
75 | 74 | `;
|
76 | 75 |
|
77 | 76 | const fragmentShader = /* glsl */`
|
78 | 77 | precision highp float;
|
79 | 78 | precision highp sampler3D;
|
80 | 79 |
|
| 80 | + uniform mat4 viewMatrix; |
81 | 81 | uniform mat4 modelViewMatrix;
|
82 | 82 | uniform mat4 projectionMatrix;
|
83 | 83 |
|
84 |
| - in vec3 vOrigin; |
85 |
| - in vec3 vDirection; |
| 84 | + in vec4 vScreenPosition; |
| 85 | + in mat4 vInstanceToViewMatrix; |
86 | 86 |
|
87 | 87 | out vec4 color;
|
88 | 88 |
|
|
126 | 126 | return normalize( vec3( x, y, z ) );
|
127 | 127 | }
|
128 | 128 |
|
129 |
| - void main(){ |
| 129 | + void main() { |
130 | 130 |
|
131 |
| - vec3 rayDir = normalize( vDirection ); |
132 |
| - vec2 bounds = hitBox( vOrigin, rayDir ); |
| 131 | + // perform w divide in the fragment shader to avoid interpolation artifacts |
| 132 | + vec2 screenUv = vScreenPosition.xy / vScreenPosition.w; |
| 133 | + mat4 invProjectionMatrix = inverse( projectionMatrix ); |
| 134 | + mat4 invInstanceToViewMatrix = inverse( vInstanceToViewMatrix ); |
| 135 | + |
| 136 | + // get camera ray |
| 137 | + vec4 temp; |
| 138 | + vec3 camRayOrigin, camRayEnd; |
| 139 | + temp = invProjectionMatrix * vec4( screenUv, - 1.0, 1.0 ); |
| 140 | + camRayOrigin = temp.xyz / temp.w; |
| 141 | +
|
| 142 | + temp = invProjectionMatrix * vec4( screenUv, 1.0, 1.0 ); |
| 143 | + camRayEnd = temp.xyz / temp.w; |
| 144 | + |
| 145 | + // get local ray |
| 146 | + vec3 instRayOrigin, instRayDirection, instRayEnd; |
| 147 | + instRayOrigin = ( invInstanceToViewMatrix * vec4( camRayOrigin, 1.0 ) ).xyz; |
| 148 | + instRayEnd = ( invInstanceToViewMatrix * vec4( camRayEnd, 1.0 ) ).xyz; |
| 149 | + instRayDirection = normalize( instRayEnd - instRayOrigin ); |
| 150 | +
|
| 151 | + // calculate the start of the ray at the box edge |
| 152 | + vec2 bounds = hitBox( instRayOrigin, instRayDirection ); |
133 | 153 |
|
134 | 154 | if ( bounds.x > bounds.y ) discard;
|
135 | 155 |
|
136 | 156 | bounds.x = max( bounds.x, 0.0 );
|
137 | 157 |
|
138 |
| - vec3 p = vOrigin + bounds.x * rayDir; |
139 |
| - vec3 inc = 1.0 / abs( rayDir ); |
| 158 | + vec3 p = instRayOrigin + bounds.x * instRayDirection; |
| 159 | + vec3 inc = 1.0 / abs( instRayDirection ); |
140 | 160 | float delta = min( inc.x, min( inc.y, inc.z ) );
|
141 | 161 | delta /= 50.0;
|
142 | 162 |
|
| 163 | + // march through the volume |
143 | 164 | for ( float t = bounds.x; t < bounds.y; t += delta ) {
|
144 | 165 |
|
145 | 166 | float d = sample1( p + 0.5 );
|
|
152 | 173 |
|
153 | 174 | }
|
154 | 175 |
|
155 |
| - p += rayDir * delta; |
| 176 | + p += instRayDirection * delta; |
156 | 177 |
|
157 | 178 | }
|
158 | 179 |
|
159 | 180 | if ( color.a == 0.0 ) discard;
|
160 | 181 |
|
| 182 | + // calculate the final point in the ndc coords |
| 183 | + vec4 ndc = projectionMatrix * vInstanceToViewMatrix * vec4( p, 1.0 ); |
| 184 | + ndc /= ndc.w; |
| 185 | +
|
| 186 | + // map the ndc coordinate to depth |
| 187 | + // https://stackoverflow.com/questions/10264949/glsl-gl-fragcoord-z-calculation-and-setting-gl-fragdepth |
| 188 | + float far = gl_DepthRange.far; |
| 189 | + float near = gl_DepthRange.near; |
| 190 | + gl_FragDepth = ( ( ( far - near ) * ndc.z ) + near + far ) / 2.0; |
| 191 | +
|
161 | 192 | }
|
162 | 193 | `;
|
163 | 194 |
|
|
0 commit comments