@meimu/mutracer 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +222 -0
- package/LICENSES/FidelityFX-FSR.txt +19 -0
- package/LICENSES/pbrt-v4-Apache-2.0.txt +202 -0
- package/THIRD_PARTY_NOTICES.md +18 -4
- package/dist/assets/bvh.worker.js +1 -1
- package/dist/mutracer.umd.js +6260 -5580
- package/docs/api.md +45 -18
- package/docs/materials.md +4 -2
- package/docs/performance.md +7 -0
- package/docs/post-processing.md +62 -9
- package/docs/progressive-rendering.md +3 -0
- package/docs/sampling.md +4 -0
- package/docs/technical/acceleration.md +52 -0
- package/docs/technical/aovs.md +79 -0
- package/docs/technical/caustics.md +109 -0
- package/docs/technical/continuous-spectrum.md +29 -0
- package/docs/technical/display-upscale.md +82 -0
- package/docs/technical/openpbr.md +99 -0
- package/docs/technical/pbrt-import.md +168 -0
- package/docs/technical/tiling.md +74 -0
- package/docs/technical/webgl.md +53 -0
- package/docs/viewer.md +11 -1
- package/lib/Display.d.ts +19 -5
- package/lib/Display.js +10 -7
- package/lib/Display.js.map +1 -1
- package/lib/Engine.d.ts +2 -1
- package/lib/Engine.js +30 -2
- package/lib/Engine.js.map +1 -1
- package/lib/Render.d.ts +20 -11
- package/lib/Render.js +32 -7
- package/lib/Render.js.map +1 -1
- package/lib/main.d.ts +3 -1
- package/lib/main.js +1 -0
- package/lib/main.js.map +1 -1
- package/lib/oidn.d.ts +1 -1
- package/lib/renderer/AovPrimitiveCache.js +39 -8
- package/lib/renderer/AovPrimitiveCache.js.map +1 -1
- package/lib/renderer/DisplayPostProcess.d.ts +8 -3
- package/lib/renderer/DisplayPostProcess.js +51 -18
- package/lib/renderer/DisplayPostProcess.js.map +1 -1
- package/lib/renderer/MaterialData.js +7 -2
- package/lib/renderer/MaterialData.js.map +1 -1
- package/lib/renderer/RenderingPipeline.d.ts +7 -1
- package/lib/renderer/RenderingPipeline.js.map +1 -1
- package/lib/renderer/TileRender.d.ts +2 -2
- package/lib/renderer/TileRender.js +128 -7
- package/lib/renderer/TileRender.js.map +1 -1
- package/lib/renderer/WGPUAov.d.ts +6 -1
- package/lib/renderer/WGPUAov.js +108 -14
- package/lib/renderer/WGPUAov.js.map +1 -1
- package/lib/renderer/WGPUCanvasSurface.js +12 -1
- package/lib/renderer/WGPUCanvasSurface.js.map +1 -1
- package/lib/renderer/WGPUEnvMapDistribution.js +19 -19
- package/lib/renderer/WGPUFullQuadPass.js +3 -3
- package/lib/renderer/WGPURayTraceOutput.js +12 -12
- package/lib/renderer/WGPURayTracePass.d.ts +17 -4
- package/lib/renderer/WGPURayTracePass.js +194 -71
- package/lib/renderer/WGPURayTracePass.js.map +1 -1
- package/lib/renderer/WGPURenderingPipeline.js +46 -40
- package/lib/renderer/WGPURenderingPipeline.js.map +1 -1
- package/lib/renderer/WebGLAov.js +3 -3
- package/lib/renderer/WebGLAov.js.map +1 -1
- package/lib/renderer/WebGLFullQuadPass.d.ts +1 -1
- package/lib/renderer/WebGLFullQuadPass.js +8 -2
- package/lib/renderer/WebGLFullQuadPass.js.map +1 -1
- package/lib/renderer/WebGLJNLMDenoiser.js +66 -66
- package/lib/renderer/WebGLJNLMDenoiser.js.map +1 -1
- package/lib/renderer/WebGLRayTraceOutputPass.js +4 -4
- package/lib/renderer/WebGLRayTracePass.d.ts +14 -10
- package/lib/renderer/WebGLRayTracePass.js +115 -111
- package/lib/renderer/WebGLRayTracePass.js.map +1 -1
- package/lib/renderer/WebGLRenderingPipeline.js +10 -3
- package/lib/renderer/WebGLRenderingPipeline.js.map +1 -1
- package/lib/renderer/WebGLSkyBaker.js +57 -57
- package/lib/renderer/aov.d.ts +13 -1
- package/lib/renderer/aov.js +21 -2
- package/lib/renderer/aov.js.map +1 -1
- package/lib/renderer/aovDisplay.js +2 -2
- package/lib/renderer/aovDisplay.js.map +1 -1
- package/lib/renderer/binnedSahBvh.d.ts +2 -1
- package/lib/renderer/binnedSahBvh.js +24 -17
- package/lib/renderer/binnedSahBvh.js.map +1 -1
- package/lib/renderer/bvhAccel.d.ts +3 -1
- package/lib/renderer/bvhAccel.js +36 -6
- package/lib/renderer/bvhAccel.js.map +1 -1
- package/lib/renderer/cameraUniform.d.ts +1 -1
- package/lib/renderer/cameraUniform.js +6 -2
- package/lib/renderer/cameraUniform.js.map +1 -1
- package/lib/renderer/compactVertices.d.ts +14 -0
- package/lib/renderer/compactVertices.js +124 -0
- package/lib/renderer/compactVertices.js.map +1 -0
- package/lib/renderer/easu.d.ts +11 -0
- package/lib/renderer/easu.js +156 -0
- package/lib/renderer/easu.js.map +1 -0
- package/lib/renderer/geometryUpdateState.d.ts +1 -0
- package/lib/renderer/geometryUpdateState.js.map +1 -1
- package/lib/renderer/geometryUpdates.js +3 -2
- package/lib/renderer/geometryUpdates.js.map +1 -1
- package/lib/renderer/glsl/aovDisplay.frag.js +5 -5
- package/lib/renderer/glsl/aovReflectance.glsl.js +35 -35
- package/lib/renderer/glsl/aovReflectanceSamples.glsl.js +1 -1
- package/lib/renderer/glsl/aovTrace.frag.js +44 -36
- package/lib/renderer/glsl/aovTrace.frag.js.map +1 -1
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.d.ts +2 -0
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.js +16 -0
- package/lib/renderer/glsl/chunks/cameraProjection.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/cameraRay.glsl.d.ts +1 -1
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js +9 -16
- package/lib/renderer/glsl/chunks/cameraRay.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/emissiveLight.glsl.js +8 -8
- package/lib/renderer/glsl/chunks/envMap.glsl.js +67 -67
- package/lib/renderer/glsl/chunks/intersect.glsl.js +390 -375
- package/lib/renderer/glsl/chunks/intersect.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/materialBuffer.glsl.js +120 -120
- package/lib/renderer/glsl/chunks/openPbrBsdf.glsl.js +562 -562
- package/lib/renderer/glsl/chunks/rand.glsl.js +3 -3
- package/lib/renderer/glsl/chunks/random.glsl.js +4 -4
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js +37 -35
- package/lib/renderer/glsl/chunks/rayTraceCore.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js +70 -74
- package/lib/renderer/glsl/chunks/sampleLight.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.d.ts +1 -1
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js +107 -88
- package/lib/renderer/glsl/chunks/sampleMaterial.glsl.js.map +1 -1
- package/lib/renderer/glsl/chunks/sampleShadowCatcher.glsl.js +11 -11
- package/lib/renderer/glsl/chunks/sampling.glsl.js +77 -77
- package/lib/renderer/glsl/chunks/sobol.glsl.js +70 -70
- package/lib/renderer/glsl/chunks/spectralPrefix.glsl.d.ts +6 -0
- package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js +47 -0
- package/lib/renderer/glsl/chunks/spectralPrefix.glsl.js.map +1 -0
- package/lib/renderer/glsl/chunks/textureLinear.glsl.js +5 -5
- package/lib/renderer/glsl/chunks/uvProjection.glsl.js +11 -11
- package/lib/renderer/glsl/depthQuery.frag.js +12 -6
- package/lib/renderer/glsl/depthQuery.frag.js.map +1 -1
- package/lib/renderer/glsl/normalizeRayTraceOutput.frag.js +10 -10
- package/lib/renderer/glsl/rayTrace.frag.js +233 -170
- package/lib/renderer/glsl/rayTrace.frag.js.map +1 -1
- package/lib/renderer/glsl/shadowCatcher.frag.js +10 -9
- package/lib/renderer/glsl/shadowCatcher.frag.js.map +1 -1
- package/lib/renderer/glsl/webglPipeline.frag.js +58 -58
- package/lib/renderer/gpuMemory.js +1 -1
- package/lib/renderer/gpuMemory.js.map +1 -1
- package/lib/renderer/openPbrEnergyLut.d.ts +2 -1
- package/lib/renderer/openPbrEnergyLut.js +18 -1
- package/lib/renderer/openPbrEnergyLut.js.map +1 -1
- package/lib/renderer/pathLimits.d.ts +5 -4
- package/lib/renderer/pathLimits.js +6 -5
- package/lib/renderer/pathLimits.js.map +1 -1
- package/lib/renderer/prepareMeshBVH.d.ts +2 -0
- package/lib/renderer/prepareMeshBVH.js +5 -3
- package/lib/renderer/prepareMeshBVH.js.map +1 -1
- package/lib/renderer/progressiveScheduler.js +1 -1
- package/lib/renderer/progressiveScheduler.js.map +1 -1
- package/lib/renderer/renderPipeline.d.ts +4 -0
- package/lib/renderer/renderPipeline.js +1 -0
- package/lib/renderer/renderPipeline.js.map +1 -1
- package/lib/renderer/researchTransport.d.ts +1 -1
- package/lib/renderer/researchTransport.js.map +1 -1
- package/lib/renderer/sceneAssembly.d.ts +1 -1
- package/lib/renderer/sceneAssembly.js +4 -3
- package/lib/renderer/sceneAssembly.js.map +1 -1
- package/lib/renderer/sceneChangeDetector.d.ts +1 -1
- package/lib/renderer/sceneChangeDetector.js +3 -1
- package/lib/renderer/sceneChangeDetector.js.map +1 -1
- package/lib/renderer/sceneLayoutSchema.d.ts +1 -0
- package/lib/renderer/sceneLayoutSchema.js +2 -2
- package/lib/renderer/sceneLayoutSchema.js.map +1 -1
- package/lib/renderer/scenePreparation.d.ts +3 -2
- package/lib/renderer/scenePreparation.js +18 -2
- package/lib/renderer/scenePreparation.js.map +1 -1
- package/lib/renderer/scratchSampling.js +6 -6
- package/lib/renderer/spectrum.js +2 -2
- package/lib/renderer/staticBvhPreparation.d.ts +9 -0
- package/lib/renderer/staticBvhPreparation.js +8 -2
- package/lib/renderer/staticBvhPreparation.js.map +1 -1
- package/lib/renderer/surfaceHit.d.ts +10 -0
- package/lib/renderer/surfaceHit.js +22 -0
- package/lib/renderer/surfaceHit.js.map +1 -0
- package/lib/renderer/tangentRequirements.d.ts +2 -0
- package/lib/renderer/tangentRequirements.js +7 -0
- package/lib/renderer/tangentRequirements.js.map +1 -0
- package/lib/renderer/textureAtlas.d.ts +4 -0
- package/lib/renderer/textureAtlas.js +48 -2
- package/lib/renderer/textureAtlas.js.map +1 -1
- package/lib/renderer/webgl.js +4 -0
- package/lib/renderer/webgl.js.map +1 -1
- package/lib/renderer/webglVertexAttributes.d.ts +17 -0
- package/lib/renderer/webglVertexAttributes.js +44 -0
- package/lib/renderer/webglVertexAttributes.js.map +1 -0
- package/lib/renderer/wgpuBindlessSource.js +2 -2
- package/lib/renderer/wgpuMaterialConstants.js +4 -3
- package/lib/renderer/wgpuMaterialConstants.js.map +1 -1
- package/lib/renderer/wgpuSceneUniform.js +2 -2
- package/lib/renderer/wgpuSceneUniform.js.map +1 -1
- package/lib/renderer/wgpuShaderSource.d.ts +15 -0
- package/lib/renderer/wgpuShaderSource.js +1 -1
- package/lib/renderer/wgpuShaderSource.js.map +1 -1
- package/lib/renderer/wgsl/aovCompact.wgsl.d.ts +4 -0
- package/lib/renderer/wgsl/aovCompact.wgsl.js +26 -0
- package/lib/renderer/wgsl/aovCompact.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/aovDisplay.wgsl.js +9 -9
- package/lib/renderer/wgsl/aovReflectance.wgsl.js +39 -39
- package/lib/renderer/wgsl/aovReflectanceSamples.wgsl.js +1 -1
- package/lib/renderer/wgsl/aovResolve.wgsl.d.ts +4 -0
- package/lib/renderer/wgsl/aovResolve.wgsl.js +21 -2
- package/lib/renderer/wgsl/aovResolve.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js +2 -2
- package/lib/renderer/wgsl/aovSnapshot.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/aovTrace.wgsl.js +31 -31
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js +56 -0
- package/lib/renderer/wgsl/aovTraceDisplay.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/bloom.wgsl.js +18 -18
- package/lib/renderer/wgsl/causticLight.compute.d.ts +1 -1
- package/lib/renderer/wgsl/causticLight.compute.js +121 -119
- package/lib/renderer/wgsl/causticLight.compute.js.map +1 -1
- package/lib/renderer/wgsl/chunks/background.wgsl.js +46 -46
- package/lib/renderer/wgsl/chunks/causticAdjoint.wgsl.js +4 -4
- package/lib/renderer/wgsl/chunks/causticAtomic.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/caustics.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/common.wgsl.js +4 -4
- package/lib/renderer/wgsl/chunks/envMap.wgsl.js +30 -30
- package/lib/renderer/wgsl/chunks/intersect.wgsl.d.ts +6 -2
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js +550 -542
- package/lib/renderer/wgsl/chunks/intersect.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js +18 -16
- package/lib/renderer/wgsl/chunks/intersectionAlpha.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.d.ts +2 -1
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js +70 -69
- package/lib/renderer/wgsl/chunks/materialBuffer.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/openPbrBsdf.wgsl.js +593 -593
- package/lib/renderer/wgsl/chunks/pdm_displacement.wgsl.js +118 -118
- package/lib/renderer/wgsl/chunks/rand.wgsl.js +3 -3
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.d.ts +4 -1
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js +32 -26
- package/lib/renderer/wgsl/chunks/rayTraceCore.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sampleLight.wgsl.js +114 -114
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js +159 -137
- package/lib/renderer/wgsl/chunks/sampleMaterial.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/chunks/sampleShadowCatcher.wgsl.js +8 -8
- package/lib/renderer/wgsl/chunks/sampling.wgsl.js +74 -74
- package/lib/renderer/wgsl/chunks/sobol.wgsl.js +74 -74
- package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.d.ts +6 -0
- package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js +66 -0
- package/lib/renderer/wgsl/chunks/spectralPrefix.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/chunks/uvProjection.wgsl.js +11 -11
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js +61 -0
- package/lib/renderer/wgsl/chunks/vertexAttributes.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/compose.frag.wgsl.js +99 -97
- package/lib/renderer/wgsl/compose.frag.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/customDenoise.wgsl.js +10 -10
- package/lib/renderer/wgsl/depthQuery.wgsl.d.ts +1 -1
- package/lib/renderer/wgsl/depthQuery.wgsl.js +11 -2
- package/lib/renderer/wgsl/depthQuery.wgsl.js.map +1 -1
- package/lib/renderer/wgsl/easu.wgsl.d.ts +2 -0
- package/lib/renderer/wgsl/easu.wgsl.js +80 -0
- package/lib/renderer/wgsl/easu.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.d.ts +21 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.js +230 -0
- package/lib/renderer/wgsl/easuDetail.wgsl.js.map +1 -0
- package/lib/renderer/wgsl/jnlm.compute.js +74 -74
- package/lib/renderer/wgsl/jnlm.compute.js.map +1 -1
- package/lib/renderer/wgsl/offlineAdaptive.compute.js +26 -26
- package/lib/renderer/wgsl/oidnAuxiliary.wgsl.js +3 -3
- package/lib/renderer/wgsl/photonMap.compute.js +89 -89
- package/lib/renderer/wgsl/proceduralSky.compute.js +61 -61
- package/lib/renderer/wgsl/rayTrace.compute.d.ts +14 -0
- package/lib/renderer/wgsl/rayTrace.compute.js +395 -333
- package/lib/renderer/wgsl/rayTrace.compute.js.map +1 -1
- package/lib/scene/Scene.js.map +1 -1
- package/lib/settings/render.d.ts +11 -0
- package/lib/settings/render.js +1 -0
- package/lib/settings/render.js.map +1 -1
- package/lib/util/fromTHREE.js +21 -14
- package/lib/util/fromTHREE.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +5 -2
- package/lib/oidnBundledWeights.cdn.d.ts +0 -2
- package/lib/oidnBundledWeights.cdn.js +0 -5
- package/lib/oidnBundledWeights.cdn.js.map +0 -1
- package/lib/renderer/bvh.worker.d.ts +0 -1
- package/lib/renderer/bvh.worker.js +0 -16
- package/lib/renderer/bvh.worker.js.map +0 -1
- package/lib/renderer/bvhWorkerBuild.d.ts +0 -13
- package/lib/renderer/bvhWorkerBuild.js +0 -17
- package/lib/renderer/bvhWorkerBuild.js.map +0 -1
- package/lib/renderer/lightCore.d.ts +0 -12
- package/lib/renderer/lightCore.js +0 -13
- package/lib/renderer/lightCore.js.map +0 -1
- package/lib/renderer/materialCore.d.ts +0 -8
- package/lib/renderer/materialCore.js +0 -9
- package/lib/renderer/materialCore.js.map +0 -1
- package/lib/scene/PixelTexture.d.ts +0 -6
- package/lib/scene/PixelTexture.js +0 -10
- package/lib/scene/PixelTexture.js.map +0 -1
- package/lib/util/studioLighting.d.ts +0 -18
- package/lib/util/studioLighting.js +0 -36
- package/lib/util/studioLighting.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intersect.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/intersect.glsl.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapAlphaUsageConstants } from '../../materialConstants.js';\n// Portions adapted from ray-tracing-renderer@0.10.15\n// (https://github.com/hoverinc/ray-tracing-renderer).\n// Copyright (c) 2019 HOVER, MIT license; see LICENSES/RayTracingRenderer-MIT.txt.\n\nimport { INSTANCE_VEC4_STRIDE } from '../../bvhAccel.js';\nimport { createShaderMixin, glsl, Shader } from '../../shader.js';\n\nfunction getBVHTraverseCode(\n handleHitCode: string,\n skipTriangleCode = '',\n initialTMax = 'RAY_MAX_DISTANCE'\n) {\n const intersectTriangles = glsl`\n ivec3 vertexOffset = ivec3(floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).y));\n for (int k = 0; k < primitiveCount; k++) {\n int triangleIndex = primitiveOffset + k;\n ${skipTriangleCode}\n vec4 r3 = fetchBVH(triangleIndex);\n ivec3 index = floatBitsToInt(r3.xyz) + vertexOffset;\n Triangle tri = Triangle(\n fetchData(positionBuffer, index.x, vertexColumns).xyz,\n fetchData(positionBuffer, index.y, vertexColumns).xyz,\n fetchData(positionBuffer, index.z, vertexColumns).xyz\n );\n TriangleIntersect hit = intersectTriangle(o, d, tri, maxDim, shear, tMax);\n\n if (hit.t > 0.0) {\n tMax = hit.t;\n vec3 e1 = tri.p1 - tri.p0;\n vec3 e2 = tri.p2 - tri.p0;\n vec3 faceNormal = normalize(cross(e1, e2));\n int sideMaterialIndex = int(unpackMaterialIndex(\n floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).z)\n ).x);\n bool materialDoubleSided = fetchMatData(\n sideMaterialIndex * MAT_DATA_SIZE + MAT_ROW_ALPHA\n ).z > 0.5;\n if (!doubleSided && !materialDoubleSided && dot(faceNormal, d) > 0.0) {\n continue;\n }\n\n ${handleHitCode}\n }\n }\n`;\n return glsl`\n ivec2 stack[STACK_SIZE];\n int top = -1;\n int prevInsIdx = -1;\n float tMax = ${initialTMax};\n\n vec3 o = ray.o;\n vec3 d = ray.d;\n\n bool isHit = false;\n vec3 hitFaceNormal;\n vec3 hitBarycentric;\n ivec3 hitIndex;\n\n Triangle hitTri;\n\n // TODO not sure why. but do root node check here will cause rendering wrong in windows.\n top = 0;\n stack[0] = ivec2(0, -1);\n\n int iter = 0;\n while(top >= 0 && iter < 5000) {\n iter++;\n ivec2 node = stack[top--];\n\n int insIdx = node.y;\n\n if (insIdx != prevInsIdx) {\n if (insIdx < 0) {\n o = ray.o;\n d = ray.d;\n }\n else {\n mat4 w2l = mat4(\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n o = (w2l * vec4(ray.o, 1.0)).xyz;\n d = (w2l * vec4(ray.d, 0.0)).xyz;\n }\n maxDim = maxDimension(abs(d));\n shear = getShear(d, maxDim);\n prevInsIdx = insIdx;\n }\n\n int bufferOff = insIdx < 0 ? 0 : blasOffset;\n uint encodedBlasOffset = insIdx < 0 ? 0u : floatBitsToUint(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).x);\n int blasLayout = int(encodedBlasOffset >> 30u);\n int blasInsOffset = int(encodedBlasOffset & 0x3fffffffu);\n int primitiveCount = 0;\n int primitiveOffset = 0;\n\n if (blasLayout == 3) {\n uint nodeInfo = uint(node.x);\n if ((nodeInfo & 0x80000000u) != 0u) {\n primitiveCount = int((nodeInfo >> 23u) & 0xffu);\n primitiveOffset = bufferOff + blasInsOffset + int(nodeInfo & 0x007fffffu);\n }\n else {\n int i = node.x + bufferOff;\n vec4 compressed0 = fetchBVH(i);\n vec4 compressed1 = fetchBVH(i + 1);\n vec4 compressed2 = fetchBVH(i + 2);\n vec4 compressed3 = fetchBVH(i + 3);\n vec4 compressed4 = fetchBVH(i + 4);\n uint header = floatBitsToUint(compressed0.w);\n int exponentX = int(header << 24u) >> 24;\n int exponentY = int((header >> 8u) << 24u) >> 24;\n int exponentZ = int((header >> 16u) << 24u) >> 24;\n vec3 quantizationScale = vec3(\n uintBitsToFloat(uint(exponentX + 127) << 23u),\n uintBitsToFloat(uint(exponentY + 127) << 23u),\n uintBitsToFloat(uint(exponentZ + 127) << 23u)\n );\n uint childBase = floatBitsToUint(compressed1.x);\n uint triangleBase = floatBitsToUint(compressed1.y);\n uint internalMask = header >> 24u;\n uint octant = (d.x < 0.0 ? 4u : 0u) |\n (d.y < 0.0 ? 2u : 0u) |\n (d.z < 0.0 ? 1u : 0u);\n uint quantizedWords[12] = uint[12](\n floatBitsToUint(compressed2.x), floatBitsToUint(compressed2.y),\n floatBitsToUint(compressed2.z), floatBitsToUint(compressed2.w),\n floatBitsToUint(compressed3.x), floatBitsToUint(compressed3.y),\n floatBitsToUint(compressed3.z), floatBitsToUint(compressed3.w),\n floatBitsToUint(compressed4.x), floatBitsToUint(compressed4.y),\n floatBitsToUint(compressed4.z), floatBitsToUint(compressed4.w)\n );\n\n for (int order = 7; order >= 0; order--) {\n uint slot = uint(order) ^ octant;\n uint metaWord = slot >= 4u\n ? floatBitsToUint(compressed1.w)\n : floatBitsToUint(compressed1.z);\n uint meta = (metaWord >> ((slot & 3u) * 8u)) & 0xffu;\n if (meta == 0u) continue;\n uint byteShift = (slot & 3u) * 8u;\n uint wordOffset = slot >> 2u;\n vec3 quantizedMin = vec3(\n float((quantizedWords[wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[2u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[4u + wordOffset] >> byteShift) & 0xffu)\n );\n vec3 quantizedMax = vec3(\n float((quantizedWords[6u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[8u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[10u + wordOffset] >> byteShift) & 0xffu)\n );\n vec3 childMin = compressed0.xyz + quantizedMin * quantizationScale;\n vec3 childMax = compressed0.xyz + quantizedMax * quantizationScale;\n if (intersectBox(o, d, childMin, childMax, tMax) <= 0.0) continue;\n uint localOffset = meta & 0x1fu;\n if (localOffset >= 24u) {\n uint precedingMask = internalMask & ((1u << slot) - 1u);\n uint internalIndex = childBase + countBvhBits(precedingMask);\n stack[++top] = ivec2(\n blasInsOffset + int(internalIndex * 5u), insIdx\n );\n }\n else {\n uint triangleCount = countBvhBits(meta >> 5u);\n uint primitiveAddress = triangleBase + localOffset;\n uint leafInfo = 0x80000000u |\n (triangleCount << 23u) |\n (primitiveAddress & 0x007fffffu);\n stack[++top] = ivec2(int(leafInfo), insIdx);\n }\n }\n }\n }\n else if (blasLayout == 2) {\n int i = node.x + bufferOff;\n vec4 gpu0 = fetchBVH(i);\n vec4 gpu1 = fetchBVH(i + 1);\n vec4 gpu2 = fetchBVH(i + 2);\n vec4 gpu3 = fetchBVH(i + 3);\n primitiveCount = int(floatBitsToUint(gpu2.w));\n if (primitiveCount > 0) {\n primitiveOffset = bufferOff + blasInsOffset + int(floatBitsToUint(gpu3.w));\n }\n else {\n int left = blasInsOffset + int(floatBitsToUint(gpu0.w) * 4u);\n int right = blasInsOffset + int(floatBitsToUint(gpu1.w) * 4u);\n float d0 = intersectBox(o, d, gpu0.xyz, gpu1.xyz, tMax);\n float d1 = intersectBox(o, d, gpu2.xyz, gpu3.xyz, tMax);\n if (d0 > d1) {\n if (d0 > 0.0) stack[++top] = ivec2(left, insIdx);\n if (d1 > 0.0) stack[++top] = ivec2(right, insIdx);\n }\n else {\n if (d1 > 0.0) stack[++top] = ivec2(right, insIdx);\n if (d0 > 0.0) stack[++top] = ivec2(left, insIdx);\n }\n }\n }\n else if (blasLayout == 1) {\n uint nodeInfo = uint(node.x);\n if ((nodeInfo & 0x80000000u) != 0u) {\n primitiveCount = int((nodeInfo >> 23u) & 0xffu);\n primitiveOffset = bufferOff + blasInsOffset + int(nodeInfo & 0x007fffffu);\n }\n else {\n int i = node.x + bufferOff;\n vec4 wide0 = fetchBVH(i);\n vec4 wide1 = fetchBVH(i + 1);\n vec4 wide2 = fetchBVH(i + 2);\n vec4 wide3 = fetchBVH(i + 3);\n vec3 nodeMin = wide0.xyz;\n vec3 nodeExtent = vec3(wide0.w, wide1.x, wide1.y);\n uint childInfos[4] = uint[4](\n floatBitsToUint(wide1.z), floatBitsToUint(wide1.w),\n floatBitsToUint(wide2.x), floatBitsToUint(wide2.y)\n );\n vec4 childMinX = unpackBvh4Bounds(floatBitsToUint(wide2.z));\n vec4 childMinY = unpackBvh4Bounds(floatBitsToUint(wide2.w));\n vec4 childMinZ = unpackBvh4Bounds(floatBitsToUint(wide3.x));\n vec4 childMaxX = unpackBvh4Bounds(floatBitsToUint(wide3.y));\n vec4 childMaxY = unpackBvh4Bounds(floatBitsToUint(wide3.z));\n vec4 childMaxZ = unpackBvh4Bounds(floatBitsToUint(wide3.w));\n vec3 invD = traversalInverse(d);\n vec3 padding = depthSlabPadding(invD, o);\n vec4 tx0 = (nodeMin.x + childMinX * nodeExtent.x - o.x) * invD.x;\n vec4 tx1 = (nodeMin.x + childMaxX * nodeExtent.x - o.x) * invD.x;\n vec4 ty0 = (nodeMin.y + childMinY * nodeExtent.y - o.y) * invD.y;\n vec4 ty1 = (nodeMin.y + childMaxY * nodeExtent.y - o.y) * invD.y;\n vec4 tz0 = (nodeMin.z + childMinZ * nodeExtent.z - o.z) * invD.z;\n vec4 tz1 = (nodeMin.z + childMaxZ * nodeExtent.z - o.z) * invD.z;\n vec4 tNear = max(max((min(tx0, tx1) - vec4(padding.x)), (min(ty0, ty1) - vec4(padding.y))), (min(tz0, tz1) - vec4(padding.z)));\n vec4 tFar = min(min((max(tx0, tx1) + vec4(padding.x)), (max(ty0, ty1) + vec4(padding.y))), (max(tz0, tz1) + vec4(padding.z)));\n vec4 distance = mix(tFar, tNear, greaterThan(tNear, vec4(0.0)));\n distance = mix(distance, vec4(-1.0), greaterThan(tNear, min(tFar, vec4(tMax))));\n float childDistances[4] = float[4](distance.x, distance.y, distance.z, distance.w);\n\n // Push far-to-near so that the closest child is popped first.\n for (int order = 0; order < 4; order++) {\n float farthestDistance = -1.0;\n int farthestChild = -1;\n for (int child = 0; child < 4; child++) {\n if (childInfos[child] != 0u && childDistances[child] > farthestDistance) {\n farthestDistance = childDistances[child];\n farthestChild = child;\n }\n }\n if (farthestChild >= 0 && farthestDistance > 0.0) {\n uint childInfo = childInfos[farthestChild];\n int childAddress = int(childInfo);\n if ((childInfo & 0x80000000u) == 0u) {\n childAddress += blasInsOffset;\n }\n stack[++top] = ivec2(childAddress, insIdx);\n childDistances[farthestChild] = -1.0;\n }\n }\n }\n }\n else {\n int i = node.x + bufferOff;\n vec4 r1 = fetchBVH(i);\n int pointerToRightOrNumPrims = floatBitsToInt(r1.w);\n\n if (pointerToRightOrNumPrims >= 0) {\n int left = node.x + 2;\n int right = pointerToRightOrNumPrims + blasInsOffset;\n\n float d0 = intersectBox(o, d, fetchBVH(left + bufferOff).xyz, fetchBVH(left + 1 + bufferOff).xyz, tMax);\n float d1 = intersectBox(o, d, fetchBVH(right + bufferOff).xyz, fetchBVH(right + 1 + bufferOff).xyz, tMax);\n if (d0 > d1) {\n if (d0 > 0.0) {\n stack[++top] = ivec2(left, insIdx);\n }\n if (d1 > 0.0) {\n stack[++top] = ivec2(right, insIdx);\n }\n }\n else {\n if (d1 > 0.0) {\n stack[++top] = ivec2(right, insIdx);\n }\n if (d0 > 0.0) {\n stack[++top] = ivec2(left, insIdx);\n }\n }\n }\n else {\n if (insIdx < 0) {\n for (int k = 0; k < -pointerToRightOrNumPrims; k++) {\n vec4 r3 = fetchBVH(i + 2 + k);\n stack[++top] = ivec2(floatBitsToInt(r3.y), floatBitsToInt(r3.x));\n }\n }\n else {\n primitiveCount = -pointerToRightOrNumPrims;\n primitiveOffset = i + 2;\n }\n }\n }\n if (primitiveCount > 0) {\n ${intersectTriangles}\n }\n }\n`;\n}\n\nexport default createShaderMixin({\n uniforms: {\n positionBuffer: Shader.uniform('sampler2D'),\n normalBuffer: Shader.uniform('sampler2D'),\n tangentBuffer: Shader.uniform('sampler2D'),\n uvBuffer: Shader.uniform('sampler2D'),\n uv1Buffer: Shader.uniform('sampler2D'),\n colorBuffer: Shader.uniform('sampler2D'),\n materialIndexBuffer: Shader.uniform('sampler2D'),\n\n bvhBuffer: Shader.uniform('sampler2D'),\n instancesBuffer: Shader.uniform('sampler2D'),\n\n bvhColumns: Shader.uniform('int', 1),\n vertexColumns: Shader.uniform('int', 1),\n\n instancesColumns: Shader.uniform('int', 1),\n\n blasOffset: Shader.uniform('int'),\n\n isEmptyScene: Shader.uniform('bool')\n },\n main: glsl`\n\nstruct Triangle {\n vec3 p0;\n vec3 p1;\n vec3 p2;\n};\n#ifdef NUM_LIGHTS\nfloat intersectSphere(float rad, vec3 pos, Ray r) {\n vec3 op = pos - r.o;\n float eps = 0.001;\n float b = dot(op, r.d);\n float det = b * b - dot(op, op) + rad * rad;\n if (det < 0.0)\n return INF;\n\n det = sqrt(det);\n float t1 = b - det;\n if (t1 > eps)\n return t1;\n\n float t2 = b + det;\n if (t2 > eps)\n return t2;\n\n return INF;\n}\n\nfloat intersectRect(vec3 pos, vec3 u, vec3 v, vec3 n, Ray r) {\n float dt = dot(r.d, n);\n float t = (dot(n, pos) - dot(n, r.o)) / dt;\n\n if (t > EPS) {\n vec3 p = r.o + r.d * t;\n vec3 vi = p - pos;\n float a1 = dot(u / dot(u, u), vi);\n if (a1 >= 0.0 && a1 <= 1.0) {\n float a2 = dot(v / dot(v, v), vi);\n if (a2 >= 0.0 && a2 <= 1.0) {\n return t;\n }\n }\n }\n\n return INF;\n}\n\nfloat sphereSolidAnglePdf(vec3 origin, vec3 center, float radius) {\n float centerDistance = distance(origin, center);\n if (centerDistance <= radius) return INV4PI;\n float sinThetaMaxSquared = min(1.0, radius * radius / (centerDistance * centerDistance));\n float cosThetaMax = sqrt(max(0.0, 1.0 - sinThetaMaxSquared));\n // Match the cancellation-free solid angle used by direct light sampling.\n float oneMinusCosThetaMax = sinThetaMaxSquared / (1.0 + cosThetaMax);\n return 1.0 / max(TWOPI * oneMinusCosThetaMax, 1e-8);\n}\n\nfloat intersectLight(Ray r, Light light, out LightSampleRec lightSample) {\n // Directional lights are delta sources without finite geometry. Start at\n // INF so they cannot accidentally terminate a BSDF continuation as a\n // geometric light hit; rect and sphere branches overwrite this value.\n float d = INF;\n vec3 u = light.u;\n vec3 v = light.v;\n int type = int(light.type);\n\n#ifdef HAS_RECT_LIGHTS\n if (type == RECT_LIGHT) {\n // Adjust the position from center to start corner\n vec3 pos = light.position-u*0.5-v*0.5;\n vec3 normal = normalize(cross(u, v));\n if (dot(normal, r.d) > 0.) // Hide backfacing quad light\n return INF;\n\n d = intersectRect(pos, u, v, normal, r);\n if (d < 0.) {\n d = INF;\n }\n else {\n float cosTheta = dot(-r.d, normal);\n float spread = light.spread;\n if (cosTheta >= cos(spread * PI / 2.0)) {\n lightSample.pdf = (d * d) / (light.area * cosTheta);\n lightSample.emission = light.emission;\n }\n }\n }\n#endif\n#ifdef HAS_SPHERE_LIGHTS\n if (type == SPHERE_LIGHT) {\n if (light.radius <= 0.0) {\n vec3 toPoint = light.position - r.o;\n float projection = dot(toPoint, r.d);\n vec3 perpendicular = toPoint - projection * r.d;\n if (projection <= EPS || dot(perpendicular, perpendicular) > 1e-8) return INF;\n d = projection;\n lightSample.direction = r.d;\n lightSample.normal = -r.d;\n lightSample.dist = d;\n lightSample.pdf = 1.0;\n lightSample.isDelta = true;\n } else {\n d = intersectSphere(light.radius, light.position, r);\n lightSample.isDelta = false;\n }\n if (d < 0.) {\n d = INF;\n }\n else {\n if (light.radius > 0.0) {\n lightSample.pdf = sphereSolidAnglePdf(r.o, light.position, light.radius);\n }\n lightSample.emission = light.radius <= 0.0\n ? light.emission / max(d * d, 1e-8)\n : light.emission;\n }\n }\n#endif\n#ifdef HAS_SPOT_LIGHTS\n if (type == SPOT_LIGHT) {\n if (light.radius <= 0.0) {\n vec3 toPoint = light.position - r.o;\n float projection = dot(toPoint, r.d);\n vec3 perpendicular = toPoint - projection * r.d;\n if (projection <= EPS || dot(perpendicular, perpendicular) > 1e-8) return INF;\n d = projection;\n lightSample.direction = r.d;\n lightSample.normal = -r.d;\n lightSample.dist = d;\n lightSample.pdf = 1.0;\n lightSample.isDelta = true;\n } else {\n d = intersectSphere(light.radius, light.position, r);\n lightSample.isDelta = false;\n }\n if (d != INF) {\n vec3 hitPt = r.o + d * r.d;\n float multiplier = evaluateSpotEmissionMultiplier(light, normalize(r.o - hitPt));\n if (multiplier <= 0.0) return INF;\n if (light.radius > 0.0) {\n lightSample.pdf = sphereSolidAnglePdf(r.o, light.position, light.radius);\n }\n lightSample.emission = light.emission * multiplier * (light.radius <= 0.0\n ? 1.0 / max(d * d, 1e-8)\n : 1.0);\n }\n }\n#endif\n\n return d;\n}\n#endif\n\nint randomPickMaterial(ivec4 m0, ivec4 m1, ivec4 m2, vec3 bary) {\n vec2 m00 = unpackMaterialIndex(m0.x);\n vec2 m01 = unpackMaterialIndex(m0.y);\n vec2 m02 = unpackMaterialIndex(m0.z);\n vec2 m10 = unpackMaterialIndex(m1.x);\n vec2 m11 = unpackMaterialIndex(m1.y);\n vec2 m12 = unpackMaterialIndex(m1.z);\n vec2 m20 = unpackMaterialIndex(m2.x);\n vec2 m21 = unpackMaterialIndex(m2.y);\n vec2 m22 = unpackMaterialIndex(m2.z);\n float w00 = m00.y * bary.x;\n float w01 = m01.y * bary.x;\n float w02 = m02.y * bary.x;\n float w10 = m10.y * bary.y;\n float w11 = m11.y * bary.y;\n float w12 = m12.y * bary.y;\n float w20 = m20.y * bary.z;\n float w21 = m21.y * bary.z;\n float w22 = m22.y * bary.z;\n\n float wTotal = w00 + w01 + w02 + w10 + w11 + w12 + w20 + w21 + w22;\n // Accumulate weights\n w00 = w00 / wTotal;\n w01 = w01 / wTotal + w00;\n w02 = w02 / wTotal + w01;\n w10 = w10 / wTotal + w02;\n w11 = w11 / wTotal + w10;\n w12 = w12 / wTotal + w11;\n w20 = w20 / wTotal + w12;\n w21 = w21 / wTotal + w20;\n w22 = w22 / wTotal + w21;\n\n float rand = hashedSample(0u);\n float mIdx;\n if (rand < w00) {\n mIdx = m00.x;\n } else if (rand < w01) {\n mIdx = m01.x;\n } else if (rand < w02) {\n mIdx = m02.x;\n } else if (rand < w10) {\n mIdx = m10.x;\n } else if (rand < w11) {\n mIdx = m11.x;\n } else if (rand < w12) {\n mIdx = m12.x;\n } else if (rand < w20) {\n mIdx = m20.x;\n } else if (rand < w21) {\n mIdx = m21.x;\n } else {\n mIdx = m22.x;\n }\n return int(mIdx);\n}\n\n\nvec4 fetchIns(int i);\n\n\nmat2x3 anisotropy_axes(vec3 normal, vec3 dp1, vec3 dp2, vec2 duv1, vec2 duv2, vec4 inputTangent) {\n float determinant = duv1.x * duv2.y - duv1.y * duv2.x;\n vec3 t = inputTangent.xyz;\n vec3 b = vec3(0.0);\n // Internal W=2 marks an authored XYZ tangent whose sign is derived from UVs.\n float handedness = abs(inputTangent.w) > 1.5 ? 0.0 : inputTangent.w;\n if (abs(determinant) > 1e-12) {\n vec3 dt = (dp1 * duv2.y - dp2 * duv1.y) / determinant;\n vec3 db = (dp2 * duv1.x - dp1 * duv2.x) / determinant;\n if (dot(t, t) < 1e-8) { t = dt; }\n if (handedness == 0.0) { handedness = (dot(cross(normal, dt), db) < 0.0 ? -1.0 : 1.0); }\n }\n t -= normal * dot(normal, t);\n if (dot(t, t) < 1e-8) {\n float signZ = (normal.z >= 0.0 ? 1.0 : -1.0);\n float factor = -1.0 / (signZ + normal.z);\n float xy = normal.x * normal.y * factor;\n t = vec3(1.0 + signZ * normal.x * normal.x * factor, signZ * xy, -signZ * normal.x);\n b = vec3(xy, signZ + normal.y * normal.y * factor, -normal.y);\n }\n else { t = normalize(t); b = normalize(cross(normal, t)); }\n return mat2x3(t, b * (handedness < 0.0 ? -1.0 : 1.0));\n}\n\nvoid fetchAttributes(inout SurfaceInteraction si, Triangle tri, vec3 barycentric, ivec3 index) {\n si.hit = true;\n si.position = barycentric.x * tri.p0 + barycentric.y * tri.p1 + barycentric.z * tri.p2;\n ivec2 i0 = unpackTexel(index.x, vertexColumns);\n ivec2 i1 = unpackTexel(index.y, vertexColumns);\n ivec2 i2 = unpackTexel(index.z, vertexColumns);\n si.vertexColor = vec3(1.0);\n#ifdef USE_VERTEX_COLOR\n si.vertexColor = barycentric.x * texelFetch(colorBuffer, i0, 0).rgb\n + barycentric.y * texelFetch(colorBuffer, i1, 0).rgb\n + barycentric.z * texelFetch(colorBuffer, i2, 0).rgb;\n#endif\n\n vec3 n0 = texelFetch(normalBuffer, i0, 0).xyz;\n vec3 n1 = texelFetch(normalBuffer, i1, 0).xyz;\n vec3 n2 = texelFetch(normalBuffer, i2, 0).xyz;\n vec3 normal = normalize(barycentric.x * n0 + barycentric.y * n1 + barycentric.z * n2);\n si.vertexNormal = normal;\n\n // Approximate the smooth limit surface at this triangle hit. Direct-light\n // rays use this geometric offset only near the shadow terminator, avoiding\n // false self-shadowing by adjacent facets without moving ordinary hits.\n // Architecture follows Cycles' shadow_ray_smooth_surface_offset.\n vec3 geometricNormal = normalize(cross(tri.p1 - tri.p0, tri.p2 - tri.p0));\n vec3 smoothNormal = barycentric.x * n0 + barycentric.y * n1 + barycentric.z * n2;\n float a = dot(n2 - n0, tri.p0 - tri.p2);\n float b = dot(n2 - n1, tri.p1 - tri.p2);\n float c = dot(n1 - n0, tri.p1 - tri.p0);\n float h = a * barycentric.x * (barycentric.x - 1.0)\n + (a + b + c) * barycentric.x * barycentric.y\n + b * barycentric.y * (barycentric.y - 1.0);\n if (dot(smoothNormal, geometricNormal) > 0.0) {\n float h0 = max(max(dot(tri.p1 - tri.p0, n0), dot(tri.p2 - tri.p0, n0)), 0.0);\n float h1 = max(max(dot(tri.p0 - tri.p1, n1), dot(tri.p2 - tri.p1, n1)), 0.0);\n float h2 = max(max(dot(tri.p0 - tri.p2, n2), dot(tri.p1 - tri.p2, n2)), 0.0);\n h0 = max(dot(tri.p0 - si.position, n0) + h0, 0.0);\n h1 = max(dot(tri.p1 - si.position, n1) + h1, 0.0);\n h2 = max(dot(tri.p2 - si.position, n2) + h2, 0.0);\n h = max(min(min(h0, h1), h2), h * 0.5);\n }\n else {\n float h0 = max(max(dot(tri.p0 - tri.p1, n0), dot(tri.p0 - tri.p2, n0)), 0.0);\n float h1 = max(max(dot(tri.p1 - tri.p0, n1), dot(tri.p1 - tri.p2, n1)), 0.0);\n float h2 = max(max(dot(tri.p2 - tri.p0, n2), dot(tri.p2 - tri.p1, n2)), 0.0);\n h0 = max(dot(si.position - tri.p0, n0) + h0, 0.0);\n h1 = max(dot(si.position - tri.p1, n1) + h1, 0.0);\n h2 = max(dot(si.position - tri.p2, n2) + h2, 0.0);\n h = min(-min(min(h0, h1), h2), h * 0.5);\n }\n si.shadowOffset = smoothNormal * h;\n\n // TODO currently isampler doesn't work\n ivec4 m0 = ivec4(texelFetch(materialIndexBuffer, i0, 0));\n ivec4 m1 = ivec4(texelFetch(materialIndexBuffer, i1, 0));\n ivec4 m2 = ivec4(texelFetch(materialIndexBuffer, i2, 0));\n \n if (m0.x > 0 || m1.x > 0 || m2.x > 0) {\n si.materialIndex = randomPickMaterial(m0, m1, m2, barycentric);\n }\n \n vec2 uv0 = texelFetch(uvBuffer, i0, 0).xy;\n vec2 uv1 = texelFetch(uvBuffer, i1, 0).xy;\n vec2 uv2 = texelFetch(uvBuffer, i2, 0).xy;\n #if defined(NUM_DIFFUSE_MAPS) || defined(NUM_NORMAL_MAPS) || defined(NUM_METALLIC_ROUGHNESS_MAPS) || defined(NUM_ROUGHNESS_MAPS) || defined(NUM_METALNESS_MAPS) || defined(NUM_EMISSIVE_MAPS) || defined(NUM_THIN_FILM_MAPS) || defined(NUM_ANISOTROPY_MAPS) || defined(NUM_COAT_NORMAL_MAPS)\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec2 secondaryUv0 = texelFetch(uv1Buffer, i0, 0).xy;\n vec2 secondaryUv1 = texelFetch(uv1Buffer, i1, 0).xy;\n vec2 secondaryUv2 = texelFetch(uv1Buffer, i2, 0).xy;\n vec2 secondaryUv = barycentric.x * secondaryUv0\n + barycentric.y * secondaryUv1\n + barycentric.z * secondaryUv2;\n\n vec4 uvInfo = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, si.position, normal, uvInfo.zw);\n secondaryUv = uv;\n } else {\n uv *= uvInfo.zw;\n secondaryUv *= uvInfo.zw;\n }\n #else\n vec2 uv = vec2(0.0);\n vec2 secondaryUv = vec2(0.0);\n #endif\n\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normal;\n#ifdef NUM_COAT_NORMAL_MAPS\n float coatNormalIndex = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_LAYER_MAPS).z;\n#endif\n#endif\n vec4 directionMaterial = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_DIRECTION_NORMAL);\n float coatRotation = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_FILM_TEXTURE).x;\n if (directionMaterial.x >= 0.0 || directionMaterial.y != 0.0 || coatRotation != 0.0\n#ifdef USE_COAT_NORMAL_FRAMES\n || fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_COAT).w > 0.0\n#endif\n ) {\n vec3 dp1 = tri.p0 - tri.p2;\n vec3 dp2 = tri.p1 - tri.p2;\n vec4 inputTangent = vec4(0.0);\n#ifdef USE_TANGENT\n inputTangent = barycentric.x * texelFetch(tangentBuffer, i0, 0)\n + barycentric.y * texelFetch(tangentBuffer, i1, 0)\n + barycentric.z * texelFetch(tangentBuffer, i2, 0);\n#endif\n mat2x3 geometryAxes = anisotropy_axes(normal, dp1, dp2, uv0-uv2, uv1-uv2, inputTangent);\n si.geometryTangent = geometryAxes[0];\n si.geometryBitangent = geometryAxes[1];\n mat2x3 directionAxes = geometryAxes;\n#ifdef NUM_ANISOTROPY_MAPS\n if (directionMaterial.x >= 0.0 && mapUvChannel[int(directionMaterial.x)] > 0.5) {\n vec2 a = texelFetch(uv1Buffer, i0, 0).xy;\n vec2 b = texelFetch(uv1Buffer, i1, 0).xy;\n vec2 c = texelFetch(uv1Buffer, i2, 0).xy;\n directionAxes = anisotropy_axes(normal, dp1, dp2, a-c, b-c, (inputTangent.w == 0.0 ? vec4(0.0) : inputTangent));\n }\n#endif\n si.directionTangent = directionAxes[0];\n si.directionBitangent = directionAxes[1];\n#if defined(USE_COAT_NORMAL_FRAMES) && defined(NUM_COAT_NORMAL_MAPS)\n if (coatNormalIndex >= 0.0) {\n int coatIndex = int(coatNormalIndex);\n mat2x3 coatAxes = geometryAxes;\n if (mapUvChannel[coatIndex] > 0.5) {\n vec2 a = texelFetch(uv1Buffer, i0, 0).xy;\n vec2 b = texelFetch(uv1Buffer, i1, 0).xy;\n vec2 c = texelFetch(uv1Buffer, i2, 0).xy;\n coatAxes = anisotropy_axes(normal, dp1, dp2, a-c, b-c,\n inputTangent.w == 0.0 ? vec4(0.0) : inputTangent);\n }\n vec3 decoded = sampleMap(coatIndex, getMapUvSet(coatIndex, uv, secondaryUv)).rgb * 2.0 - 1.0;\n vec3 mapped = coatAxes[0] * decoded.x * directionMaterial.z\n + coatAxes[1] * decoded.y * directionMaterial.w + normal * decoded.z;\n if (dot(mapped, mapped) > 1e-12) { si.coatNormal = normalize(mapped); }\n }\n#endif\n }\n\n si.uv = uv;\n si.uv1 = secondaryUv;\n\n #ifdef USE_TANGENT\n vec3 t0 = texelFetch(tangentBuffer, i0, 0).xyz;\n vec3 t1 = texelFetch(tangentBuffer, i1, 0).xyz;\n vec3 t2 = texelFetch(tangentBuffer, i2, 0).xyz;\n si.tangent = normalize(barycentric.x * t0 + barycentric.y * t1 + barycentric.z * t2);\n #endif\n #if defined(NUM_NORMAL_MAPS)\n vec3 dp1 = tri.p0 - tri.p2;\n vec3 dp2 = tri.p1 - tri.p2;\n vec2 duv1 = uv0 - uv2;\n vec2 duv2 = uv1 - uv2;\n si.normal = getMatNormal(\n si.materialIndex, uv, normal, dp1, dp2, duv1, duv2\n );\n #else\n si.normal = normal;\n #endif\n}\n\nstruct TriangleIntersect {\n float t;\n vec3 barycentric;\n};\n\nvec4 fetchBVH(int i) {\n return fetchData(bvhBuffer, i, bvhColumns);\n}\n\nvec4 fetchIns(int i) {\n return fetchData(instancesBuffer, i, instancesColumns);\n}\n\n// GLSL ES 3.00 has no bitCount intrinsic. Count the CWBVH mask bits using\n// integer operations supported by WebGL 2.\nuint countBvhBits(uint value) {\n value -= (value >> 1u) & 0x55555555u;\n value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u);\n value = (value + (value >> 4u)) & 0x0f0f0f0fu;\n return (value * 0x01010101u) >> 24u;\n}\n\nvec4 unpackBvh4Bounds(uint packedBounds) {\n return vec4(\n float(packedBounds & 0xffu),\n float((packedBounds >> 8u) & 0xffu),\n float((packedBounds >> 16u) & 0xffu),\n float(packedBounds >> 24u)\n ) / 255.0;\n}\n\n// Triangle-ray intersection\n// Faster than the classic Möller–Trumbore intersection algorithm\n// http://www.pbr-book.org/3ed-2018/Shapes/Triangle_Meshes.html#TriangleIntersection\nTriangleIntersect intersectTriangle(vec3 o, vec3 d, Triangle tri, int maxDim, vec3 shear, float tMax) {\n TriangleIntersect ti;\n\n // translate vertices based on ray origin\n vec3 p0t = tri.p0 - o;\n vec3 p1t = tri.p1 - o;\n vec3 p2t = tri.p2 - o;\n\n // permute components of triangle vertices\n if (maxDim == 0) {\n p0t = p0t.yzx;\n p1t = p1t.yzx;\n p2t = p2t.yzx;\n } else if (maxDim == 1) {\n p0t = p0t.zxy;\n p1t = p1t.zxy;\n p2t = p2t.zxy;\n }\n\n // apply shear transformation to translated vertex positions\n p0t.xy += shear.xy * p0t.z;\n p1t.xy += shear.xy * p1t.z;\n p2t.xy += shear.xy * p2t.z;\n\n // compute edge function coefficients\n vec3 e = vec3(\n p1t.x * p2t.y - p1t.y * p2t.x,\n p2t.x * p0t.y - p2t.y * p0t.x,\n p0t.x * p1t.y - p0t.y * p1t.x\n );\n\n#ifdef DEPTH_QUERY_MODE\n vec3 edgeScale = abs(vec3(p1t.x * p2t.y, p2t.x * p0t.y, p0t.x * p1t.y))\n + abs(vec3(p1t.y * p2t.x, p2t.y * p0t.x, p0t.y * p1t.x));\n e = mix(e, vec3(0.0), lessThanEqual(abs(e), edgeScale * 1e-6));\n#endif\n\n // check if intersection is inside triangle\n if (any(lessThan(e, vec3(0))) && any(greaterThan(e, vec3(0)))) {\n return ti;\n }\n\n float det = e.x + e.y + e.z;\n#ifdef DEPTH_QUERY_MODE\n if (det == 0.0) return ti;\n#endif\n\n p0t.z *= shear.z;\n p1t.z *= shear.z;\n p2t.z *= shear.z;\n float tScaled = (e.x * p0t.z + e.y * p1t.z + e.z * p2t.z);\n\n // check if closer intersection already exists\n if (abs(tScaled) > abs(tMax * det)) {\n return ti;\n }\n\n float invDet = 1. / det;\n ti.t = tScaled * invDet;\n ti.barycentric = e * invDet;\n\n return ti;\n}\n\nstruct Box {\n vec3 min;\n vec3 max;\n};\n\n// Conservative slabs only for the unjittered depth query shader.\nvec3 traversalInverse(vec3 d) {\n#ifdef DEPTH_QUERY_MODE\n vec3 denominator = mix(d, mix(vec3(1e-20), vec3(-1e-20), lessThan(d, vec3(0.0))), lessThan(abs(d), vec3(1e-20)));\n return 1.0 / denominator;\n#else\n return 1.0 / d;\n#endif\n}\n\nvec3 depthSlabPadding(vec3 invD, vec3 o) {\n#ifdef DEPTH_QUERY_MODE\n return abs(invD) * max(vec3(1.0), abs(o)) * 1e-6;\n#else\n return vec3(0.0);\n#endif\n}\n\n// Branchless ray/box intersection\n// https://tavianator.com/fast-branchless-raybounding-box-intersections/\nfloat intersectBox(vec3 o, vec3 d, vec3 bmin, vec3 bmax, float tMax) {\n#ifdef DEPTH_QUERY_MODE\n vec3 invD = traversalInverse(d);\n vec3 tBot = (bmin - o) * invD;\n vec3 tTop = (bmax - o) * invD;\n vec3 padding = depthSlabPadding(invD, o);\n#else\n vec3 tBot = (bmin - o) / d;\n vec3 tTop = (bmax - o) / d;\n vec3 padding = vec3(0.0);\n#endif\n vec3 tNear = min(tBot, tTop) - padding;\n vec3 tFar = max(tBot, tTop) + padding;\n float t0 = max(tNear.x, max(tNear.y, tNear.z));\n float t1 = min(tFar.x, min(tFar.y, tFar.z));\n\n return (t0 > t1 || t0 > tMax) ? -1.0 : (t0 > 0.0 ? t0 : t1);\n}\n\nint maxDimension(vec3 v) {\n return v.x > v.y ? (v.x > v.z ? 0 : 2) : (v.y > v.z ? 1 : 2);\n}\n\nvec3 getShear(vec3 d, int maxDim) {\n // Permute space so that the z dimension is the one where the absolute value of the ray's direction is largest.\n // Then create a shear transformation that aligns ray direction with the +z axis\n if (maxDim == 0) {\n return vec3(-d.y, -d.z, 1.0) / d.x;\n } else if (maxDim == 1) {\n return vec3(-d.z, -d.x, 1.0) / d.y;\n } else {\n return vec3(-d.x, -d.y, 1.0) / d.z;\n }\n}\n\n// Traverse BVH, find closest triangle intersection, and return surface information\nvoid intersectScene(in Ray ray, inout SurfaceInteraction si, bool doubleSided) {\n si.hit = false;\n\n if (isEmptyScene) {\n return;\n }\n\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n int hitInsIdx;\n\n${getBVHTraverseCode(glsl`\n si.triangleIndex = triangleIndex;\n hitTri = tri;\n hitFaceNormal = faceNormal;\n hitBarycentric = hit.barycentric;\n hitIndex = index;\n isHit = true;\n hitInsIdx = insIdx;\n`)}\n\n if (isHit) {\n si.instanceIndex = hitInsIdx;\n si.materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n // fetchAttributes before transform to world space.\n fetchAttributes(si, hitTri, hitBarycentric, hitIndex);\n mat4 l2w = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 5),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 6),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 7),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 8)\n );\n mat4 w2l = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n mat3 normalTransform = transpose(mat3(w2l));\n si.faceNormal = normalize(normalTransform * hitFaceNormal);\n si.vertexNormal = normalize(normalTransform * si.vertexNormal);\n si.normal = normalize(normalTransform * si.normal);\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normalize(normalTransform * si.coatNormal);\n#endif\n#ifdef USE_TANGENT\n if (dot(si.tangent, si.tangent) > 0.0) {\n si.tangent = normalize(mat3(l2w) * si.tangent);\n }\n#endif\n si.shadowOffset = (l2w * vec4(si.shadowOffset, 0.0)).xyz;\n si.directionTangent = mat3(l2w) * si.directionTangent;\n si.directionBitangent = mat3(l2w) * si.directionBitangent;\n si.geometryTangent = mat3(l2w) * si.geometryTangent;\n si.geometryBitangent = mat3(l2w) * si.geometryBitangent;\n si.position = (l2w * vec4(si.position, 1.0)).xyz;\n }\n}\n\n// Local intersection helper for shader bevel.\nvoid intersectSceneBevel(in Ray ray, inout SurfaceInteraction si, int instanceIndex, float maxDistance) {\n si.hit = false;\n\n if (isEmptyScene) {\n return;\n }\n\n bool doubleSided = true;\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n int hitInsIdx;\n\n${getBVHTraverseCode(\n glsl`\n si.triangleIndex = triangleIndex;\n hitTri = tri;\n hitFaceNormal = faceNormal;\n hitBarycentric = hit.barycentric;\n hitIndex = index;\n isHit = true;\n hitInsIdx = insIdx;\n`,\n glsl`\n if (insIdx != instanceIndex) {\n continue;\n }\n`,\n 'maxDistance'\n)}\n\n if (isHit) {\n si.instanceIndex = hitInsIdx;\n si.materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n fetchAttributes(si, hitTri, hitBarycentric, hitIndex);\n mat4 l2w = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 5),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 6),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 7),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 8)\n );\n mat4 w2l = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n mat3 normalTransform = transpose(mat3(w2l));\n si.faceNormal = normalize(normalTransform * hitFaceNormal);\n si.vertexNormal = normalize(normalTransform * si.vertexNormal);\n si.normal = normalize(normalTransform * si.normal);\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normalize(normalTransform * si.coatNormal);\n#endif\n#ifdef USE_TANGENT\n if (dot(si.tangent, si.tangent) > 0.0) {\n si.tangent = normalize(mat3(l2w) * si.tangent);\n }\n#endif\n si.shadowOffset = (l2w * vec4(si.shadowOffset, 0.0)).xyz;\n si.directionTangent = mat3(l2w) * si.directionTangent;\n si.directionBitangent = mat3(l2w) * si.directionBitangent;\n si.geometryTangent = mat3(l2w) * si.geometryTangent;\n si.geometryBitangent = mat3(l2w) * si.geometryBitangent;\n si.position = (l2w * vec4(si.position, 1.0)).xyz;\n }\n}\n\nbool intersectSceneShadow(in Ray ray, float lightDistance, int currTriangleIndex) {\n\n if (isEmptyScene) {\n return false;\n }\n\n bool doubleSided = true;\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n\n${getBVHTraverseCode(\n glsl`\n // Traversal is clipped to lightDistance. Affine instance transforms keep\n // the ray parameter unchanged because local directions are not normalized.\n bool isOccluded = true;\n vec3 barycentric = hit.barycentric;\n vec3 position = barycentric.x * tri.p0 + barycentric.y * tri.p1 + barycentric.z * tri.p2;\n\n if (isOccluded) {\n#ifdef HAS_ALPHA\n int materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n ivec2 i0 = unpackTexel(index.x, vertexColumns);\n ivec2 i1 = unpackTexel(index.y, vertexColumns);\n ivec2 i2 = unpackTexel(index.z, vertexColumns);\n ivec4 m0 = ivec4(texelFetch(materialIndexBuffer, i0, 0));\n ivec4 m1 = ivec4(texelFetch(materialIndexBuffer, i1, 0));\n ivec4 m2 = ivec4(texelFetch(materialIndexBuffer, i2, 0));\n \n if (m0.x > 0 || m1.x > 0 || m2.x > 0) {\n materialIndex = randomPickMaterial(m0, m1, m2, barycentric);\n }\n \n int ii = materialIndex * MAT_DATA_SIZE;\n int mapAlphaUsage = int(fetchMatData(ii + MAT_ROW_MISC).a);\n float alpha = fetchMatData(ii + MAT_ROW_ALPHA_FILM).r;\n #ifdef NUM_DIFFUSE_MAPS\n if (mapAlphaUsage == ${mapAlphaUsageConstants.alpha + ''}) {\n int diffuseMapIndex = int(fetchMatData(ii + MAT_ROW_METALLIC_MAPS).z);\n if (diffuseMapIndex >= 0) {\n vec2 uv0 = texelFetch(uvBuffer, i0, 0).xy;\n vec2 uv1 = texelFetch(uvBuffer, i1, 0).xy;\n vec2 uv2 = texelFetch(uvBuffer, i2, 0).xy;\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec4 uvInfo = fetchMatData(ii + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, position, hitFaceNormal, uvInfo.zw);\n } else {\n uv *= uvInfo.zw;\n }\n \n alpha *= sampleMap(diffuseMapIndex, uv).a;\n }\n }\n #endif\n #ifdef NUM_ALPHA_MAPS\n int alphaMapIndex = int(fetchMatData(ii + MAT_ROW_STANDALONE_MAPS).z);\n if (alphaMapIndex >= 0) {\n vec2 uv0 = texelFetch(uvBuffer, i0, 0).xy;\n vec2 uv1 = texelFetch(uvBuffer, i1, 0).xy;\n vec2 uv2 = texelFetch(uvBuffer, i2, 0).xy;\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec4 uvInfo = fetchMatData(ii + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, position, hitFaceNormal, uvInfo.zw);\n } else {\n uv *= uvInfo.zw;\n }\n alpha *= sampleMap(alphaMapIndex, uv).g;\n }\n #endif\n float alphaCutoff = fetchMatData(ii + MAT_ROW_STANDALONE_MAPS).a;\n alpha = resolveMaterialAlpha(\n alpha, int(fetchMatData(ii + MAT_ROW_ALPHA).w), alphaCutoff\n );\n if (hashedSample(0u) > alpha) {\n // Continue after a transparent hit without traversing beyond the light.\n tMax = min(max(lightDistance, 0.0), RAY_MAX_DISTANCE);\n isOccluded = false;\n }\n#endif\n }\n if (isOccluded) {\n return true;\n }\n`,\n glsl`\n if (triangleIndex == currTriangleIndex) {\n continue;\n }\n`,\n 'min(max(lightDistance, 0.0), RAY_MAX_DISTANCE)'\n)}\n return false;\n}\n`\n});\n"]}
|
|
1
|
+
{"version":3,"file":"intersect.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/intersect.glsl.ts"],"names":[],"mappings":"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","sourcesContent":["import { mapAlphaUsageConstants } from '../../materialConstants.js';\n// Portions adapted from ray-tracing-renderer@0.10.15\n// (https://github.com/hoverinc/ray-tracing-renderer).\n// Copyright (c) 2019 HOVER, MIT license; see LICENSES/RayTracingRenderer-MIT.txt.\n\nimport { INSTANCE_VEC4_STRIDE } from '../../bvhAccel.js';\nimport { createShaderMixin, glsl, Shader } from '../../shader.js';\n\nfunction getBVHTraverseCode(\n handleHitCode: string,\n skipTriangleCode = '',\n initialTMax = 'RAY_MAX_DISTANCE'\n) {\n const intersectTriangles = glsl`\n ivec3 vertexOffset = ivec3(floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).y));\n for (int k = 0; k < primitiveCount; k++) {\n int triangleIndex = primitiveOffset + k;\n ${skipTriangleCode}\n vec4 r3 = fetchBVH(triangleIndex);\n ivec3 index = floatBitsToInt(r3.xyz) + vertexOffset;\n Triangle tri = Triangle(\n fetchData(positionBuffer, index.x, vertexColumns).xyz,\n fetchData(positionBuffer, index.y, vertexColumns).xyz,\n fetchData(positionBuffer, index.z, vertexColumns).xyz\n );\n TriangleIntersect hit = intersectTriangle(o, d, tri, maxDim, shear, tMax);\n\n if (hit.t > 0.0) {\n tMax = hit.t;\n vec3 e1 = tri.p1 - tri.p0;\n vec3 e2 = tri.p2 - tri.p0;\n vec3 faceNormal = normalize(cross(e1, e2));\n int sideMaterialIndex = int(unpackMaterialIndex(\n floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).z)\n ).x);\n bool materialDoubleSided = fetchMatData(\n sideMaterialIndex * MAT_DATA_SIZE + MAT_ROW_ALPHA\n ).z > 0.5;\n if (!doubleSided && !materialDoubleSided && dot(faceNormal, d) > 0.0) {\n continue;\n }\n\n ${handleHitCode}\n }\n }\n`;\n return glsl`\n ivec2 stack[STACK_SIZE];\n int top = -1;\n int prevInsIdx = -1;\n float tMax = ${initialTMax};\n\n vec3 o = ray.o;\n vec3 d = ray.d;\n\n bool isHit = false;\n vec3 hitFaceNormal;\n vec3 hitBarycentric;\n ivec3 hitIndex;\n\n Triangle hitTri;\n\n // TODO not sure why. but do root node check here will cause rendering wrong in windows.\n top = 0;\n stack[0] = ivec2(0, -1);\n\n int iter = 0;\n while(top >= 0 && iter < 5000) {\n iter++;\n ivec2 node = stack[top--];\n\n int insIdx = node.y;\n\n if (insIdx != prevInsIdx) {\n if (insIdx < 0) {\n o = ray.o;\n d = ray.d;\n }\n else {\n mat4 w2l = mat4(\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n o = (w2l * vec4(ray.o, 1.0)).xyz;\n d = (w2l * vec4(ray.d, 0.0)).xyz;\n }\n maxDim = maxDimension(abs(d));\n shear = getShear(d, maxDim);\n prevInsIdx = insIdx;\n }\n\n int bufferOff = insIdx < 0 ? 0 : blasOffset;\n uint encodedBlasOffset = insIdx < 0 ? 0u : floatBitsToUint(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).x);\n int blasLayout = int(encodedBlasOffset >> 30u);\n int blasInsOffset = int(encodedBlasOffset & 0x3fffffffu);\n int primitiveCount = 0;\n int primitiveOffset = 0;\n\n if (blasLayout == 3) {\n uint nodeInfo = uint(node.x);\n if ((nodeInfo & 0x80000000u) != 0u) {\n primitiveCount = int((nodeInfo >> 23u) & 0xffu);\n primitiveOffset = bufferOff + blasInsOffset + int(nodeInfo & 0x007fffffu);\n }\n else {\n int i = node.x + bufferOff;\n vec4 compressed0 = fetchBVH(i);\n vec4 compressed1 = fetchBVH(i + 1);\n vec4 compressed2 = fetchBVH(i + 2);\n vec4 compressed3 = fetchBVH(i + 3);\n vec4 compressed4 = fetchBVH(i + 4);\n uint header = floatBitsToUint(compressed0.w);\n int exponentX = int(header << 24u) >> 24;\n int exponentY = int((header >> 8u) << 24u) >> 24;\n int exponentZ = int((header >> 16u) << 24u) >> 24;\n vec3 quantizationScale = vec3(\n uintBitsToFloat(uint(exponentX + 127) << 23u),\n uintBitsToFloat(uint(exponentY + 127) << 23u),\n uintBitsToFloat(uint(exponentZ + 127) << 23u)\n );\n uint childBase = floatBitsToUint(compressed1.x);\n uint triangleBase = floatBitsToUint(compressed1.y);\n uint internalMask = header >> 24u;\n uint octant = (d.x < 0.0 ? 4u : 0u) |\n (d.y < 0.0 ? 2u : 0u) |\n (d.z < 0.0 ? 1u : 0u);\n uint quantizedWords[12] = uint[12](\n floatBitsToUint(compressed2.x), floatBitsToUint(compressed2.y),\n floatBitsToUint(compressed2.z), floatBitsToUint(compressed2.w),\n floatBitsToUint(compressed3.x), floatBitsToUint(compressed3.y),\n floatBitsToUint(compressed3.z), floatBitsToUint(compressed3.w),\n floatBitsToUint(compressed4.x), floatBitsToUint(compressed4.y),\n floatBitsToUint(compressed4.z), floatBitsToUint(compressed4.w)\n );\n\n for (int order = 7; order >= 0; order--) {\n uint slot = uint(order) ^ octant;\n uint metaWord = slot >= 4u\n ? floatBitsToUint(compressed1.w)\n : floatBitsToUint(compressed1.z);\n uint meta = (metaWord >> ((slot & 3u) * 8u)) & 0xffu;\n if (meta == 0u) continue;\n uint byteShift = (slot & 3u) * 8u;\n uint wordOffset = slot >> 2u;\n vec3 quantizedMin = vec3(\n float((quantizedWords[wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[2u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[4u + wordOffset] >> byteShift) & 0xffu)\n );\n vec3 quantizedMax = vec3(\n float((quantizedWords[6u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[8u + wordOffset] >> byteShift) & 0xffu),\n float((quantizedWords[10u + wordOffset] >> byteShift) & 0xffu)\n );\n vec3 childMin = compressed0.xyz + quantizedMin * quantizationScale;\n vec3 childMax = compressed0.xyz + quantizedMax * quantizationScale;\n if (intersectBox(o, d, childMin, childMax, tMax) <= 0.0) continue;\n uint localOffset = meta & 0x1fu;\n if (localOffset >= 24u) {\n uint precedingMask = internalMask & ((1u << slot) - 1u);\n uint internalIndex = childBase + countBvhBits(precedingMask);\n stack[++top] = ivec2(\n blasInsOffset + int(internalIndex * 5u), insIdx\n );\n }\n else {\n uint triangleCount = countBvhBits(meta >> 5u);\n uint primitiveAddress = triangleBase + localOffset;\n uint leafInfo = 0x80000000u |\n (triangleCount << 23u) |\n (primitiveAddress & 0x007fffffu);\n stack[++top] = ivec2(int(leafInfo), insIdx);\n }\n }\n }\n }\n else if (blasLayout == 2) {\n int i = node.x + bufferOff;\n vec4 gpu0 = fetchBVH(i);\n vec4 gpu1 = fetchBVH(i + 1);\n vec4 gpu2 = fetchBVH(i + 2);\n vec4 gpu3 = fetchBVH(i + 3);\n primitiveCount = int(floatBitsToUint(gpu2.w));\n if (primitiveCount > 0) {\n primitiveOffset = bufferOff + blasInsOffset + int(floatBitsToUint(gpu3.w));\n }\n else {\n int left = blasInsOffset + int(floatBitsToUint(gpu0.w) * 4u);\n int right = blasInsOffset + int(floatBitsToUint(gpu1.w) * 4u);\n float d0 = intersectBox(o, d, gpu0.xyz, gpu1.xyz, tMax);\n float d1 = intersectBox(o, d, gpu2.xyz, gpu3.xyz, tMax);\n if (d0 > d1) {\n if (d0 > 0.0) stack[++top] = ivec2(left, insIdx);\n if (d1 > 0.0) stack[++top] = ivec2(right, insIdx);\n }\n else {\n if (d1 > 0.0) stack[++top] = ivec2(right, insIdx);\n if (d0 > 0.0) stack[++top] = ivec2(left, insIdx);\n }\n }\n }\n else if (blasLayout == 1) {\n uint nodeInfo = uint(node.x);\n if ((nodeInfo & 0x80000000u) != 0u) {\n primitiveCount = int((nodeInfo >> 23u) & 0xffu);\n primitiveOffset = bufferOff + blasInsOffset + int(nodeInfo & 0x007fffffu);\n }\n else {\n int i = node.x + bufferOff;\n vec4 wide0 = fetchBVH(i);\n vec4 wide1 = fetchBVH(i + 1);\n vec4 wide2 = fetchBVH(i + 2);\n vec4 wide3 = fetchBVH(i + 3);\n vec3 nodeMin = wide0.xyz;\n vec3 nodeExtent = vec3(wide0.w, wide1.x, wide1.y);\n uint childInfos[4] = uint[4](\n floatBitsToUint(wide1.z), floatBitsToUint(wide1.w),\n floatBitsToUint(wide2.x), floatBitsToUint(wide2.y)\n );\n vec4 childMinX = unpackBvh4Bounds(floatBitsToUint(wide2.z));\n vec4 childMinY = unpackBvh4Bounds(floatBitsToUint(wide2.w));\n vec4 childMinZ = unpackBvh4Bounds(floatBitsToUint(wide3.x));\n vec4 childMaxX = unpackBvh4Bounds(floatBitsToUint(wide3.y));\n vec4 childMaxY = unpackBvh4Bounds(floatBitsToUint(wide3.z));\n vec4 childMaxZ = unpackBvh4Bounds(floatBitsToUint(wide3.w));\n vec3 invD = traversalInverse(d);\n vec3 padding = depthSlabPadding(invD, o);\n vec4 tx0 = (nodeMin.x + childMinX * nodeExtent.x - o.x) * invD.x;\n vec4 tx1 = (nodeMin.x + childMaxX * nodeExtent.x - o.x) * invD.x;\n vec4 ty0 = (nodeMin.y + childMinY * nodeExtent.y - o.y) * invD.y;\n vec4 ty1 = (nodeMin.y + childMaxY * nodeExtent.y - o.y) * invD.y;\n vec4 tz0 = (nodeMin.z + childMinZ * nodeExtent.z - o.z) * invD.z;\n vec4 tz1 = (nodeMin.z + childMaxZ * nodeExtent.z - o.z) * invD.z;\n vec4 tNear = max(max((min(tx0, tx1) - vec4(padding.x)), (min(ty0, ty1) - vec4(padding.y))), (min(tz0, tz1) - vec4(padding.z)));\n vec4 tFar = min(min((max(tx0, tx1) + vec4(padding.x)), (max(ty0, ty1) + vec4(padding.y))), (max(tz0, tz1) + vec4(padding.z)));\n vec4 distance = mix(tFar, tNear, greaterThan(tNear, vec4(0.0)));\n distance = mix(distance, vec4(-1.0), greaterThan(tNear, min(tFar, vec4(tMax))));\n float childDistances[4] = float[4](distance.x, distance.y, distance.z, distance.w);\n\n // Push far-to-near so that the closest child is popped first.\n for (int order = 0; order < 4; order++) {\n float farthestDistance = -1.0;\n int farthestChild = -1;\n for (int child = 0; child < 4; child++) {\n if (childInfos[child] != 0u && childDistances[child] > farthestDistance) {\n farthestDistance = childDistances[child];\n farthestChild = child;\n }\n }\n if (farthestChild >= 0 && farthestDistance > 0.0) {\n uint childInfo = childInfos[farthestChild];\n int childAddress = int(childInfo);\n if ((childInfo & 0x80000000u) == 0u) {\n childAddress += blasInsOffset;\n }\n stack[++top] = ivec2(childAddress, insIdx);\n childDistances[farthestChild] = -1.0;\n }\n }\n }\n }\n else {\n int i = node.x + bufferOff;\n vec4 r1 = fetchBVH(i);\n int pointerToRightOrNumPrims = floatBitsToInt(r1.w);\n\n if (pointerToRightOrNumPrims >= 0) {\n int left = node.x + 2;\n int right = pointerToRightOrNumPrims + blasInsOffset;\n\n float d0 = intersectBox(o, d, fetchBVH(left + bufferOff).xyz, fetchBVH(left + 1 + bufferOff).xyz, tMax);\n float d1 = intersectBox(o, d, fetchBVH(right + bufferOff).xyz, fetchBVH(right + 1 + bufferOff).xyz, tMax);\n if (d0 > d1) {\n if (d0 > 0.0) {\n stack[++top] = ivec2(left, insIdx);\n }\n if (d1 > 0.0) {\n stack[++top] = ivec2(right, insIdx);\n }\n }\n else {\n if (d1 > 0.0) {\n stack[++top] = ivec2(right, insIdx);\n }\n if (d0 > 0.0) {\n stack[++top] = ivec2(left, insIdx);\n }\n }\n }\n else {\n if (insIdx < 0) {\n for (int k = 0; k < -pointerToRightOrNumPrims; k++) {\n vec4 r3 = fetchBVH(i + 2 + k);\n int box = floatBitsToInt(r3.w);\n if (intersectBox(ray.o, ray.d, fetchBVH(box).xyz, fetchBVH(box + 1).xyz, tMax) > 0.0) {\n stack[++top] = ivec2(floatBitsToInt(r3.y), floatBitsToInt(r3.x));\n }\n }\n }\n else {\n primitiveCount = -pointerToRightOrNumPrims;\n primitiveOffset = i + 2;\n }\n }\n }\n if (primitiveCount > 0) {\n ${intersectTriangles}\n }\n }\n`;\n}\n\nexport default createShaderMixin({\n defines: {\n VERTEX_ATTRIBUTE_STRIDE: 2\n },\n uniforms: {\n positionBuffer: Shader.uniform('sampler2D'),\n // Interleaved shading attributes; layout in webglVertexAttributes.ts.\n vertexAttributes: Shader.uniform('sampler2D'),\n\n // TLAS, BLASes and then the instance records.\n bvhBuffer: Shader.uniform('sampler2D'),\n\n bvhColumns: Shader.uniform('int', 1),\n vertexColumns: Shader.uniform('int', 1),\n vertexAttributeColumns: Shader.uniform('int', 1),\n\n instancesOffset: Shader.uniform('int', 0),\n\n blasOffset: Shader.uniform('int'),\n\n isEmptyScene: Shader.uniform('bool')\n },\n main: glsl`\n\nstruct Triangle {\n vec3 p0;\n vec3 p1;\n vec3 p2;\n};\n#ifdef NUM_LIGHTS\nfloat intersectSphere(float rad, vec3 pos, Ray r) {\n vec3 op = pos - r.o;\n float eps = 0.001;\n float b = dot(op, r.d);\n float det = b * b - dot(op, op) + rad * rad;\n if (det < 0.0)\n return INF;\n\n det = sqrt(det);\n float t1 = b - det;\n if (t1 > eps)\n return t1;\n\n float t2 = b + det;\n if (t2 > eps)\n return t2;\n\n return INF;\n}\n\nfloat intersectRect(vec3 pos, vec3 u, vec3 v, vec3 n, Ray r) {\n float dt = dot(r.d, n);\n float t = (dot(n, pos) - dot(n, r.o)) / dt;\n\n if (t > EPS) {\n vec3 p = r.o + r.d * t;\n vec3 vi = p - pos;\n float a1 = dot(u / dot(u, u), vi);\n if (a1 >= 0.0 && a1 <= 1.0) {\n float a2 = dot(v / dot(v, v), vi);\n if (a2 >= 0.0 && a2 <= 1.0) {\n return t;\n }\n }\n }\n\n return INF;\n}\n\nfloat sphereSolidAnglePdf(vec3 origin, vec3 center, float radius) {\n float centerDistance = distance(origin, center);\n if (centerDistance <= radius) return INV4PI;\n float sinThetaMaxSquared = min(1.0, radius * radius / (centerDistance * centerDistance));\n float cosThetaMax = sqrt(max(0.0, 1.0 - sinThetaMaxSquared));\n // Match the cancellation-free solid angle used by direct light sampling.\n float oneMinusCosThetaMax = sinThetaMaxSquared / (1.0 + cosThetaMax);\n return 1.0 / max(TWOPI * oneMinusCosThetaMax, 1e-8);\n}\n\nfloat intersectLight(Ray r, Light light, out LightSampleRec lightSample) {\n // Directional lights are delta sources without finite geometry. Start at\n // INF so they cannot accidentally terminate a BSDF continuation as a\n // geometric light hit; rect and sphere branches overwrite this value.\n float d = INF;\n vec3 u = light.u;\n vec3 v = light.v;\n int type = int(light.type);\n\n#ifdef HAS_RECT_LIGHTS\n if (type == RECT_LIGHT) {\n // Adjust the position from center to start corner\n vec3 pos = light.position-u*0.5-v*0.5;\n vec3 normal = normalize(cross(u, v));\n if (dot(normal, r.d) > 0.) // Hide backfacing quad light\n return INF;\n\n d = intersectRect(pos, u, v, normal, r);\n if (d < 0.) {\n d = INF;\n }\n else {\n float cosTheta = dot(-r.d, normal);\n float spread = light.spread;\n if (cosTheta >= cos(spread * PI / 2.0)) {\n lightSample.pdf = (d * d) / (light.area * cosTheta);\n lightSample.emission = light.emission;\n }\n }\n }\n#endif\n#ifdef HAS_SPHERE_LIGHTS\n if (type == SPHERE_LIGHT) {\n if (light.radius <= 0.0) {\n vec3 toPoint = light.position - r.o;\n float projection = dot(toPoint, r.d);\n vec3 perpendicular = toPoint - projection * r.d;\n if (projection <= EPS || dot(perpendicular, perpendicular) > 1e-8) return INF;\n d = projection;\n lightSample.direction = r.d;\n lightSample.normal = -r.d;\n lightSample.dist = d;\n lightSample.pdf = 1.0;\n lightSample.isDelta = true;\n } else {\n d = intersectSphere(light.radius, light.position, r);\n lightSample.isDelta = false;\n }\n if (d < 0.) {\n d = INF;\n }\n else {\n if (light.radius > 0.0) {\n lightSample.pdf = sphereSolidAnglePdf(r.o, light.position, light.radius);\n }\n lightSample.emission = light.radius <= 0.0\n ? light.emission / max(d * d, 1e-8)\n : light.emission;\n }\n }\n#endif\n#ifdef HAS_SPOT_LIGHTS\n if (type == SPOT_LIGHT) {\n if (light.radius <= 0.0) {\n vec3 toPoint = light.position - r.o;\n float projection = dot(toPoint, r.d);\n vec3 perpendicular = toPoint - projection * r.d;\n if (projection <= EPS || dot(perpendicular, perpendicular) > 1e-8) return INF;\n d = projection;\n lightSample.direction = r.d;\n lightSample.normal = -r.d;\n lightSample.dist = d;\n lightSample.pdf = 1.0;\n lightSample.isDelta = true;\n } else {\n d = intersectSphere(light.radius, light.position, r);\n lightSample.isDelta = false;\n }\n if (d != INF) {\n vec3 hitPt = r.o + d * r.d;\n float multiplier = evaluateSpotEmissionMultiplier(light, normalize(r.o - hitPt));\n if (multiplier <= 0.0) return INF;\n if (light.radius > 0.0) {\n lightSample.pdf = sphereSolidAnglePdf(r.o, light.position, light.radius);\n }\n lightSample.emission = light.emission * multiplier * (light.radius <= 0.0\n ? 1.0 / max(d * d, 1e-8)\n : 1.0);\n }\n }\n#endif\n\n return d;\n}\n#endif\n\nint randomPickMaterial(ivec4 m0, ivec4 m1, ivec4 m2, vec3 bary) {\n vec2 m00 = unpackMaterialIndex(m0.x);\n vec2 m01 = unpackMaterialIndex(m0.y);\n vec2 m02 = unpackMaterialIndex(m0.z);\n vec2 m10 = unpackMaterialIndex(m1.x);\n vec2 m11 = unpackMaterialIndex(m1.y);\n vec2 m12 = unpackMaterialIndex(m1.z);\n vec2 m20 = unpackMaterialIndex(m2.x);\n vec2 m21 = unpackMaterialIndex(m2.y);\n vec2 m22 = unpackMaterialIndex(m2.z);\n float w00 = m00.y * bary.x;\n float w01 = m01.y * bary.x;\n float w02 = m02.y * bary.x;\n float w10 = m10.y * bary.y;\n float w11 = m11.y * bary.y;\n float w12 = m12.y * bary.y;\n float w20 = m20.y * bary.z;\n float w21 = m21.y * bary.z;\n float w22 = m22.y * bary.z;\n\n float wTotal = w00 + w01 + w02 + w10 + w11 + w12 + w20 + w21 + w22;\n // Accumulate weights\n w00 = w00 / wTotal;\n w01 = w01 / wTotal + w00;\n w02 = w02 / wTotal + w01;\n w10 = w10 / wTotal + w02;\n w11 = w11 / wTotal + w10;\n w12 = w12 / wTotal + w11;\n w20 = w20 / wTotal + w12;\n w21 = w21 / wTotal + w20;\n w22 = w22 / wTotal + w21;\n\n float rand = hashedSample(0u);\n float mIdx;\n if (rand < w00) {\n mIdx = m00.x;\n } else if (rand < w01) {\n mIdx = m01.x;\n } else if (rand < w02) {\n mIdx = m02.x;\n } else if (rand < w10) {\n mIdx = m10.x;\n } else if (rand < w11) {\n mIdx = m11.x;\n } else if (rand < w12) {\n mIdx = m12.x;\n } else if (rand < w20) {\n mIdx = m20.x;\n } else if (rand < w21) {\n mIdx = m21.x;\n } else {\n mIdx = m22.x;\n }\n return int(mIdx);\n}\n\n\nvec4 fetchIns(int i);\n\nvec4 fetchVertexAttribute(int vertex, int slot) {\n return fetchData(vertexAttributes, vertex * VERTEX_ATTRIBUTE_STRIDE + slot, vertexAttributeColumns);\n}\nvec3 fetchVertexNormal(int vertex) { return fetchVertexAttribute(vertex, 0).xyz; }\nvec2 fetchVertexUv(int vertex) { return fetchVertexAttribute(vertex, 1).xy; }\nivec4 fetchVertexMaterial(int vertex) {\n return ivec4(fetchVertexAttribute(vertex, 0).w, fetchVertexAttribute(vertex, 1).zw, 0.0);\n}\nvec2 fetchVertexUv1(int vertex) {\n#ifdef USE_UV1\n return fetchVertexAttribute(vertex, VERTEX_UV1_SLOT).xy;\n#else\n return vec2(0.0);\n#endif\n}\n#ifdef USE_TANGENT\nvec4 fetchVertexTangent(int vertex) { return fetchVertexAttribute(vertex, VERTEX_TANGENT_SLOT); }\n#endif\n\n\nmat2x3 anisotropy_axes(vec3 normal, vec3 dp1, vec3 dp2, vec2 duv1, vec2 duv2, vec4 inputTangent) {\n float determinant = duv1.x * duv2.y - duv1.y * duv2.x;\n vec3 t = inputTangent.xyz;\n vec3 b = vec3(0.0);\n // Internal W=2 marks an authored XYZ tangent whose sign is derived from UVs.\n float handedness = abs(inputTangent.w) > 1.5 ? 0.0 : inputTangent.w;\n if (abs(determinant) > 1e-12) {\n vec3 dt = (dp1 * duv2.y - dp2 * duv1.y) / determinant;\n vec3 db = (dp2 * duv1.x - dp1 * duv2.x) / determinant;\n if (dot(t, t) < 1e-8) { t = dt; }\n if (handedness == 0.0) { handedness = (dot(cross(normal, dt), db) < 0.0 ? -1.0 : 1.0); }\n }\n t -= normal * dot(normal, t);\n if (dot(t, t) < 1e-8) {\n float signZ = (normal.z >= 0.0 ? 1.0 : -1.0);\n float factor = -1.0 / (signZ + normal.z);\n float xy = normal.x * normal.y * factor;\n t = vec3(1.0 + signZ * normal.x * normal.x * factor, signZ * xy, -signZ * normal.x);\n b = vec3(xy, signZ + normal.y * normal.y * factor, -normal.y);\n }\n else { t = normalize(t); b = normalize(cross(normal, t)); }\n return mat2x3(t, b * (handedness < 0.0 ? -1.0 : 1.0));\n}\n\nvoid fetchAttributes(inout SurfaceInteraction si, Triangle tri, vec3 barycentric, ivec3 index) {\n si.hit = true;\n si.position = barycentric.x * tri.p0 + barycentric.y * tri.p1 + barycentric.z * tri.p2;\n si.vertexColor = vec3(1.0);\n#ifdef USE_VERTEX_COLOR\n si.vertexColor = barycentric.x * fetchVertexAttribute(index.x, VERTEX_COLOR_SLOT).rgb\n + barycentric.y * fetchVertexAttribute(index.y, VERTEX_COLOR_SLOT).rgb\n + barycentric.z * fetchVertexAttribute(index.z, VERTEX_COLOR_SLOT).rgb;\n#endif\n\n vec3 n0 = fetchVertexNormal(index.x);\n vec3 n1 = fetchVertexNormal(index.y);\n vec3 n2 = fetchVertexNormal(index.z);\n vec3 normal = normalize(barycentric.x * n0 + barycentric.y * n1 + barycentric.z * n2);\n si.vertexNormal = normal;\n\n // Approximate the smooth limit surface at this triangle hit. Direct-light\n // rays use this geometric offset only near the shadow terminator, avoiding\n // false self-shadowing by adjacent facets without moving ordinary hits.\n // Architecture follows Cycles' shadow_ray_smooth_surface_offset.\n vec3 geometricNormal = normalize(cross(tri.p1 - tri.p0, tri.p2 - tri.p0));\n vec3 smoothNormal = barycentric.x * n0 + barycentric.y * n1 + barycentric.z * n2;\n float a = dot(n2 - n0, tri.p0 - tri.p2);\n float b = dot(n2 - n1, tri.p1 - tri.p2);\n float c = dot(n1 - n0, tri.p1 - tri.p0);\n float h = a * barycentric.x * (barycentric.x - 1.0)\n + (a + b + c) * barycentric.x * barycentric.y\n + b * barycentric.y * (barycentric.y - 1.0);\n if (dot(smoothNormal, geometricNormal) > 0.0) {\n float h0 = max(max(dot(tri.p1 - tri.p0, n0), dot(tri.p2 - tri.p0, n0)), 0.0);\n float h1 = max(max(dot(tri.p0 - tri.p1, n1), dot(tri.p2 - tri.p1, n1)), 0.0);\n float h2 = max(max(dot(tri.p0 - tri.p2, n2), dot(tri.p1 - tri.p2, n2)), 0.0);\n h0 = max(dot(tri.p0 - si.position, n0) + h0, 0.0);\n h1 = max(dot(tri.p1 - si.position, n1) + h1, 0.0);\n h2 = max(dot(tri.p2 - si.position, n2) + h2, 0.0);\n h = max(min(min(h0, h1), h2), h * 0.5);\n }\n else {\n float h0 = max(max(dot(tri.p0 - tri.p1, n0), dot(tri.p0 - tri.p2, n0)), 0.0);\n float h1 = max(max(dot(tri.p1 - tri.p0, n1), dot(tri.p1 - tri.p2, n1)), 0.0);\n float h2 = max(max(dot(tri.p2 - tri.p0, n2), dot(tri.p2 - tri.p1, n2)), 0.0);\n h0 = max(dot(si.position - tri.p0, n0) + h0, 0.0);\n h1 = max(dot(si.position - tri.p1, n1) + h1, 0.0);\n h2 = max(dot(si.position - tri.p2, n2) + h2, 0.0);\n h = min(-min(min(h0, h1), h2), h * 0.5);\n }\n si.shadowOffset = smoothNormal * h;\n\n ivec4 m0 = fetchVertexMaterial(index.x);\n ivec4 m1 = fetchVertexMaterial(index.y);\n ivec4 m2 = fetchVertexMaterial(index.z);\n \n if (m0.x > 0 || m1.x > 0 || m2.x > 0) {\n si.materialIndex = randomPickMaterial(m0, m1, m2, barycentric);\n }\n \n vec2 uv0 = fetchVertexUv(index.x);\n vec2 uv1 = fetchVertexUv(index.y);\n vec2 uv2 = fetchVertexUv(index.z);\n #if defined(NUM_DIFFUSE_MAPS) || defined(NUM_NORMAL_MAPS) || defined(NUM_METALLIC_ROUGHNESS_MAPS) || defined(NUM_ROUGHNESS_MAPS) || defined(NUM_METALNESS_MAPS) || defined(NUM_EMISSIVE_MAPS) || defined(NUM_THIN_FILM_MAPS) || defined(NUM_ANISOTROPY_MAPS) || defined(NUM_COAT_NORMAL_MAPS)\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec2 secondaryUv0 = fetchVertexUv1(index.x);\n vec2 secondaryUv1 = fetchVertexUv1(index.y);\n vec2 secondaryUv2 = fetchVertexUv1(index.z);\n vec2 secondaryUv = barycentric.x * secondaryUv0\n + barycentric.y * secondaryUv1\n + barycentric.z * secondaryUv2;\n\n vec4 uvInfo = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, si.position, normal, uvInfo.zw);\n secondaryUv = uv;\n } else {\n uv *= uvInfo.zw;\n secondaryUv *= uvInfo.zw;\n }\n #else\n vec2 uv = vec2(0.0);\n vec2 secondaryUv = vec2(0.0);\n #endif\n\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normal;\n#ifdef NUM_COAT_NORMAL_MAPS\n float coatNormalIndex = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_LAYER_MAPS).z;\n#endif\n#endif\n vec4 directionMaterial = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_DIRECTION_NORMAL);\n float coatRotation = fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_FILM_TEXTURE).x;\n if (directionMaterial.x >= 0.0 || directionMaterial.y != 0.0 || coatRotation != 0.0\n#ifdef USE_COAT_NORMAL_FRAMES\n || fetchMatData(si.materialIndex * MAT_DATA_SIZE + MAT_ROW_COAT).w > 0.0\n#endif\n ) {\n vec3 dp1 = tri.p0 - tri.p2;\n vec3 dp2 = tri.p1 - tri.p2;\n vec4 inputTangent = vec4(0.0);\n#ifdef USE_TANGENT\n inputTangent = barycentric.x * fetchVertexTangent(index.x)\n + barycentric.y * fetchVertexTangent(index.y)\n + barycentric.z * fetchVertexTangent(index.z);\n#endif\n mat2x3 geometryAxes = anisotropy_axes(normal, dp1, dp2, uv0-uv2, uv1-uv2, inputTangent);\n si.geometryTangent = geometryAxes[0];\n si.geometryBitangent = geometryAxes[1];\n mat2x3 directionAxes = geometryAxes;\n#ifdef NUM_ANISOTROPY_MAPS\n if (directionMaterial.x >= 0.0 && mapUvChannel[int(directionMaterial.x)] > 0.5) {\n vec2 a = fetchVertexUv1(index.x);\n vec2 b = fetchVertexUv1(index.y);\n vec2 c = fetchVertexUv1(index.z);\n directionAxes = anisotropy_axes(normal, dp1, dp2, a-c, b-c, (inputTangent.w == 0.0 ? vec4(0.0) : inputTangent));\n }\n#endif\n si.directionTangent = directionAxes[0];\n si.directionBitangent = directionAxes[1];\n#if defined(USE_COAT_NORMAL_FRAMES) && defined(NUM_COAT_NORMAL_MAPS)\n if (coatNormalIndex >= 0.0) {\n int coatIndex = int(coatNormalIndex);\n mat2x3 coatAxes = geometryAxes;\n if (mapUvChannel[coatIndex] > 0.5) {\n vec2 a = fetchVertexUv1(index.x);\n vec2 b = fetchVertexUv1(index.y);\n vec2 c = fetchVertexUv1(index.z);\n coatAxes = anisotropy_axes(normal, dp1, dp2, a-c, b-c,\n inputTangent.w == 0.0 ? vec4(0.0) : inputTangent);\n }\n vec3 decoded = sampleMap(coatIndex, getMapUvSet(coatIndex, uv, secondaryUv)).rgb * 2.0 - 1.0;\n vec3 mapped = coatAxes[0] * decoded.x * directionMaterial.z\n + coatAxes[1] * decoded.y * directionMaterial.w + normal * decoded.z;\n if (dot(mapped, mapped) > 1e-12) { si.coatNormal = normalize(mapped); }\n }\n#endif\n }\n\n si.uv = uv;\n si.uv1 = secondaryUv;\n\n #ifdef USE_TANGENT\n vec3 t0 = fetchVertexTangent(index.x).xyz;\n vec3 t1 = fetchVertexTangent(index.y).xyz;\n vec3 t2 = fetchVertexTangent(index.z).xyz;\n si.tangent = normalize(barycentric.x * t0 + barycentric.y * t1 + barycentric.z * t2);\n #endif\n #if defined(NUM_NORMAL_MAPS)\n vec3 dp1 = tri.p0 - tri.p2;\n vec3 dp2 = tri.p1 - tri.p2;\n vec2 duv1 = uv0 - uv2;\n vec2 duv2 = uv1 - uv2;\n si.normal = getMatNormal(\n si.materialIndex, uv, normal, dp1, dp2, duv1, duv2\n );\n #else\n si.normal = normal;\n #endif\n}\n\nstruct TriangleIntersect {\n float t;\n vec3 barycentric;\n};\n\nvec4 fetchBVH(int i) {\n return fetchData(bvhBuffer, i, bvhColumns);\n}\n\nvec4 fetchIns(int i) {\n return fetchData(bvhBuffer, instancesOffset + i, bvhColumns);\n}\n\n// GLSL ES 3.00 has no bitCount intrinsic. Count the CWBVH mask bits using\n// integer operations supported by WebGL 2.\nuint countBvhBits(uint value) {\n value -= (value >> 1u) & 0x55555555u;\n value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u);\n value = (value + (value >> 4u)) & 0x0f0f0f0fu;\n return (value * 0x01010101u) >> 24u;\n}\n\nvec4 unpackBvh4Bounds(uint packedBounds) {\n return vec4(\n float(packedBounds & 0xffu),\n float((packedBounds >> 8u) & 0xffu),\n float((packedBounds >> 16u) & 0xffu),\n float(packedBounds >> 24u)\n ) / 255.0;\n}\n\n// Triangle-ray intersection\n// Faster than the classic Möller–Trumbore intersection algorithm\n// http://www.pbr-book.org/3ed-2018/Shapes/Triangle_Meshes.html#TriangleIntersection\nTriangleIntersect intersectTriangle(vec3 o, vec3 d, Triangle tri, int maxDim, vec3 shear, float tMax) {\n TriangleIntersect ti;\n\n // translate vertices based on ray origin\n vec3 p0t = tri.p0 - o;\n vec3 p1t = tri.p1 - o;\n vec3 p2t = tri.p2 - o;\n\n // permute components of triangle vertices\n if (maxDim == 0) {\n p0t = p0t.yzx;\n p1t = p1t.yzx;\n p2t = p2t.yzx;\n } else if (maxDim == 1) {\n p0t = p0t.zxy;\n p1t = p1t.zxy;\n p2t = p2t.zxy;\n }\n\n // apply shear transformation to translated vertex positions\n p0t.xy += shear.xy * p0t.z;\n p1t.xy += shear.xy * p1t.z;\n p2t.xy += shear.xy * p2t.z;\n\n // compute edge function coefficients\n vec3 e = vec3(\n p1t.x * p2t.y - p1t.y * p2t.x,\n p2t.x * p0t.y - p2t.y * p0t.x,\n p0t.x * p1t.y - p0t.y * p1t.x\n );\n\n#ifdef DEPTH_QUERY_MODE\n vec3 edgeScale = abs(vec3(p1t.x * p2t.y, p2t.x * p0t.y, p0t.x * p1t.y))\n + abs(vec3(p1t.y * p2t.x, p2t.y * p0t.x, p0t.y * p1t.x));\n e = mix(e, vec3(0.0), lessThanEqual(abs(e), edgeScale * 1e-6));\n#endif\n\n // check if intersection is inside triangle\n if (any(lessThan(e, vec3(0))) && any(greaterThan(e, vec3(0)))) {\n return ti;\n }\n\n float det = e.x + e.y + e.z;\n#ifdef DEPTH_QUERY_MODE\n if (det == 0.0) return ti;\n#endif\n\n p0t.z *= shear.z;\n p1t.z *= shear.z;\n p2t.z *= shear.z;\n float tScaled = (e.x * p0t.z + e.y * p1t.z + e.z * p2t.z);\n\n // check if closer intersection already exists\n if (abs(tScaled) > abs(tMax * det)) {\n return ti;\n }\n\n float invDet = 1. / det;\n ti.t = tScaled * invDet;\n ti.barycentric = e * invDet;\n\n return ti;\n}\n\nstruct Box {\n vec3 min;\n vec3 max;\n};\n\n// Conservative slabs only for the unjittered depth query shader.\nvec3 traversalInverse(vec3 d) {\n#ifdef DEPTH_QUERY_MODE\n vec3 denominator = mix(d, mix(vec3(1e-20), vec3(-1e-20), lessThan(d, vec3(0.0))), lessThan(abs(d), vec3(1e-20)));\n return 1.0 / denominator;\n#else\n return 1.0 / d;\n#endif\n}\n\nvec3 depthSlabPadding(vec3 invD, vec3 o) {\n#ifdef DEPTH_QUERY_MODE\n return abs(invD) * max(vec3(1.0), abs(o)) * 1e-6;\n#else\n return vec3(0.0);\n#endif\n}\n\n// Branchless ray/box intersection\n// https://tavianator.com/fast-branchless-raybounding-box-intersections/\nfloat intersectBox(vec3 o, vec3 d, vec3 bmin, vec3 bmax, float tMax) {\n#ifdef DEPTH_QUERY_MODE\n vec3 invD = traversalInverse(d);\n vec3 tBot = (bmin - o) * invD;\n vec3 tTop = (bmax - o) * invD;\n vec3 padding = depthSlabPadding(invD, o);\n#else\n vec3 tBot = (bmin - o) / d;\n vec3 tTop = (bmax - o) / d;\n vec3 padding = vec3(0.0);\n#endif\n vec3 tNear = min(tBot, tTop) - padding;\n vec3 tFar = max(tBot, tTop) + padding;\n float t0 = max(tNear.x, max(tNear.y, tNear.z));\n float t1 = min(tFar.x, min(tFar.y, tFar.z));\n\n return (t0 > t1 || t0 > tMax) ? -1.0 : (t0 > 0.0 ? t0 : t1);\n}\n\nint maxDimension(vec3 v) {\n return v.x > v.y ? (v.x > v.z ? 0 : 2) : (v.y > v.z ? 1 : 2);\n}\n\nvec3 getShear(vec3 d, int maxDim) {\n // Permute space so that the z dimension is the one where the absolute value of the ray's direction is largest.\n // Then create a shear transformation that aligns ray direction with the +z axis\n if (maxDim == 0) {\n return vec3(-d.y, -d.z, 1.0) / d.x;\n } else if (maxDim == 1) {\n return vec3(-d.z, -d.x, 1.0) / d.y;\n } else {\n return vec3(-d.x, -d.y, 1.0) / d.z;\n }\n}\n\n// Traverse BVH, find closest triangle intersection, and return surface information\nvoid intersectScene(in Ray ray, inout SurfaceInteraction si, bool doubleSided) {\n si.hit = false;\n\n if (isEmptyScene) {\n return;\n }\n\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n int hitInsIdx;\n\n${getBVHTraverseCode(glsl`\n si.triangleIndex = triangleIndex;\n hitTri = tri;\n hitFaceNormal = faceNormal;\n hitBarycentric = hit.barycentric;\n hitIndex = index;\n isHit = true;\n hitInsIdx = insIdx;\n`)}\n\n if (isHit) {\n si.instanceIndex = hitInsIdx;\n si.materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n // fetchAttributes before transform to world space.\n fetchAttributes(si, hitTri, hitBarycentric, hitIndex);\n mat4 l2w = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 5),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 6),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 7),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 8)\n );\n mat4 w2l = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n mat3 normalTransform = transpose(mat3(w2l));\n si.faceNormal = normalize(normalTransform * hitFaceNormal);\n si.vertexNormal = normalize(normalTransform * si.vertexNormal);\n si.normal = normalize(normalTransform * si.normal);\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normalize(normalTransform * si.coatNormal);\n#endif\n#ifdef USE_TANGENT\n if (dot(si.tangent, si.tangent) > 0.0) {\n si.tangent = normalize(mat3(l2w) * si.tangent);\n }\n#endif\n si.shadowOffset = (l2w * vec4(si.shadowOffset, 0.0)).xyz;\n si.directionTangent = mat3(l2w) * si.directionTangent;\n si.directionBitangent = mat3(l2w) * si.directionBitangent;\n si.geometryTangent = mat3(l2w) * si.geometryTangent;\n si.geometryBitangent = mat3(l2w) * si.geometryBitangent;\n si.position = (l2w * vec4(si.position, 1.0)).xyz;\n }\n}\n\n// Local intersection helper for shader bevel.\nvoid intersectSceneBevel(in Ray ray, inout SurfaceInteraction si, int instanceIndex, float maxDistance) {\n si.hit = false;\n\n if (isEmptyScene) {\n return;\n }\n\n bool doubleSided = true;\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n int hitInsIdx;\n\n${getBVHTraverseCode(\n glsl`\n si.triangleIndex = triangleIndex;\n hitTri = tri;\n hitFaceNormal = faceNormal;\n hitBarycentric = hit.barycentric;\n hitIndex = index;\n isHit = true;\n hitInsIdx = insIdx;\n`,\n glsl`\n if (insIdx != instanceIndex) {\n continue;\n }\n`,\n 'maxDistance'\n)}\n\n if (isHit) {\n si.instanceIndex = hitInsIdx;\n si.materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n fetchAttributes(si, hitTri, hitBarycentric, hitIndex);\n mat4 l2w = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 5),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 6),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 7),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 8)\n );\n mat4 w2l = mat4(\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 1),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 2),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 3),\n fetchIns(hitInsIdx * ${INSTANCE_VEC4_STRIDE} + 4)\n );\n mat3 normalTransform = transpose(mat3(w2l));\n si.faceNormal = normalize(normalTransform * hitFaceNormal);\n si.vertexNormal = normalize(normalTransform * si.vertexNormal);\n si.normal = normalize(normalTransform * si.normal);\n#ifdef USE_COAT_NORMAL_FRAMES\n si.coatNormal = normalize(normalTransform * si.coatNormal);\n#endif\n#ifdef USE_TANGENT\n if (dot(si.tangent, si.tangent) > 0.0) {\n si.tangent = normalize(mat3(l2w) * si.tangent);\n }\n#endif\n si.shadowOffset = (l2w * vec4(si.shadowOffset, 0.0)).xyz;\n si.directionTangent = mat3(l2w) * si.directionTangent;\n si.directionBitangent = mat3(l2w) * si.directionBitangent;\n si.geometryTangent = mat3(l2w) * si.geometryTangent;\n si.geometryBitangent = mat3(l2w) * si.geometryBitangent;\n si.position = (l2w * vec4(si.position, 1.0)).xyz;\n }\n}\n\nbool intersectSceneShadow(in Ray ray, float lightDistance, int currTriangleIndex) {\n\n if (isEmptyScene) {\n return false;\n }\n\n bool doubleSided = true;\n int maxDim = maxDimension(abs(ray.d));\n vec3 shear = getShear(ray.d, maxDim);\n\n${getBVHTraverseCode(\n glsl`\n // Traversal is clipped to lightDistance. Affine instance transforms keep\n // the ray parameter unchanged because local directions are not normalized.\n bool isOccluded = true;\n vec3 barycentric = hit.barycentric;\n vec3 position = barycentric.x * tri.p0 + barycentric.y * tri.p1 + barycentric.z * tri.p2;\n\n if (isOccluded) {\n#ifdef HAS_ALPHA\n int materialIndex = int(unpackMaterialIndex(floatBitsToInt(fetchIns(insIdx * ${INSTANCE_VEC4_STRIDE}).z)).x);\n ivec4 m0 = fetchVertexMaterial(index.x);\n ivec4 m1 = fetchVertexMaterial(index.y);\n ivec4 m2 = fetchVertexMaterial(index.z);\n \n if (m0.x > 0 || m1.x > 0 || m2.x > 0) {\n materialIndex = randomPickMaterial(m0, m1, m2, barycentric);\n }\n \n int ii = materialIndex * MAT_DATA_SIZE;\n int mapAlphaUsage = int(fetchMatData(ii + MAT_ROW_MISC).a);\n float alpha = fetchMatData(ii + MAT_ROW_ALPHA_FILM).r;\n #ifdef NUM_DIFFUSE_MAPS\n if (mapAlphaUsage == ${mapAlphaUsageConstants.alpha + ''}) {\n int diffuseMapIndex = int(fetchMatData(ii + MAT_ROW_METALLIC_MAPS).z);\n if (diffuseMapIndex >= 0) {\n vec2 uv0 = fetchVertexUv(index.x);\n vec2 uv1 = fetchVertexUv(index.y);\n vec2 uv2 = fetchVertexUv(index.z);\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec4 uvInfo = fetchMatData(ii + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, position, hitFaceNormal, uvInfo.zw);\n } else {\n uv *= uvInfo.zw;\n }\n \n alpha *= sampleMap(diffuseMapIndex, uv).a;\n }\n }\n #endif\n #ifdef NUM_ALPHA_MAPS\n int alphaMapIndex = int(fetchMatData(ii + MAT_ROW_STANDALONE_MAPS).z);\n if (alphaMapIndex >= 0) {\n vec2 uv0 = fetchVertexUv(index.x);\n vec2 uv1 = fetchVertexUv(index.y);\n vec2 uv2 = fetchVertexUv(index.z);\n vec2 uv = barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2;\n vec4 uvInfo = fetchMatData(ii + MAT_ROW_UV);\n int uvProjection = int(uvInfo.r);\n if (uvProjection > 0) {\n uv = projectUV(uvProjection, position, hitFaceNormal, uvInfo.zw);\n } else {\n uv *= uvInfo.zw;\n }\n alpha *= sampleMap(alphaMapIndex, uv).g;\n }\n #endif\n float alphaCutoff = fetchMatData(ii + MAT_ROW_STANDALONE_MAPS).a;\n alpha = resolveMaterialAlpha(\n alpha, int(fetchMatData(ii + MAT_ROW_ALPHA).w), alphaCutoff\n );\n if (hashedSample(0u) > alpha) {\n // Continue after a transparent hit without traversing beyond the light.\n tMax = min(max(lightDistance, 0.0), RAY_MAX_DISTANCE);\n isOccluded = false;\n }\n#endif\n }\n if (isOccluded) {\n return true;\n }\n`,\n glsl`\n if (triangleIndex == currTriangleIndex) {\n continue;\n }\n`,\n 'min(max(lightDistance, 0.0), RAY_MAX_DISTANCE)'\n)}\n return false;\n}\n`\n});\n"]}
|
|
@@ -25,7 +25,7 @@ export function createMaterialBufferGlsl(fragments = {}) {
|
|
|
25
25
|
main: glsl `
|
|
26
26
|
${materialRowsGlsl()}
|
|
27
27
|
#ifdef HAS_GLTF_ANISOTROPY
|
|
28
|
-
vec2
|
|
28
|
+
vec2 fl(float roughness, float strength) {
|
|
29
29
|
if (strength == 0.0) { return vec2(roughness, 0.0); }
|
|
30
30
|
float u = roughness * roughness;
|
|
31
31
|
float a = u + (1.0 - u) * strength * strength;
|
|
@@ -35,7 +35,7 @@ return vec2(pow((a*a + u*u) * 0.5, 0.25), clamp(1.0 - u/a, 0.0, 1.0));
|
|
|
35
35
|
|
|
36
36
|
#endif
|
|
37
37
|
|
|
38
|
-
vec3
|
|
38
|
+
vec3 np(vec3 c) {
|
|
39
39
|
return mix(pow(c * 0.9478672986 + 0.0521327014, vec3(2.4)), c * 0.0773993808, vec3(lessThan(c, vec3(0.04045))));
|
|
40
40
|
}
|
|
41
41
|
vec4 fetchMatData(int i) {
|
|
@@ -43,7 +43,7 @@ return fetchData(materialBuffer, i, materialBufferColumns);
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
float
|
|
46
|
+
float mB(float alpha, int alphaMode, float alphaCutoff) {
|
|
47
47
|
if (alphaMode == ${materialAlphaModeConstants.opaque}) {
|
|
48
48
|
return 1.0;
|
|
49
49
|
}
|
|
@@ -53,7 +53,7 @@ return alpha >= alphaCutoff ? 1.0 : 0.0;
|
|
|
53
53
|
return alpha;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
float
|
|
56
|
+
float As(int idx) {
|
|
57
57
|
return fetchMatData(idx * MAT_DATA_SIZE + MAT_ROW_COLOR).w;
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -64,44 +64,44 @@ return vec2(float(val >> 8), float(val & 0xff) / 255.0);
|
|
|
64
64
|
#ifdef NUM_MAPS
|
|
65
65
|
vec3 decodeMapColor(int index, vec3 c) {
|
|
66
66
|
if (mapColorLinear[index] > 0.5) { return c; }
|
|
67
|
-
return
|
|
67
|
+
return np(c);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
vec2
|
|
70
|
+
vec2 getMapSize(int index) {
|
|
71
71
|
return mapInfo[index].xy;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
float
|
|
74
|
+
float getMapLayer(int index) {
|
|
75
75
|
return floor(mapInfo[index].z);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
vec2
|
|
78
|
+
vec2 getMapOffset(int index) {
|
|
79
79
|
return vec2(fract(mapInfo[index].z), mapInfo[index].w);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
float
|
|
82
|
+
float gi(float value, float mode) {
|
|
83
83
|
if (mode < 0.5) return fract(value);
|
|
84
84
|
if (mode < 1.5) return clamp(value, 0.0, 1.0);
|
|
85
85
|
return 1.0 - abs(1.0 - (value - 2.0 * floor(value * 0.5)));
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
vec2
|
|
88
|
+
vec2 jj(int index, vec2 uv) {
|
|
89
89
|
vec4 transform = mapTransform[index];
|
|
90
90
|
vec2 value = uv * transform.xy + transform.zw;
|
|
91
|
-
return vec2(
|
|
91
|
+
return vec2(gi(value.x, mapWrap[index].x), gi(value.y, mapWrap[index].y));
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
vec2
|
|
95
|
-
vec2
|
|
96
|
-
vec2
|
|
97
|
-
vec2
|
|
98
|
-
vec2
|
|
99
|
-
vec2
|
|
100
|
-
vec2
|
|
94
|
+
vec2 getMapUV(int index, vec2 uv) {
|
|
95
|
+
vec2 sZ = jj(index, uv);
|
|
96
|
+
vec2 jT = 1.0 / vec2(textureSize(map, 0).xy);
|
|
97
|
+
vec2 eg = getMapOffset(index);
|
|
98
|
+
vec2 lf = getMapSize(index) + jT;
|
|
99
|
+
vec2 qy = eg - 0.5 * jT;
|
|
100
|
+
vec2 mM = eg + lf - jT;
|
|
101
101
|
return clamp(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
qy + sZ * lf,
|
|
103
|
+
eg,
|
|
104
|
+
mM
|
|
105
105
|
);
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -109,42 +109,42 @@ vec2 getMapUvSet(int index, vec2 uv, vec2 uv1) {
|
|
|
109
109
|
return mapUvChannel[index] > 0.5 ? uv1 : uv;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
vec4
|
|
113
|
-
ivec2 p = clamp(
|
|
114
|
-
if (modes.x < 0.5) p.x = ((
|
|
115
|
-
if (modes.y < 0.5) p.y = ((
|
|
116
|
-
return texelFetch(map, ivec3(origin + p, int(
|
|
112
|
+
vec4 eX(int index, ivec2 jV, ivec2 size, ivec2 origin, vec2 modes) {
|
|
113
|
+
ivec2 p = clamp(jV, ivec2(0), size - 1);
|
|
114
|
+
if (modes.x < 0.5) p.x = ((jV.x % size.x) + size.x) % size.x;
|
|
115
|
+
if (modes.y < 0.5) p.y = ((jV.y % size.y) + size.y) % size.y;
|
|
116
|
+
return texelFetch(map, ivec3(origin + p, int(getMapLayer(index))), 0);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
vec4 sampleMap(int index, vec2 uv) {
|
|
120
|
-
ivec2 size = ivec2(round(
|
|
121
|
-
vec2
|
|
120
|
+
ivec2 size = ivec2(round(getMapSize(index) * vec2(textureSize(map, 0).xy) + 1.0));
|
|
121
|
+
vec2 texel = jj(index, uv) * vec2(size) - 0.5;
|
|
122
122
|
vec2 modes = mapWrap[index];
|
|
123
|
-
if ((size.x > 1 && modes.x < 0.5 && (
|
|
124
|
-
(size.y > 1 && modes.y < 0.5 && (
|
|
125
|
-
ivec2 base = ivec2(floor(
|
|
126
|
-
vec2 weight = fract(
|
|
127
|
-
ivec2 origin = ivec2(round(
|
|
123
|
+
if ((size.x > 1 && modes.x < 0.5 && (texel.x < 0.0 || texel.x > float(size.x - 1))) ||
|
|
124
|
+
(size.y > 1 && modes.y < 0.5 && (texel.y < 0.0 || texel.y > float(size.y - 1)))) {
|
|
125
|
+
ivec2 base = ivec2(floor(texel));
|
|
126
|
+
vec2 weight = fract(texel);
|
|
127
|
+
ivec2 origin = ivec2(round(getMapOffset(index) * vec2(textureSize(map, 0).xy) - 0.5));
|
|
128
128
|
return mix(
|
|
129
|
-
mix(
|
|
130
|
-
mix(
|
|
129
|
+
mix(eX(index, base, size, origin, modes), eX(index, base + ivec2(1, 0), size, origin, modes), weight.x),
|
|
130
|
+
mix(eX(index, base + ivec2(0, 1), size, origin, modes), eX(index, base + ivec2(1, 1), size, origin, modes), weight.x), weight.y);
|
|
131
131
|
}
|
|
132
|
-
return texture(map, vec3(
|
|
132
|
+
return texture(map, vec3(getMapUV(index, uv), getMapLayer(index)));
|
|
133
133
|
}
|
|
134
134
|
#endif
|
|
135
135
|
|
|
136
136
|
|
|
137
137
|
vec2 aL(float roughness, float anisotropy) {
|
|
138
138
|
float alpha = roughness * roughness;
|
|
139
|
-
float
|
|
140
|
-
if (anisotropy == 0.0) { return vec2(max(
|
|
141
|
-
float
|
|
142
|
-
float
|
|
143
|
-
return max(vec2(
|
|
139
|
+
float rf = ROUGHNESS_MIN * ROUGHNESS_MIN;
|
|
140
|
+
if (anisotropy == 0.0) { return vec2(max(rf, alpha)); }
|
|
141
|
+
float da = 1.0 - anisotropy;
|
|
142
|
+
float uU = alpha * sqrt(2.0 / (1.0 + da * da));
|
|
143
|
+
return max(vec2(rf), vec2(uU, da * uU));
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
vec4 fetchIns(int i);
|
|
147
|
-
vec3
|
|
147
|
+
vec3 lO(int instanceIndex) {
|
|
148
148
|
if (instanceIndex < 0) return vec3(1.0);
|
|
149
149
|
return fetchIns(instanceIndex * ${INSTANCE_VEC4_STRIDE + ''} + 9).rgb;
|
|
150
150
|
}
|
|
@@ -158,62 +158,62 @@ int instanceIndex,
|
|
|
158
158
|
vec3 vertexColor
|
|
159
159
|
) {
|
|
160
160
|
int i = materialIndex * MAT_DATA_SIZE;
|
|
161
|
-
vec4
|
|
161
|
+
vec4 qL = fetchMatData(i + MAT_ROW_COLOR);
|
|
162
162
|
vec4 roughnessAndNormal = fetchMatData(i + MAT_ROW_ROUGHNESS_NORMAL);
|
|
163
|
-
vec4
|
|
164
|
-
vec4
|
|
165
|
-
vec4
|
|
163
|
+
vec4 gG = fetchMatData(i + MAT_ROW_METALLIC_MAPS);
|
|
164
|
+
vec4 ig = fetchMatData(i + MAT_ROW_EMISSION);
|
|
165
|
+
vec4 hr = fetchMatData(i + MAT_ROW_IOR_TRANSMISSION);
|
|
166
166
|
vec4 misc = fetchMatData(i + MAT_ROW_MISC);
|
|
167
|
-
vec4
|
|
168
|
-
vec4
|
|
169
|
-
vec4
|
|
167
|
+
vec4 pg = fetchMatData(i + MAT_ROW_ALPHA_FILM);
|
|
168
|
+
vec4 nd = fetchMatData(i + MAT_ROW_BASE_CONTROLS);
|
|
169
|
+
vec4 qT = fetchMatData(i + MAT_ROW_SPECULAR_FUZZ);
|
|
170
170
|
vec4 subsurface = fetchMatData(i + MAT_ROW_SUBSURFACE);
|
|
171
|
-
vec4
|
|
171
|
+
vec4 AH = fetchMatData(i + MAT_ROW_FUZZ);
|
|
172
172
|
vec4 coat = fetchMatData(i + MAT_ROW_COAT);
|
|
173
|
-
vec4
|
|
174
|
-
vec4
|
|
175
|
-
vec4
|
|
173
|
+
vec4 ng = fetchMatData(i + MAT_ROW_COAT_CONTROLS);
|
|
174
|
+
vec4 oJ = fetchMatData(i + MAT_ROW_FILM_DISPERSION);
|
|
175
|
+
vec4 pf = fetchMatData(i + MAT_ROW_STANDALONE_MAPS);
|
|
176
176
|
int mapAlphaUsage = int(misc.a);
|
|
177
177
|
|
|
178
|
-
mat.baseColor =
|
|
179
|
-
mat.materialType = int(
|
|
178
|
+
mat.baseColor = qL.rgb;
|
|
179
|
+
mat.materialType = int(qL.w);
|
|
180
180
|
mat.specularRoughness = roughnessAndNormal.x;
|
|
181
|
-
mat.baseMetalness =
|
|
182
|
-
mat.specularAnisotropy = clamp(
|
|
183
|
-
mat.emission =
|
|
181
|
+
mat.baseMetalness = gG.x;
|
|
182
|
+
mat.specularAnisotropy = clamp(gG.y, 0.0, 1.0);
|
|
183
|
+
mat.emission = ig.rgb;
|
|
184
184
|
mat.inside = false;
|
|
185
|
-
mat.specularIor =
|
|
186
|
-
mat.transmissionWeight =
|
|
185
|
+
mat.specularIor = hr.x;
|
|
186
|
+
mat.transmissionWeight = hr.y;
|
|
187
187
|
#ifdef HAS_MEDIUM
|
|
188
|
-
mat.mediumType = int(
|
|
188
|
+
mat.mediumType = int(hr.z);
|
|
189
189
|
#else
|
|
190
190
|
mat.mediumType = 0;
|
|
191
191
|
#endif
|
|
192
|
-
mat.thinWalled =
|
|
192
|
+
mat.thinWalled = hr.w > 0.5;
|
|
193
193
|
mat.bevel = misc.r;
|
|
194
194
|
mat.transmissionDispersionScale = misc.g;
|
|
195
|
-
mat.dispersionAbbeNumber = max(
|
|
195
|
+
mat.dispersionAbbeNumber = max(oJ.y, 1e-6);
|
|
196
196
|
mat.thinFilmThickness = misc.b;
|
|
197
|
-
mat.thinFilmIor =
|
|
198
|
-
mat.thinFilmWeight = clamp(
|
|
197
|
+
mat.thinFilmIor = pg.b;
|
|
198
|
+
mat.thinFilmWeight = clamp(oJ.x, 0.0, 1.0);
|
|
199
199
|
|
|
200
200
|
mat.thinFilmThickness *= 1000.0;
|
|
201
|
-
mat.baseWeight = clamp(
|
|
202
|
-
mat.diffuseRoughness = clamp(
|
|
203
|
-
mat.specularWeight = max(0.0,
|
|
204
|
-
mat.subsurfaceWeight = clamp(
|
|
205
|
-
mat.specularColor = max(
|
|
206
|
-
mat.fuzzWeight = clamp(
|
|
201
|
+
mat.baseWeight = clamp(nd.x, 0.0, 1.0);
|
|
202
|
+
mat.diffuseRoughness = clamp(nd.y, 0.0, 1.0);
|
|
203
|
+
mat.specularWeight = max(0.0, nd.z);
|
|
204
|
+
mat.subsurfaceWeight = clamp(nd.w, 0.0, 1.0);
|
|
205
|
+
mat.specularColor = max(qT.rgb, vec3(0.0));
|
|
206
|
+
mat.fuzzWeight = clamp(qT.w, 0.0, 1.0);
|
|
207
207
|
mat.subsurfaceColor = max(subsurface.rgb, vec3(0.0));
|
|
208
208
|
mat.transmissionColor = max(fetchMatData(i + MAT_ROW_TRANSMISSION_COLOR).rgb, vec3(0.0));
|
|
209
|
-
mat.fuzzColor = max(
|
|
210
|
-
mat.fuzzRoughness = clamp(
|
|
209
|
+
mat.fuzzColor = max(AH.rgb, vec3(0.0));
|
|
210
|
+
mat.fuzzRoughness = clamp(AH.w, 0.0, 1.0);
|
|
211
211
|
mat.coatColor = max(coat.rgb, vec3(0.0));
|
|
212
212
|
mat.coatWeight = clamp(coat.w, 0.0, 1.0);
|
|
213
|
-
mat.coatRoughness = clamp(
|
|
214
|
-
mat.coatAnisotropy = clamp(
|
|
215
|
-
mat.coatIor = max(
|
|
216
|
-
mat.coatDarkening = clamp(
|
|
213
|
+
mat.coatRoughness = clamp(ng.x, ROUGHNESS_MIN, 1.0);
|
|
214
|
+
mat.coatAnisotropy = clamp(ng.y, 0.0, 1.0);
|
|
215
|
+
mat.coatIor = max(ng.z, 1.0);
|
|
216
|
+
mat.coatDarkening = clamp(ng.w, 0.0, 1.0);
|
|
217
217
|
|
|
218
218
|
#ifdef HAS_MEDIUM
|
|
219
219
|
mat.mediumExtinction = max(fetchMatData(i + MAT_ROW_MEDIUM_EXTINCTION).rgb, vec3(0.0));
|
|
@@ -224,13 +224,13 @@ mat.mediumType = max(max(mat.mediumExtinction.x, mat.mediumExtinction.y), mat.me
|
|
|
224
224
|
|
|
225
225
|
|
|
226
226
|
#ifdef HAS_ALPHA
|
|
227
|
-
mat.alpha =
|
|
227
|
+
mat.alpha = pg.r;
|
|
228
228
|
#else
|
|
229
229
|
mat.alpha = 1.0;
|
|
230
230
|
#endif
|
|
231
231
|
|
|
232
232
|
#ifdef NUM_DIFFUSE_MAPS
|
|
233
|
-
int diffuseMapIndex = int(
|
|
233
|
+
int diffuseMapIndex = int(gG.z);
|
|
234
234
|
if (diffuseMapIndex >= 0) {
|
|
235
235
|
vec4 diffuse = sampleMap(
|
|
236
236
|
diffuseMapIndex, getMapUvSet(diffuseMapIndex, uv, uv1)
|
|
@@ -251,21 +251,21 @@ mat.alpha *= diffuse.a;
|
|
|
251
251
|
|
|
252
252
|
${simpleTextureSample('alphaMap', 'glsl')}
|
|
253
253
|
|
|
254
|
-
mat.alpha =
|
|
255
|
-
mat.alpha, int(fetchMatData(i + MAT_ROW_ALPHA).w),
|
|
254
|
+
mat.alpha = mB(
|
|
255
|
+
mat.alpha, int(fetchMatData(i + MAT_ROW_ALPHA).w), pf.w
|
|
256
256
|
);
|
|
257
257
|
|
|
258
258
|
${simpleTextureSample('transmissionMap', 'glsl')}
|
|
259
259
|
|
|
260
260
|
#ifdef NUM_METALLIC_ROUGHNESS_MAPS
|
|
261
|
-
int metallicRoughnessMapIndex = int(
|
|
261
|
+
int metallicRoughnessMapIndex = int(gG.w);
|
|
262
262
|
if (metallicRoughnessMapIndex >= 0) {
|
|
263
|
-
vec4
|
|
263
|
+
vec4 ga = sampleMap(
|
|
264
264
|
metallicRoughnessMapIndex,
|
|
265
265
|
getMapUvSet(metallicRoughnessMapIndex, uv, uv1)
|
|
266
266
|
);
|
|
267
|
-
mat.baseMetalness *=
|
|
268
|
-
mat.specularRoughness *=
|
|
267
|
+
mat.baseMetalness *= ga.b;
|
|
268
|
+
mat.specularRoughness *= ga.g;
|
|
269
269
|
}
|
|
270
270
|
#endif
|
|
271
271
|
|
|
@@ -274,7 +274,7 @@ ${simpleTextureSample('roughnessMap', 'glsl')}
|
|
|
274
274
|
${simpleTextureSample('metalnessMap', 'glsl')}
|
|
275
275
|
|
|
276
276
|
#ifdef NUM_EMISSIVE_MAPS
|
|
277
|
-
int emissiveMapIndex = int(
|
|
277
|
+
int emissiveMapIndex = int(ig.w);
|
|
278
278
|
if (emissiveMapIndex >= 0) {
|
|
279
279
|
vec3 emissive = sampleMap(
|
|
280
280
|
emissiveMapIndex, getMapUvSet(emissiveMapIndex, uv, uv1)
|
|
@@ -284,12 +284,12 @@ mat.emission *= decodeMapColor(emissiveMapIndex, emissive);
|
|
|
284
284
|
#endif
|
|
285
285
|
|
|
286
286
|
#ifdef NUM_COAT_WEIGHT_MAPS
|
|
287
|
-
int
|
|
288
|
-
if (
|
|
289
|
-
float
|
|
290
|
-
|
|
287
|
+
int iu = int(fetchMatData(i + MAT_ROW_LAYER_MAPS).x);
|
|
288
|
+
if (iu >= 0 && mat.materialType == 0) {
|
|
289
|
+
float sK = clamp(coat.w, 0.0, 1.0) * sampleMap(
|
|
290
|
+
iu, getMapUvSet(iu, uv, uv1)
|
|
291
291
|
).r;
|
|
292
|
-
mat.emission *= mix(vec3(1.0), sqrt(max(coat.rgb, vec3(0.0))),
|
|
292
|
+
mat.emission *= mix(vec3(1.0), sqrt(max(coat.rgb, vec3(0.0))), sK);
|
|
293
293
|
}
|
|
294
294
|
#endif
|
|
295
295
|
|
|
@@ -311,29 +311,29 @@ ${simpleTextureSample('specularWeightMap', 'glsl')}
|
|
|
311
311
|
|
|
312
312
|
${simpleTextureSample('specularColorMap', 'glsl')}
|
|
313
313
|
|
|
314
|
-
vec4
|
|
314
|
+
vec4 mg = fetchMatData(i + MAT_ROW_DIRECTION_NORMAL);
|
|
315
315
|
mat.anisotropyDirection = vec2(1.0, 0.0);
|
|
316
|
-
mat.anisotropyDirectionEnabled =
|
|
316
|
+
mat.anisotropyDirectionEnabled = mg.y != 0.0;
|
|
317
317
|
mat.coatAnisotropyRotation = fetchMatData(i + MAT_ROW_FILM_TEXTURE).x;
|
|
318
318
|
#ifdef NUM_ANISOTROPY_MAPS
|
|
319
|
-
if (
|
|
320
|
-
int index = int(
|
|
321
|
-
vec4
|
|
322
|
-
mat.specularAnisotropy *=
|
|
323
|
-
vec2 direction =
|
|
319
|
+
if (mg.x >= 0.0) {
|
|
320
|
+
int index = int(mg.x);
|
|
321
|
+
vec4 texel = sampleMap(index, getMapUvSet(index, uv, uv1));
|
|
322
|
+
mat.specularAnisotropy *= texel.b;
|
|
323
|
+
vec2 direction = texel.rg * 2.0 - 1.0;
|
|
324
324
|
if (dot(direction, direction) > 1e-4) mat.anisotropyDirection = normalize(direction);
|
|
325
325
|
mat.anisotropyDirectionEnabled = true;
|
|
326
326
|
}
|
|
327
327
|
#endif
|
|
328
328
|
#ifdef HAS_GLTF_ANISOTROPY
|
|
329
329
|
if (fetchMatData(i + MAT_ROW_FILM_TEXTURE).y > 0.5 && mat.specularAnisotropy > 0.0) {
|
|
330
|
-
vec2
|
|
331
|
-
mat.specularRoughness =
|
|
332
|
-
mat.specularAnisotropy =
|
|
330
|
+
vec2 vG = fl(clamp(mat.specularRoughness, 0.0, 1.0), mat.specularAnisotropy);
|
|
331
|
+
mat.specularRoughness = vG.x;
|
|
332
|
+
mat.specularAnisotropy = vG.y;
|
|
333
333
|
}
|
|
334
334
|
#endif
|
|
335
335
|
if (mat.anisotropyDirectionEnabled) {
|
|
336
|
-
float theta =
|
|
336
|
+
float theta = mg.y;
|
|
337
337
|
vec2 d = mat.anisotropyDirection;
|
|
338
338
|
mat.anisotropyDirection = vec2(cos(theta)*d.x - sin(theta)*d.y, sin(theta)*d.x + cos(theta)*d.y);
|
|
339
339
|
}
|
|
@@ -341,12 +341,12 @@ mat.anisotropyDirection = vec2(cos(theta)*d.x - sin(theta)*d.y, sin(theta)*d.x +
|
|
|
341
341
|
|
|
342
342
|
|
|
343
343
|
if (mat.coatWeight > 0.0 && mat.coatRoughness > 0.0) {
|
|
344
|
-
float
|
|
345
|
-
float
|
|
344
|
+
float im = mat.specularRoughness * mat.specularRoughness;
|
|
345
|
+
float iq = mat.coatRoughness * mat.coatRoughness;
|
|
346
346
|
mat.specularRoughness = mix(mat.specularRoughness,
|
|
347
|
-
pow(min(1.0,
|
|
347
|
+
pow(min(1.0, im * im + 2.0 * iq * iq), 0.25), mat.coatWeight);
|
|
348
348
|
}
|
|
349
|
-
vec3 color =
|
|
349
|
+
vec3 color = lO(instanceIndex) * vertexColor;
|
|
350
350
|
mat.baseColor *= color;
|
|
351
351
|
if (mat.materialType == UNLIT) mat.emission *= color;
|
|
352
352
|
|
|
@@ -358,7 +358,7 @@ mat.alphaY = specularAlpha.y;
|
|
|
358
358
|
}
|
|
359
359
|
|
|
360
360
|
#if defined(NUM_NORMAL_MAPS)
|
|
361
|
-
vec3
|
|
361
|
+
vec3 qa(int materialIndex, vec2 uv, vec3 normal, vec3 dp1, vec3 dp2, vec2 pU, vec2 pV) {
|
|
362
362
|
int i = materialIndex * MAT_DATA_SIZE;
|
|
363
363
|
vec4 roughnessAndNormal = fetchMatData(i + MAT_ROW_ROUGHNESS_NORMAL);
|
|
364
364
|
int normalMapIndex = int(roughnessAndNormal.y);
|
|
@@ -366,32 +366,32 @@ if (normalMapIndex >= 0) {
|
|
|
366
366
|
|
|
367
367
|
|
|
368
368
|
|
|
369
|
-
vec3
|
|
370
|
-
vec3
|
|
371
|
-
vec3 dpdu =
|
|
372
|
-
vec3
|
|
373
|
-
float
|
|
374
|
-
if (
|
|
375
|
-
float
|
|
376
|
-
dpdu *=
|
|
377
|
-
|
|
369
|
+
vec3 tu = cross(dp2, normal);
|
|
370
|
+
vec3 tq = cross(normal, dp1);
|
|
371
|
+
vec3 dpdu = tu * pU.x + tq * pV.x;
|
|
372
|
+
vec3 vl = tu * pU.y + tq * pV.y;
|
|
373
|
+
float dZ = max(dot(dpdu, dpdu), dot(vl, vl));
|
|
374
|
+
if (dZ > 1e-12) {
|
|
375
|
+
float vw = inversesqrt(dZ);
|
|
376
|
+
dpdu *= vw;
|
|
377
|
+
vl *= vw;
|
|
378
378
|
}
|
|
379
379
|
else {
|
|
380
380
|
|
|
381
381
|
|
|
382
382
|
|
|
383
|
-
vec3
|
|
383
|
+
vec3 pa = abs(normal.z) < 0.999
|
|
384
384
|
? vec3(0.0, 0.0, 1.0)
|
|
385
385
|
: vec3(0.0, 1.0, 0.0);
|
|
386
|
-
dpdu = normalize(cross(
|
|
387
|
-
|
|
386
|
+
dpdu = normalize(cross(pa, normal));
|
|
387
|
+
vl = cross(normal, dpdu);
|
|
388
388
|
}
|
|
389
389
|
|
|
390
390
|
vec3 n = 2.0 * sampleMap(normalMapIndex, uv).rgb - 1.0;
|
|
391
391
|
n.xy *= roughnessAndNormal.zw;
|
|
392
392
|
n = normalize(n);
|
|
393
393
|
|
|
394
|
-
mat3 tbn = mat3(dpdu,
|
|
394
|
+
mat3 tbn = mat3(dpdu, vl, normal);
|
|
395
395
|
|
|
396
396
|
return normalize(tbn * n);
|
|
397
397
|
} else {
|