@@ -22,37 +22,66 @@ uniform vec3 u_minClippingPlane;
2222uniform vec3 u_maxClippingPlane;
2323
2424uniform bool useShading;
25+ uniform bool useClutterRemover;
2526
2627const float MAX_FLOAT = 3.4028235e34 ;
2728const float EPSILON = 0 .00001f;
2829
2930// Sample the volume at a given position and return the material ID
30- float sampleVolume(vec3 samplePos) {
31+ float sampleVolume(vec3 samplePos){
32+ vec3 voxelPos = floor (samplePos) + 0 .5f;
3133 vec3 volPos = samplePos * invDimensions;
3234 return texture(volumeData, volPos).r;
3335}
3436
35- // Get the material at a given sample position, with smoothing for transitions
36- float getNewMaterial(vec3 previousPos, vec3 currentPos) {
37- vec3 samplePos = floor ((previousPos + currentPos) * 0.5 + 0.5 ) - 0.5 ;
38-
39- float voxelMaterial = sampleVolume(samplePos);
40- // vec3 interVoxelPos = fract(samplePos);
41- // vec3 voxelSide = sign(interVoxelPos - 0.5);
42- //
43- // float materialX = sampleVolume(samplePos + vec3(voxelSide.x, 0.0, 0.0));
44- // float materialY = sampleVolume(samplePos + vec3(0.0, voxelSide.y, 0.0));
45- // float materialZ = sampleVolume(samplePos + vec3(0.0, 0.0, voxelSide.z));
46- //
47- // if (materialX == materialY && materialX == materialZ && materialX != voxelMaterial) {
48- // return materialX;
49- // }
50- return voxelMaterial;
37+ // Sliding window: update arrays (shift left, insert new at end)
38+ void updateArrays(
39+ inout float [5 ] materials,
40+ inout vec3 [5 ] samplePositions,
41+ inout vec3 [5 ] normals,
42+ float newMaterial,
43+ vec3 newSamplePos,
44+ vec3 newNormal
45+ ) {
46+ for (int j = 0 ; j < 4 ; ++ j) {
47+ materials[j] = materials[j + 1 ];
48+ samplePositions[j] = samplePositions[j + 1 ];
49+ normals[j] = normals[j + 1 ];
50+ }
51+ materials[4 ] = newMaterial;
52+ samplePositions[4 ] = newSamplePos;
53+ normals[4 ] = newNormal;
54+ }
55+
56+
57+ // Get the current material using the sliding window (like MaterialTransition2D.frag)
58+ // Refinement step: copy previous value instead of re-sampling
59+ float getMaterialID(inout float [5 ] materials, inout vec3 [5 ] samplePositions) {
60+ float firstMaterial = materials[0 ];
61+ float previousMaterial = materials[1 ];
62+ float currentMaterial = materials[2 ];
63+ float nextMaterial = materials[3 ];
64+ float lastMaterial = materials[4 ];
65+
66+ // If a transition is detected, copy the previous value instead of re-sampling
67+ if (currentMaterial != previousMaterial && currentMaterial != nextMaterial
68+ && useClutterRemover) {
69+ currentMaterial = previousMaterial;
70+ materials[2 ] = currentMaterial;
71+ }
72+ return currentMaterial;
5173}
5274
5375// DDA: Find the next voxel boundary intersection and return the step length
5476// Returns the step length and sets hitAxis to 0 (x), 1 (y), or 2 (z)
55- float findNextVoxelIntersection(inout vec3 tNext, vec3 tDelta, vec3 rayDir, float t, out int hitAxis) {
77+ float findNextVoxelIntersection(
78+ inout vec3 tNext,
79+ vec3 tDelta,
80+ vec3 rayDir,
81+ float t,
82+ out int hitAxis,
83+ inout vec3 voxelSampleIndex
84+ ) {
5685 float stepLength;
5786 if (tNext.x < tNext.y) {
5887 if (tNext.x < tNext.z) {
@@ -75,10 +104,12 @@ float findNextVoxelIntersection(inout vec3 tNext, vec3 tDelta, vec3 rayDir, floa
75104 hitAxis = 2 ;
76105 }
77106 }
107+ // Update voxelSampleIndex along the hit axis
108+ float dir = sign (rayDir[hitAxis]);
109+ voxelSampleIndex[hitAxis] += dir;
78110 return stepLength;
79111}
80112
81-
82113// Apply Phong shading at a surface position, using the local normal and lighting
83114vec4 applyShading(
84115 vec3 previousPos,
@@ -128,43 +159,61 @@ void main() {
128159 vec3 samplePos = frontFacesPos;
129160 vec4 color = vec4 (0.0 );
130161
131- float previousMaterial = sampleVolume(samplePos);
132- float currentMaterial = previousMaterial;
133-
134- vec3 previousPos = samplePos;
135- vec3 currentPos = samplePos;
162+ // --- Sliding window arrays ---
163+ float [5 ] materials = float [5 ](0.0 , 0.0 , 0.0 , 0.0 , 0.0 );
164+ vec3 [5 ] samplePositions = vec3 [5 ](samplePos, samplePos, samplePos, samplePos, samplePos);
165+ vec3 [5 ] normals = vec3 [5 ](vec3 (0.0 ), vec3 (0.0 ), vec3 (0.0 ), vec3 (0.0 ), vec3 (0.0 ));
136166
137167 // DDA setup
138168 vec3 tDelta = mix (vec3 (MAX_FLOAT), 1.0 / abs (rayDir), notEqual (rayDir, vec3 (0.0 )));
139- vec3 tNext = abs (step (vec3 (0.0 ), rayDir) * (1.0 - fract (samplePos + 0.5 )) + step (rayDir, vec3 (0.0 )) * fract (samplePos + 0.5 )) * tDelta; // The ray length for each axis needed to reach a boundery, with a 0.5 offset since we use MC for smoothing where the center of a cube is the intersection of 8 voxels
169+ vec3 tNext = abs (step (vec3 (0.0 ), rayDir) * (1.0 - fract (samplePos)) + step (rayDir, vec3 (0.0 )) * fract (samplePos)) * tDelta;
170+ tNext = mix (vec3 (0.0001 ),tNext, notEqual (tNext, vec3 (0.0 )));
140171
141172 float t = 0.0 ;
142-
143- int currentHitAxis = 0 ;
144- int nextHitAxis = 0 ;
173+ int hitAxis = 0 ;
174+
175+ // Track voxel index for correct sampling
176+ vec3 voxelSampleIndex = floor (samplePos);
177+
178+
179+ // Initialize sliding window with first sample and normal
180+ float newMaterial = sampleVolume(voxelSampleIndex);
181+ vec3 newNormal = vec3 (0.0 ); // No normal for the first sample
182+ for (int i = 0 ; i < 5 ; ++ i) {
183+ materials[i] = newMaterial;
184+ samplePositions[i] = samplePos;
185+ normals[i] = newNormal;
186+ }
145187
146188 while (lengthRay > 0.0 ) {
147- currentHitAxis = nextHitAxis;
148- float stepLength = findNextVoxelIntersection(tNext, tDelta, rayDir, t, nextHitAxis);
189+ float stepLength = findNextVoxelIntersection(tNext, tDelta, rayDir, t, hitAxis, voxelSampleIndex);
149190 if (stepLength <= 0.0 || lengthRay <= 0.0 )
150191 break ;
151192
152- previousPos = currentPos;
153- currentPos = samplePos + rayDir * stepLength;
154- previousMaterial = currentMaterial;
155- currentMaterial = getNewMaterial(previousPos, currentPos);
193+ vec3 previousPos = samplePositions[1 ];
194+ vec3 currentPos = samplePos + rayDir * stepLength;
195+
196+ // Compute normal for this step
197+ vec3 newNormal = vec3 (0.0 );
198+ if (hitAxis == 0 ) newNormal.x = - sign (rayDir.x);
199+ else if (hitAxis == 1 ) newNormal.y = - sign (rayDir.y);
200+ else if (hitAxis == 2 ) newNormal.z = - sign (rayDir.z);
201+
202+ // Sample new material and update sliding window (including normals)
203+ newMaterial = sampleVolume(voxelSampleIndex + 0 .5f); // + 0.5f to center the sample
204+ updateArrays(materials, samplePositions, normals, newMaterial, currentPos, newNormal);
205+
206+ float previousMaterial = materials[1 ];
207+ float currentMaterial = getMaterialID(materials, samplePositions);
208+
209+ vec4 sampleColor = texture(materialTexture, vec2 (currentMaterial, previousMaterial) * invMatTexSize);
156210
157211 // Only composite if not the very first step
158212 if (t > 0.0 ) {
159- vec4 sampleColor = texture(materialTexture, vec2 (currentMaterial, previousMaterial) * invMatTexSize);
213+ // Use the normal associated with the current sample (index 2)
214+ vec3 normal = normals[2 ];
160215
161216 if (useShading && previousMaterial != currentMaterial && sampleColor.a > 0.01 ) {
162- // Compute normal based on hit axis and ray direction
163- vec3 normal = vec3 (0.0 );
164- if (currentHitAxis == 0 ) normal.x = - sign (rayDir.x);
165- else if (currentHitAxis == 1 ) normal.y = - sign (rayDir.y);
166- else if (currentHitAxis == 2 ) normal.z = - sign (rayDir.z);
167-
168217 sampleColor = applyShading(previousPos, rayDir, sampleColor, currentPos, normal);
169218 }
170219
@@ -185,4 +234,4 @@ void main() {
185234 }
186235
187236 FragColor = color;
188- }
237+ }
0 commit comments