VoxelFS.glsl 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // See Intersection.glsl for the definition of intersectScene
  2. // See IntersectionUtils.glsl for the definition of nextIntersection
  3. // See convertUvToBox.glsl, convertUvToCylinder.glsl, or convertUvToEllipsoid.glsl
  4. // for the definition of convertUvToShapeUvSpace. The appropriate function is
  5. // selected based on the VoxelPrimitive shape type, and added to the shader in
  6. // Scene/VoxelRenderResources.js.
  7. // See Octree.glsl for the definitions of TraversalData, SampleData,
  8. // traverseOctreeFromBeginning, and traverseOctreeFromExisting
  9. // See Megatexture.glsl for the definition of accumulatePropertiesFromMegatexture
  10. #define STEP_COUNT_MAX 1000 // Harcoded value because GLSL doesn't like variable length loops
  11. #define ALPHA_ACCUM_MAX 0.98 // Must be > 0.0 and <= 1.0
  12. uniform mat3 u_transformDirectionViewToLocal;
  13. uniform vec3 u_cameraPositionUv;
  14. uniform float u_stepSize;
  15. #if defined(PICKING)
  16. uniform vec4 u_pickColor;
  17. #endif
  18. #if defined(JITTER)
  19. float hash(vec2 p)
  20. {
  21. vec3 p3 = fract(vec3(p.xyx) * 50.0); // magic number = hashscale
  22. p3 += dot(p3, p3.yzx + 19.19);
  23. return fract((p3.x + p3.y) * p3.z);
  24. }
  25. #endif
  26. vec4 getStepSize(in SampleData sampleData, in Ray viewRay, in RayShapeIntersection shapeIntersection) {
  27. #if defined(SHAPE_BOX)
  28. Box voxelBox = constructVoxelBox(sampleData.tileCoords, sampleData.tileUv);
  29. RayShapeIntersection voxelIntersection = intersectBox(viewRay, voxelBox);
  30. vec4 entry = shapeIntersection.entry.w >= voxelIntersection.entry.w ? shapeIntersection.entry : voxelIntersection.entry;
  31. float exit = min(voxelIntersection.exit.w, shapeIntersection.exit.w);
  32. float dt = (exit - entry.w) * RAY_SCALE;
  33. return vec4(normalize(entry.xyz), dt);
  34. #else
  35. float dimAtLevel = pow(2.0, float(sampleData.tileCoords.w));
  36. return vec4(viewRay.dir, u_stepSize / dimAtLevel);
  37. #endif
  38. }
  39. void main()
  40. {
  41. vec4 fragCoord = gl_FragCoord;
  42. vec2 screenCoord = (fragCoord.xy - czm_viewport.xy) / czm_viewport.zw; // [0,1]
  43. vec3 eyeDirection = normalize(czm_windowToEyeCoordinates(fragCoord).xyz);
  44. vec3 viewDirWorld = normalize(czm_inverseViewRotation * eyeDirection); // normalize again just in case
  45. vec3 viewDirUv = normalize(u_transformDirectionViewToLocal * eyeDirection); // normalize again just in case
  46. vec3 viewPosUv = u_cameraPositionUv;
  47. #if defined(SHAPE_BOX)
  48. vec3 dInv = 1.0 / viewDirUv;
  49. Ray viewRayUv = Ray(viewPosUv, viewDirUv, dInv);
  50. #else
  51. Ray viewRayUv = Ray(viewPosUv, viewDirUv);
  52. #endif
  53. Intersections ix;
  54. RayShapeIntersection shapeIntersection = intersectScene(screenCoord, viewRayUv, ix);
  55. // Exit early if the scene was completely missed.
  56. if (shapeIntersection.entry.w == NO_HIT) {
  57. discard;
  58. }
  59. float currT = shapeIntersection.entry.w * RAY_SCALE;
  60. float endT = shapeIntersection.exit.w;
  61. vec3 positionUv = viewPosUv + currT * viewDirUv;
  62. vec3 positionUvShapeSpace = convertUvToShapeUvSpace(positionUv);
  63. // Traverse the tree from the start position
  64. TraversalData traversalData;
  65. SampleData sampleDatas[SAMPLE_COUNT];
  66. traverseOctreeFromBeginning(positionUvShapeSpace, traversalData, sampleDatas);
  67. vec4 step = getStepSize(sampleDatas[0], viewRayUv, shapeIntersection);
  68. #if defined(JITTER)
  69. float noise = hash(screenCoord); // [0,1]
  70. currT += noise * step.w;
  71. positionUv += noise * step.w * viewDirUv;
  72. #endif
  73. FragmentInput fragmentInput;
  74. #if defined(STATISTICS)
  75. setStatistics(fragmentInput.metadata.statistics);
  76. #endif
  77. vec4 colorAccum =vec4(0.0);
  78. for (int stepCount = 0; stepCount < STEP_COUNT_MAX; ++stepCount) {
  79. // Read properties from the megatexture based on the traversal state
  80. Properties properties = accumulatePropertiesFromMegatexture(sampleDatas);
  81. // Prepare the custom shader inputs
  82. copyPropertiesToMetadata(properties, fragmentInput.metadata);
  83. fragmentInput.voxel.positionUv = positionUv;
  84. fragmentInput.voxel.positionShapeUv = positionUvShapeSpace;
  85. fragmentInput.voxel.positionUvLocal = sampleDatas[0].tileUv;
  86. fragmentInput.voxel.viewDirUv = viewDirUv;
  87. fragmentInput.voxel.viewDirWorld = viewDirWorld;
  88. fragmentInput.voxel.surfaceNormal = step.xyz;
  89. fragmentInput.voxel.travelDistance = step.w;
  90. // Run the custom shader
  91. czm_modelMaterial materialOutput;
  92. fragmentMain(fragmentInput, materialOutput);
  93. // Sanitize the custom shader output
  94. vec4 color = vec4(materialOutput.diffuse, materialOutput.alpha);
  95. color.rgb = max(color.rgb, vec3(0.0));
  96. color.a = clamp(color.a, 0.0, 1.0);
  97. // Pre-multiplied alpha blend
  98. colorAccum += (1.0 - colorAccum.a) * vec4(color.rgb * color.a, color.a);
  99. // Stop traversing if the alpha has been fully saturated
  100. if (colorAccum.a > ALPHA_ACCUM_MAX) {
  101. colorAccum.a = ALPHA_ACCUM_MAX;
  102. break;
  103. }
  104. if (step.w == 0.0) {
  105. // Shape is infinitely thin. The ray may have hit the edge of a
  106. // foreground voxel. Step ahead slightly to check for more voxels
  107. step.w == 0.00001;
  108. }
  109. // Keep raymarching
  110. currT += step.w;
  111. positionUv += step.w * viewDirUv;
  112. // Check if there's more intersections.
  113. if (currT > endT) {
  114. #if (INTERSECTION_COUNT == 1)
  115. break;
  116. #else
  117. shapeIntersection = nextIntersection(ix);
  118. if (shapeIntersection.entry.w == NO_HIT) {
  119. break;
  120. } else {
  121. // Found another intersection. Resume raymarching there
  122. currT = shapeIntersection.entry.w * RAY_SCALE;
  123. endT = shapeIntersection.exit.w;
  124. positionUv = viewPosUv + currT * viewDirUv;
  125. }
  126. #endif
  127. }
  128. // Traverse the tree from the current ray position.
  129. // This is similar to traverseOctreeFromBeginning but is faster when the ray is in the same tile as the previous step.
  130. positionUvShapeSpace = convertUvToShapeUvSpace(positionUv);
  131. traverseOctreeFromExisting(positionUvShapeSpace, traversalData, sampleDatas);
  132. step = getStepSize(sampleDatas[0], viewRayUv, shapeIntersection);
  133. }
  134. // Convert the alpha from [0,ALPHA_ACCUM_MAX] to [0,1]
  135. colorAccum.a /= ALPHA_ACCUM_MAX;
  136. #if defined(PICKING)
  137. // If alpha is 0.0 there is nothing to pick
  138. if (colorAccum.a == 0.0) {
  139. discard;
  140. }
  141. out_FragColor = u_pickColor;
  142. #else
  143. out_FragColor = colorAccum;
  144. #endif
  145. }