@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,32 +1,34 @@
|
|
|
1
1
|
// Estimate the direct lighting integral using multiple importance sampling
|
|
2
2
|
// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral
|
|
3
3
|
import { glsl } from '../../shader.js';
|
|
4
|
-
export function createSampleMaterialGlsl(fragments = {}) {
|
|
4
|
+
export function createSampleMaterialGlsl(fragments = {}, channelIndependentLight = false) {
|
|
5
5
|
return glsl `
|
|
6
6
|
float emissiveHitMisWeight(SurfaceInteraction si,Path path) {
|
|
7
7
|
|
|
8
|
-
float
|
|
9
|
-
if(
|
|
8
|
+
float Ar=dot(si.faceNormal,-path.ray.d);
|
|
9
|
+
if(Ar<=0.0&&fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_ALPHA).z<0.5)return 0.0;
|
|
10
10
|
#ifdef HAS_EMISSIVE_LIGHTS
|
|
11
11
|
if(!path.fromEye && emissiveWeightTotal>0.0) {
|
|
12
12
|
vec3 emission=fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_EMISSION).rgb;
|
|
13
13
|
float value=dot(emission,vec3(.2126,.7152,.0722)),cosine=dot(si.faceNormal,-path.ray.d);
|
|
14
|
-
if(value>0.0&&cosine>0.0){float d=distance(si.position,path.ray.o);return
|
|
14
|
+
if(value>0.0&&cosine>0.0){float d=distance(si.position,path.ray.o);return aG(path.scatteringPdf,value/emissiveWeightTotal*d*d/cosine);}
|
|
15
15
|
}
|
|
16
16
|
#endif
|
|
17
17
|
return 1.0;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
vec3
|
|
21
|
-
float
|
|
22
|
-
vec3
|
|
20
|
+
vec3 qY(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {
|
|
21
|
+
float mz = 1.0;
|
|
22
|
+
vec3 ob = vec3(sample2D(aX(LIGHT_POSITION)), sample1D(aX(LIGHT_SELECT)));
|
|
23
23
|
|
|
24
24
|
LightSampleRec lightSample;
|
|
25
|
-
sampleLight(si.position,
|
|
25
|
+
sampleLight(si.position, ob, lightSample, false);${fragments['sample0'] ?? ''}
|
|
26
|
+
${channelIndependentLight ? /* glsl */ ` if (dispersionWavelengths == 1) {
|
|
26
27
|
lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);
|
|
28
|
+
}` : /* glsl */ ` lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);`}
|
|
27
29
|
|
|
28
30
|
vec3 lightDir = lightSample.direction;
|
|
29
|
-
vec3
|
|
31
|
+
vec3 sg = -path.ray.d;
|
|
30
32
|
float lightPdf = lightSample.pdf;
|
|
31
33
|
|
|
32
34
|
|
|
@@ -41,7 +43,12 @@ if (lightPdf <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y),
|
|
|
41
43
|
return vec3(0.0);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
${channelIndependentLight ? /* glsl */ `
|
|
47
|
+
|
|
48
|
+
if (dispersionWavelengths != 1) {
|
|
49
|
+
lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);
|
|
50
|
+
}
|
|
51
|
+
` : ''} float scatteringPdf = 0.0;
|
|
45
52
|
vec3 f = vec3(0.0);
|
|
46
53
|
if (isSurface) {
|
|
47
54
|
if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {
|
|
@@ -50,8 +57,8 @@ return vec3(0.0);
|
|
|
50
57
|
f = openpbr_eval_prepared(prepared, lightDir, scatteringPdf);
|
|
51
58
|
}
|
|
52
59
|
else {
|
|
53
|
-
scatteringPdf =
|
|
54
|
-
dot(
|
|
60
|
+
scatteringPdf = ba(
|
|
61
|
+
dot(sg, lightDir),
|
|
55
62
|
si.mediumAnisotropy
|
|
56
63
|
);
|
|
57
64
|
f = vec3(scatteringPdf);
|
|
@@ -61,34 +68,34 @@ if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {
|
|
|
61
68
|
return vec3(0.0);
|
|
62
69
|
}
|
|
63
70
|
|
|
64
|
-
Ray
|
|
65
|
-
vec3
|
|
71
|
+
Ray oa;
|
|
72
|
+
vec3 eY = si.position + EPS * lightDir;
|
|
66
73
|
if (isSurface) {
|
|
67
74
|
const float shadowTerminatorCutoff = 0.1;
|
|
68
|
-
float
|
|
75
|
+
float dl = dot(si.normal, lightDir);
|
|
69
76
|
#ifdef USE_COAT_NORMAL_FRAMES
|
|
70
|
-
if (mat.coatNormalEnabled) {
|
|
77
|
+
if (mat.coatNormalEnabled) { dl = dot(si.faceNormal, lightDir); }
|
|
71
78
|
#endif
|
|
72
|
-
vec3 geometricNormal =
|
|
73
|
-
|
|
74
|
-
float
|
|
75
|
-
float
|
|
79
|
+
vec3 geometricNormal = dl < 0.0 ? -si.faceNormal : si.faceNormal;
|
|
80
|
+
dl = abs(dl);
|
|
81
|
+
float iw = dot(geometricNormal, lightDir);
|
|
82
|
+
float qo = dl < shadowTerminatorCutoff
|
|
76
83
|
? clamp(
|
|
77
|
-
2.0 - (
|
|
84
|
+
2.0 - (iw + dl) / shadowTerminatorCutoff,
|
|
78
85
|
0.0,
|
|
79
86
|
1.0
|
|
80
87
|
)
|
|
81
|
-
: clamp(1.0 -
|
|
82
|
-
|
|
88
|
+
: clamp(1.0 - iw / shadowTerminatorCutoff, 0.0, 1.0);
|
|
89
|
+
eY += si.shadowOffset * qo;
|
|
83
90
|
}
|
|
84
|
-
float
|
|
85
|
-
vec3
|
|
91
|
+
float rM=lightSample.dist-EPS;
|
|
92
|
+
vec3 qS=lightDir;
|
|
86
93
|
if(lightSample.sourceType==1){
|
|
87
94
|
vec3 endpoint=si.position+lightDir*lightSample.dist+EPS*lightSample.normal;
|
|
88
|
-
|
|
95
|
+
qS=normalize(endpoint-eY);rM=distance(endpoint,eY);
|
|
89
96
|
}
|
|
90
|
-
initRay(
|
|
91
|
-
if (intersectSceneShadow(
|
|
97
|
+
initRay(oa, eY, qS);
|
|
98
|
+
if (intersectSceneShadow(oa, rM, si.triangleIndex)) {
|
|
92
99
|
return vec3(0.0);
|
|
93
100
|
}
|
|
94
101
|
|
|
@@ -96,7 +103,7 @@ return vec3(0.0);
|
|
|
96
103
|
|
|
97
104
|
|
|
98
105
|
if (isSurface && cosThetaL < 0.0 && lightSample.sourceType == 0) {
|
|
99
|
-
vec4 background =
|
|
106
|
+
vec4 background = cq(oa.o, lightDir);
|
|
100
107
|
lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.a, pathChannel);
|
|
101
108
|
}
|
|
102
109
|
#endif
|
|
@@ -105,45 +112,45 @@ lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.
|
|
|
105
112
|
|
|
106
113
|
float misWeight = lightSample.isDelta
|
|
107
114
|
? 1.0
|
|
108
|
-
:
|
|
115
|
+
: aG(lightPdf, scatteringPdf);
|
|
109
116
|
${fragments['sample1'] ?? ''} return misWeight > 0.0
|
|
110
117
|
? misWeight * lightSample.emission * f / lightPdf
|
|
111
118
|
: vec3(0.0);
|
|
112
119
|
}
|
|
113
120
|
|
|
114
121
|
#ifdef USE_COAT_NORMAL_FRAMES
|
|
115
|
-
vec3
|
|
122
|
+
vec3 fQ(vec3 ru, vec3 face, vec3 view) {
|
|
116
123
|
bool front = dot(face, view) >= 0.0;
|
|
117
|
-
vec3
|
|
118
|
-
vec3
|
|
119
|
-
if (dot(
|
|
120
|
-
return
|
|
124
|
+
vec3 yc = front ? face : -face;
|
|
125
|
+
vec3 tv = front ? ru : -ru;
|
|
126
|
+
if (dot(ru, face) <= 0.0 || dot(tv, view) <= 1e-6) { return yc; }
|
|
127
|
+
return tv;
|
|
121
128
|
}
|
|
122
129
|
#endif
|
|
123
|
-
void
|
|
124
|
-
vec3
|
|
130
|
+
void nB(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {
|
|
131
|
+
vec3 yh = vec3(sample2D(aX(BSDF_DIRECTION)), sample1D(aX(BSDF_LOBE)));
|
|
125
132
|
#ifdef USE_COAT_NORMAL_FRAMES
|
|
126
|
-
vec3
|
|
127
|
-
vec3
|
|
133
|
+
vec3 bC = si.faceNormal;
|
|
134
|
+
vec3 oh = si.normal;
|
|
128
135
|
#endif
|
|
129
|
-
float
|
|
130
|
-
float
|
|
136
|
+
float uk = -dot(si.faceNormal, path.ray.d);
|
|
137
|
+
float vH = -dot(si.normal, path.ray.d);
|
|
131
138
|
if ((mat.transmissionWeight > 0.0 || mat.subsurfaceWeight > 0.0) && mat.thinWalled) {
|
|
132
139
|
|
|
133
|
-
if (
|
|
140
|
+
if (uk < 0.0) {
|
|
134
141
|
si.faceNormal = -si.faceNormal;
|
|
135
|
-
|
|
142
|
+
uk = -uk;
|
|
136
143
|
}
|
|
137
|
-
if (
|
|
144
|
+
if (vH < 0.0) {
|
|
138
145
|
si.normal = -si.normal;
|
|
139
|
-
|
|
146
|
+
vH = -vH;
|
|
140
147
|
}
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
|
|
144
|
-
bool
|
|
145
|
-
float ndv =
|
|
146
|
-
vec3 normal =
|
|
151
|
+
bool rS = uk >= 0.0 && vH < 0.0;
|
|
152
|
+
float ndv = rS ? uk : vH;
|
|
153
|
+
vec3 normal = rS ? si.faceNormal : si.normal;
|
|
147
154
|
|
|
148
155
|
mat.inside = ndv <= 0.0 && !mat.thinWalled;
|
|
149
156
|
|
|
@@ -152,96 +159,105 @@ vec3 ffnormal = ndv >= 0.0 ? normal : -normal;
|
|
|
152
159
|
#ifdef USE_COAT_NORMAL_FRAMES
|
|
153
160
|
if (mat.coatNormalEnabled) {
|
|
154
161
|
vec3 view = -path.ray.d;
|
|
155
|
-
float
|
|
156
|
-
mat.geometricNormal =
|
|
157
|
-
ffnormal =
|
|
158
|
-
mat.coatNormal =
|
|
159
|
-
mat.inside =
|
|
160
|
-
mat.relativeIor = (
|
|
162
|
+
float gr = dot(bC, view);
|
|
163
|
+
mat.geometricNormal = gr >= 0.0 ? bC : -bC;
|
|
164
|
+
ffnormal = fQ(oh, bC, view);
|
|
165
|
+
mat.coatNormal = fQ(si.coatNormal, bC, view);
|
|
166
|
+
mat.inside = gr <= 0.0 && !mat.thinWalled;
|
|
167
|
+
mat.relativeIor = (gr > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;
|
|
161
168
|
}
|
|
162
169
|
#endif
|
|
163
170
|
|
|
164
171
|
|
|
165
172
|
float scatteringPdf;
|
|
166
|
-
vec3
|
|
173
|
+
vec3 di;
|
|
167
174
|
path.scatteringIsDelta = false;
|
|
168
175
|
bool mediumSampled = false;
|
|
169
|
-
bool
|
|
176
|
+
bool hE = false;
|
|
170
177
|
OpenPbrPreparedBsdf prepared;
|
|
171
178
|
|
|
172
179
|
#ifdef HAS_MEDIUM
|
|
173
180
|
int mediumType = si.mediumType;
|
|
174
181
|
float d = distance(si.position, path.ray.o);
|
|
175
|
-
vec3
|
|
182
|
+
vec3 pd = path.ray.o;
|
|
176
183
|
vec3 extinction = si.mediumExtinction;
|
|
177
184
|
vec3 scattering = min(si.mediumScattering, extinction);
|
|
178
|
-
float
|
|
179
|
-
if (mediumType > 0 &&
|
|
185
|
+
float vD = max(max(extinction.x, extinction.y), extinction.z);
|
|
186
|
+
if (mediumType > 0 && vD > 0.0) {
|
|
180
187
|
|
|
181
188
|
|
|
182
189
|
|
|
183
190
|
|
|
184
|
-
int
|
|
185
|
-
float
|
|
186
|
-
float
|
|
187
|
-
? min(-log(max(sample1D(
|
|
191
|
+
int oW = min(int(sample1D(aX(MEDIUM_CHANNEL)) * 3.0), 2);
|
|
192
|
+
float fP = extinction[oW];
|
|
193
|
+
float iO = fP > 0.0
|
|
194
|
+
? min(-log(max(sample1D(aX(MEDIUM_DISTANCE)), 1e-7)) / fP, d)
|
|
188
195
|
: d;
|
|
189
|
-
mediumSampled =
|
|
190
|
-
vec3 transmittance = exp(-extinction *
|
|
191
|
-
vec3
|
|
196
|
+
mediumSampled = iO < d;
|
|
197
|
+
vec3 transmittance = exp(-extinction * iO);
|
|
198
|
+
vec3 density = mediumSampled
|
|
192
199
|
? extinction * transmittance
|
|
193
200
|
: transmittance;
|
|
194
201
|
float mediumPdf = max(
|
|
195
|
-
(
|
|
202
|
+
(density.x + density.y + density.z) / 3.0,
|
|
196
203
|
1e-8
|
|
197
204
|
);
|
|
198
205
|
if (mediumSampled) {
|
|
199
206
|
path.beta *= transmittance * scattering / mediumPdf;
|
|
200
207
|
|
|
201
|
-
path.
|
|
208
|
+
if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }
|
|
209
|
+
|
|
210
|
+
path.ray.o = pd + iO * path.ray.d;
|
|
202
211
|
si.position = path.ray.o;
|
|
203
|
-
path.li += sX(si, mat, prepared, path, ffnormal, false) * path.beta;
|
|
204
212
|
|
|
213
|
+
si.triangleIndex = -1;
|
|
214
|
+
si.instanceIndex = -1;
|
|
215
|
+
path.li += qY(si, mat, prepared, path, ffnormal, false) * path.beta;
|
|
205
216
|
|
|
206
|
-
|
|
217
|
+
|
|
218
|
+
di = dQ(
|
|
207
219
|
-path.ray.d,
|
|
208
220
|
si.mediumAnisotropy,
|
|
209
|
-
sample2D(
|
|
221
|
+
sample2D(aX(PHASE_DIRECTION))
|
|
210
222
|
);
|
|
211
|
-
scatteringPdf =
|
|
212
|
-
dot(
|
|
223
|
+
scatteringPdf = ba(
|
|
224
|
+
dot(di, -path.ray.d),
|
|
213
225
|
si.mediumAnisotropy
|
|
214
226
|
);
|
|
215
227
|
}
|
|
216
228
|
else {
|
|
217
229
|
path.beta *= transmittance / mediumPdf;
|
|
230
|
+
|
|
231
|
+
if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }
|
|
218
232
|
}
|
|
219
233
|
}
|
|
220
234
|
#endif
|
|
221
235
|
|
|
222
236
|
|
|
223
237
|
if (!mediumSampled) {
|
|
224
|
-
|
|
238
|
+
|
|
239
|
+
vec3 surfaceEmission = sampling_spectral_rgb_filter(mat.emission, pathChannel);
|
|
240
|
+
${fragments['sample2'] ?? ''}path.li += emissiveHitMisWeight(si,path) * surfaceEmission * path.beta;${fragments['sample3'] ?? ''}
|
|
225
241
|
if (mat.materialType == UNLIT) {
|
|
226
242
|
path.abort = true;
|
|
227
243
|
return;
|
|
228
244
|
}
|
|
229
|
-
vec3
|
|
245
|
+
vec3 rP = vec3(0.0);
|
|
230
246
|
#ifdef USE_TANGENT
|
|
231
|
-
|
|
247
|
+
rP = si.tangent;
|
|
232
248
|
#endif
|
|
233
249
|
mat.directionTangent = si.directionTangent;
|
|
234
250
|
mat.directionBitangent = si.directionBitangent;
|
|
235
251
|
mat.geometryTangent = si.geometryTangent;
|
|
236
252
|
mat.geometryBitangent = si.geometryBitangent;
|
|
237
|
-
prepared =
|
|
238
|
-
path.li +=
|
|
253
|
+
prepared = bX(rP, mat, -path.ray.d, ffnormal);
|
|
254
|
+
path.li += qY(si, mat, prepared, path, ffnormal, true) * path.beta;
|
|
239
255
|
${fragments['sample4'] ?? ''}
|
|
240
256
|
bool isNextRefraction;
|
|
241
|
-
vec3 f =
|
|
257
|
+
vec3 f = dr(
|
|
242
258
|
prepared,
|
|
243
|
-
|
|
244
|
-
|
|
259
|
+
yh,
|
|
260
|
+
di,
|
|
245
261
|
scatteringPdf,
|
|
246
262
|
isNextRefraction
|
|
247
263
|
);
|
|
@@ -253,25 +269,27 @@ prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6;
|
|
|
253
269
|
|
|
254
270
|
|
|
255
271
|
if (!(scatteringPdf > 0.0) || any(isnan(f)) || any(isinf(f)) ||
|
|
256
|
-
dot(
|
|
272
|
+
dot(di, di) < 0.5) {
|
|
257
273
|
path.scatteringPdf = 0.0;
|
|
258
274
|
path.abort = true;
|
|
259
275
|
return;
|
|
260
276
|
}
|
|
261
277
|
${fragments['sample5'] ?? ''} path.beta *= f / scatteringPdf;
|
|
262
|
-
|
|
278
|
+
|
|
279
|
+
if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }
|
|
280
|
+
hE = !mat.thinWalled &&
|
|
263
281
|
isNextRefraction;
|
|
264
282
|
path.isNextRefraction = isNextRefraction;
|
|
265
283
|
|
|
266
284
|
|
|
267
|
-
path.ray.o = si.position + EPS *
|
|
285
|
+
path.ray.o = si.position + EPS * di;
|
|
268
286
|
#ifdef USE_COAT_NORMAL_FRAMES
|
|
269
|
-
if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(
|
|
287
|
+
if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(bC, di) >= 0.0 ? bC : -bC); }
|
|
270
288
|
#endif
|
|
271
289
|
}
|
|
272
290
|
|
|
273
291
|
path.scatteringPdf = scatteringPdf;
|
|
274
|
-
initRay(path.ray, path.ray.o,
|
|
292
|
+
initRay(path.ray, path.ray.o, di);
|
|
275
293
|
if (mediumSampled) {${fragments['sample6'] ?? ''}
|
|
276
294
|
path.isNextRefraction = false;
|
|
277
295
|
}
|
|
@@ -280,11 +298,12 @@ path.fromEye = false;
|
|
|
280
298
|
#ifdef HAS_MEDIUM
|
|
281
299
|
|
|
282
300
|
|
|
283
|
-
if (!mediumSampled &&
|
|
284
|
-
if (
|
|
301
|
+
if (!mediumSampled && hE && mat.mediumType > 0) {
|
|
302
|
+
if (uk >= 0.0) {
|
|
285
303
|
si.mediumType = mat.mediumType;
|
|
286
304
|
si.mediumExtinction = mat.mediumExtinction;
|
|
287
305
|
si.mediumScattering = mat.mediumScattering;
|
|
306
|
+
path.scatteringMediumEntered = path.scatteringMediumEntered || any(greaterThan(mat.mediumScattering, vec3(0.0)));
|
|
288
307
|
si.mediumAnisotropy = mat.mediumAnisotropy;
|
|
289
308
|
}
|
|
290
309
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sampleMaterial.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/sampleMaterial.glsl.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,iIAAiI;AAEjI,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,MAAM,UAAU,wBAAwB,CAAC,YAA8C,EAAE;IAAI,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;mDAoB7C,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoFnF,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmHtB,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,uEAAuE,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;EAe/H,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;EAsB1B,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;sBAcJ,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;CAwBjD,CAAC;AACF,CAAC;AACD,eAAe,wBAAwB,EAAE,CAAC","sourcesContent":["// Estimate the direct lighting integral using multiple importance sampling\n// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral\n\nimport { glsl } from '../../shader.js';\nexport function createSampleMaterialGlsl(fragments: Readonly<Record<string, string>> = {}) { return glsl`\nfloat emissiveHitMisWeight(SurfaceInteraction si,Path path) {\n // Secondary intersections remain two-sided, but one-sided emission does not.\n float facing=dot(si.faceNormal,-path.ray.d);\n if(facing<=0.0&&fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_ALPHA).z<0.5)return 0.0;\n#ifdef HAS_EMISSIVE_LIGHTS\n if(!path.fromEye && emissiveWeightTotal>0.0) {\n vec3 emission=fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_EMISSION).rgb;\n float value=dot(emission,vec3(.2126,.7152,.0722)),cosine=dot(si.faceNormal,-path.ray.d);\n if(value>0.0&&cosine>0.0){float d=distance(si.position,path.ray.o);return sampling_power_heuristic(path.scatteringPdf,value/emissiveWeightTotal*d*d/cosine);}\n }\n#endif\n return 1.0;\n}\n\nvec3 DirectLight(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {\n float occluded = 1.0;\n vec3 lightRnd = vec3(sample2D(bounceDim(LIGHT_POSITION)), sample1D(bounceDim(LIGHT_SELECT)));\n\n LightSampleRec lightSample;\n sampleLight(si.position, lightRnd, lightSample, false);${fragments['sample0'] ?? ''}\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);\n\n vec3 lightDir = lightSample.direction;\n vec3 viewDir = -path.ray.d;\n float lightPdf = lightSample.pdf;\n // Opaque surfaces are rendered two-sided by the core renderer. Use the\n // face-forward shading normal here as well, otherwise the early-out rejects\n // every direct-light sample seen from the back of a triangle (for example\n // the inside of an imported room wall).\n float cosThetaL = dot(ffnormal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (isSurface && mat.coatNormalEnabled) { cosThetaL = dot(mat.geometricNormal, lightDir); }\n#endif\n\n if (lightPdf <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y), lightSample.emission.z) <= 0.0) {\n return vec3(0.0);\n }\n\n float scatteringPdf = 0.0;\n vec3 f = vec3(0.0);\n if (isSurface) {\n if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {\n return vec3(0.0);\n }\n f = openpbr_eval_prepared(prepared, lightDir, scatteringPdf);\n }\n else {\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(viewDir, lightDir),\n si.mediumAnisotropy\n );\n f = vec3(scatteringPdf);\n }\n\n if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {\n return vec3(0.0);\n }\n\n Ray lightRay;\n vec3 shadowOrigin = si.position + EPS * lightDir;\n if (isSurface) {\n const float shadowTerminatorCutoff = 0.1;\n float normalLight = dot(si.normal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { normalLight = dot(si.faceNormal, lightDir); }\n#endif\n vec3 geometricNormal = normalLight < 0.0 ? -si.faceNormal : si.faceNormal;\n normalLight = abs(normalLight);\n float geometricLight = dot(geometricNormal, lightDir);\n float offsetAmount = normalLight < shadowTerminatorCutoff\n ? clamp(\n 2.0 - (geometricLight + normalLight) / shadowTerminatorCutoff,\n 0.0,\n 1.0\n )\n : clamp(1.0 - geometricLight / shadowTerminatorCutoff, 0.0, 1.0);\n shadowOrigin += si.shadowOffset * offsetAmount;\n }\n float shadowDistance=lightSample.dist-EPS;\n vec3 shadowDirection=lightDir;\n if(lightSample.sourceType==1){\n vec3 endpoint=si.position+lightDir*lightSample.dist+EPS*lightSample.normal;\n shadowDirection=normalize(endpoint-shadowOrigin);shadowDistance=distance(endpoint,shadowOrigin);\n }\n initRay(lightRay, shadowOrigin, shadowDirection);\n if (intersectSceneShadow(lightRay, shadowDistance, si.triangleIndex)) {\n return vec3(0.0);\n }\n\n#ifdef USE_ENVMAP\n // Match the endpoint used by a BSDF-sampled surface transmission, including\n // a separately displayed or grounded background and its coverage.\n if (isSurface && cosThetaL < 0.0 && lightSample.sourceType == 0) {\n vec4 background = sampleBackgroundFromRay(lightRay.o, lightDir);\n lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.a, pathChannel);\n }\n#endif\n\n // Delta lights cannot be sampled by the BSDF strategy, so their MIS weight\n // is exactly one even when their light-selection PMF is small.\n float misWeight = lightSample.isDelta\n ? 1.0\n : sampling_power_heuristic(lightPdf, scatteringPdf);\n${fragments['sample1'] ?? ''} return misWeight > 0.0\n ? misWeight * lightSample.emission * f / lightPdf\n : vec3(0.0);\n}\n\n#ifdef USE_COAT_NORMAL_FRAMES\nvec3 coat_frame_normal(vec3 inputNormal, vec3 face, vec3 view) {\n bool front = dot(face, view) >= 0.0;\n vec3 ffFace = front ? face : -face;\n vec3 ffInput = front ? inputNormal : -inputNormal;\n if (dot(inputNormal, face) <= 0.0 || dot(ffInput, view) <= 1e-6) { return ffFace; }\n return ffInput;\n}\n#endif\nvoid SampleMaterial(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {\n vec3 matRnd = vec3(sample2D(bounceDim(BSDF_DIRECTION)), sample1D(bounceDim(BSDF_LOBE)));\n#ifdef USE_COAT_NORMAL_FRAMES\n vec3 originalFace = si.faceNormal;\n vec3 originalNormal = si.normal;\n#endif\n float ndv1 = -dot(si.faceNormal, path.ray.d);\n float ndv2 = -dot(si.normal, path.ray.d);\n if ((mat.transmissionWeight > 0.0 || mat.subsurfaceWeight > 0.0) && mat.thinWalled) {\n // Always treat thin material as entering medium\n if (ndv1 < 0.0) {\n si.faceNormal = -si.faceNormal;\n ndv1 = -ndv1;\n }\n if (ndv2 < 0.0) {\n si.normal = -si.normal;\n ndv2 = -ndv2;\n }\n }\n // In same edge cases normal is not torwards the camera while we can still see the face.\n // We need to choose faceNormal in this case.\n bool useFaceN = ndv1 >= 0.0 && ndv2 < 0.0;\n float ndv = useFaceN ? ndv1 : ndv2;\n vec3 normal = useFaceN ? si.faceNormal : si.normal;\n\n mat.inside = ndv <= 0.0 && !mat.thinWalled;\n // In or out\n mat.relativeIor = ndv > 0.0 ? (1.0 / mat.specularIor) : mat.specularIor;\n vec3 ffnormal = ndv >= 0.0 ? normal : -normal;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) {\n vec3 view = -path.ray.d;\n float geometricView = dot(originalFace, view);\n mat.geometricNormal = geometricView >= 0.0 ? originalFace : -originalFace;\n ffnormal = coat_frame_normal(originalNormal, originalFace, view);\n mat.coatNormal = coat_frame_normal(si.coatNormal, originalFace, view);\n mat.inside = geometricView <= 0.0 && !mat.thinWalled;\n mat.relativeIor = (geometricView > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;\n }\n#endif\n\n\n float scatteringPdf;\n vec3 scatterDir;\n path.scatteringIsDelta = false;\n bool mediumSampled = false;\n bool crossedBoundary = false;\n OpenPbrPreparedBsdf prepared;\n\n#ifdef HAS_MEDIUM\n int mediumType = si.mediumType;\n float d = distance(si.position, path.ray.o);\n vec3 segmentOrigin = path.ray.o;\n vec3 extinction = si.mediumExtinction;\n vec3 scattering = min(si.mediumScattering, extinction);\n float majorant = max(max(extinction.x, extinction.y), extinction.z);\n if (mediumType > 0 && majorant > 0.0) {\n // Sample one RGB extinction channel and divide by the mixture PDF. This\n // is the homogeneous-medium estimator used by PBRT and avoids the very\n // large exp((majorant - extinction) * distance) weights produced by\n // majorant tracking when OpenPBR SSS radii differ strongly by channel.\n int mediumChannel = min(int(sample1D(bounceDim(MEDIUM_CHANNEL)) * 3.0), 2);\n float channelExtinction = extinction[mediumChannel];\n float scatterDist = channelExtinction > 0.0\n ? min(-log(max(sample1D(bounceDim(MEDIUM_DISTANCE)), 1e-7)) / channelExtinction, d)\n : d;\n mediumSampled = scatterDist < d;\n vec3 transmittance = exp(-extinction * scatterDist);\n vec3 density = mediumSampled\n ? extinction * transmittance\n : transmittance;\n float mediumPdf = max(\n (density.x + density.y + density.z) / 3.0,\n 1e-8\n );\n if (mediumSampled) {\n path.beta *= transmittance * scattering / mediumPdf;\n // Move from the start of the segment, not from its end surface.\n path.ray.o = segmentOrigin + scatterDist * path.ray.d;\n si.position = path.ray.o;\n path.li += DirectLight(si, mat, prepared, path, ffnormal, false) * path.beta;\n\n // Pick a new direction based on the phase function\n scatterDir = sampling_henyey_greenstein(\n -path.ray.d,\n si.mediumAnisotropy,\n sample2D(bounceDim(PHASE_DIRECTION))\n );\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(scatterDir, -path.ray.d),\n si.mediumAnisotropy\n );\n }\n else {\n path.beta *= transmittance / mediumPdf;\n }\n }\n#endif\n\n // Direct lighting\n if (!mediumSampled) {\n ${fragments['sample2'] ?? ''}path.li += emissiveHitMisWeight(si,path) * mat.emission * path.beta;${fragments['sample3'] ?? ''}\n if (mat.materialType == UNLIT) {\n path.abort = true;\n return;\n }\n vec3 surfaceTangent = vec3(0.0);\n#ifdef USE_TANGENT\n surfaceTangent = si.tangent;\n#endif\n mat.directionTangent = si.directionTangent;\n mat.directionBitangent = si.directionBitangent;\n mat.geometryTangent = si.geometryTangent;\n mat.geometryBitangent = si.geometryBitangent;\n prepared = openpbr_prepare(surfaceTangent, mat, -path.ray.d, ffnormal);\n path.li += DirectLight(si, mat, prepared, path, ffnormal, true) * path.beta;\n${fragments['sample4'] ?? ''} // Sample BSDF for color and outgoing direction\n bool isNextRefraction;\n vec3 f = openpbr_sample_prepared(\n prepared,\n matRnd,\n scatterDir,\n scatteringPdf,\n isNextRefraction\n );\n // Null-boundary transmission is discrete and has no NEE competitor.\n path.scatteringIsDelta = !prepared.material.thinWalled &&\n abs(prepared.material.relativeIor - 1.0) <= 1e-6 &&\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6;\n // Match WebGPU: rejected VNDF/refraction proposals have no continuation.\n // Tracing their fallback direction with the incoming throughput invents\n // light paths, especially after total internal reflection inside glass.\n if (!(scatteringPdf > 0.0) || any(isnan(f)) || any(isinf(f)) ||\n dot(scatterDir, scatterDir) < 0.5) {\n path.scatteringPdf = 0.0;\n path.abort = true;\n return;\n }\n${fragments['sample5'] ?? ''} path.beta *= f / scatteringPdf;\n crossedBoundary = !mat.thinWalled &&\n isNextRefraction;\n path.isNextRefraction = isNextRefraction;\n // TODO prefer the opaque surface when transmission surface and opaque surface are overlapped.\n // Or the ray go out from transmission material will miss the opque surface.\n path.ray.o = si.position + EPS * scatterDir;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(originalFace, scatterDir) >= 0.0 ? originalFace : -originalFace); }\n#endif\n }\n\n path.scatteringPdf = scatteringPdf;\n initRay(path.ray, path.ray.o, scatterDir);\n if (mediumSampled) {${fragments['sample6'] ?? ''}\n path.isNextRefraction = false;\n }\n path.fromEye = false;\n\n#ifdef HAS_MEDIUM\n // A reflected ray stays in its current medium. Only a sampled transmission\n // event crosses the boundary of a medium-bearing closed mesh.\n if (!mediumSampled && crossedBoundary && mat.mediumType > 0) {\n if (ndv1 >= 0.0) {\n si.mediumType = mat.mediumType;\n si.mediumExtinction = mat.mediumExtinction;\n si.mediumScattering = mat.mediumScattering;\n si.mediumAnisotropy = mat.mediumAnisotropy;\n }\n else {\n si.mediumType = 0;\n si.mediumExtinction = vec3(0.0);\n si.mediumScattering = vec3(0.0);\n si.mediumAnisotropy = 0.0;\n }\n }\n#endif\n}\n`;\n}\nexport default createSampleMaterialGlsl();\n"]}
|
|
1
|
+
{"version":3,"file":"sampleMaterial.glsl.js","sourceRoot":"","sources":["../../../../src/renderer/glsl/chunks/sampleMaterial.glsl.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,iIAAiI;AAEjI,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,MAAM,UAAU,wBAAwB,CAAC,YAA8C,EAAE,EAAE,uBAAuB,GAAG,KAAK;IAAI,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;mDAoB9E,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;EACnF,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;EAEnC,CAAC,CAAC,CAAC,UAAU,CAAC,2FAA2F;;;;;;;;;;;;;;;;;;EAkB3G,uBAAuB,CAAC,CAAC,CAAC,UAAU,CAAC;;;;;CAKtC,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiEJ,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4HtB,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,0EAA0E,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;EAelI,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;EAsB1B,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;sBAgBJ,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;CAyBjD,CAAC;AACF,CAAC;AACD,eAAe,wBAAwB,EAAE,CAAC","sourcesContent":["// Estimate the direct lighting integral using multiple importance sampling\n// http://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/Direct_Lighting.html#EstimatingtheDirectLightingIntegral\n\nimport { glsl } from '../../shader.js';\nexport function createSampleMaterialGlsl(fragments: Readonly<Record<string, string>> = {}, channelIndependentLight = false) { return glsl`\nfloat emissiveHitMisWeight(SurfaceInteraction si,Path path) {\n // Secondary intersections remain two-sided, but one-sided emission does not.\n float facing=dot(si.faceNormal,-path.ray.d);\n if(facing<=0.0&&fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_ALPHA).z<0.5)return 0.0;\n#ifdef HAS_EMISSIVE_LIGHTS\n if(!path.fromEye && emissiveWeightTotal>0.0) {\n vec3 emission=fetchMatData(si.materialIndex*MAT_DATA_SIZE+MAT_ROW_EMISSION).rgb;\n float value=dot(emission,vec3(.2126,.7152,.0722)),cosine=dot(si.faceNormal,-path.ray.d);\n if(value>0.0&&cosine>0.0){float d=distance(si.position,path.ray.o);return sampling_power_heuristic(path.scatteringPdf,value/emissiveWeightTotal*d*d/cosine);}\n }\n#endif\n return 1.0;\n}\n\nvec3 DirectLight(SurfaceInteraction si, OpenPbrResolvedMaterial mat, OpenPbrPreparedBsdf prepared, inout Path path, vec3 ffnormal, bool isSurface) {\n float occluded = 1.0;\n vec3 lightRnd = vec3(sample2D(bounceDim(LIGHT_POSITION)), sample1D(bounceDim(LIGHT_SELECT)));\n\n LightSampleRec lightSample;\n sampleLight(si.position, lightRnd, lightSample, false);${fragments['sample0'] ?? ''}\n${channelIndependentLight ? /* glsl */ ` if (dispersionWavelengths == 1) {\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);\n }` : /* glsl */ ` lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);`}\n\n vec3 lightDir = lightSample.direction;\n vec3 viewDir = -path.ray.d;\n float lightPdf = lightSample.pdf;\n // Opaque surfaces are rendered two-sided by the core renderer. Use the\n // face-forward shading normal here as well, otherwise the early-out rejects\n // every direct-light sample seen from the back of a triangle (for example\n // the inside of an imported room wall).\n float cosThetaL = dot(ffnormal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (isSurface && mat.coatNormalEnabled) { cosThetaL = dot(mat.geometricNormal, lightDir); }\n#endif\n\n if (lightPdf <= 0.0 || max(max(lightSample.emission.x, lightSample.emission.y), lightSample.emission.z) <= 0.0) {\n return vec3(0.0);\n }\n\n${channelIndependentLight ? /* glsl */ ` // Test the full emission before filtering, so black spectral components\n // still consume the same visibility walk and random stream.\n if (dispersionWavelengths != 1) {\n lightSample.emission = sampling_spectral_rgb_filter(lightSample.emission, pathChannel);\n }\n` : ''} float scatteringPdf = 0.0;\n vec3 f = vec3(0.0);\n if (isSurface) {\n if (cosThetaL <= 0.0 && mat.transmissionWeight <= 0.0 && mat.subsurfaceWeight <= 0.0) {\n return vec3(0.0);\n }\n f = openpbr_eval_prepared(prepared, lightDir, scatteringPdf);\n }\n else {\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(viewDir, lightDir),\n si.mediumAnisotropy\n );\n f = vec3(scatteringPdf);\n }\n\n if (scatteringPdf <= 0.0 || max(max(f.x, f.y), f.z) <= 0.0) {\n return vec3(0.0);\n }\n\n Ray lightRay;\n vec3 shadowOrigin = si.position + EPS * lightDir;\n if (isSurface) {\n const float shadowTerminatorCutoff = 0.1;\n float normalLight = dot(si.normal, lightDir);\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { normalLight = dot(si.faceNormal, lightDir); }\n#endif\n vec3 geometricNormal = normalLight < 0.0 ? -si.faceNormal : si.faceNormal;\n normalLight = abs(normalLight);\n float geometricLight = dot(geometricNormal, lightDir);\n float offsetAmount = normalLight < shadowTerminatorCutoff\n ? clamp(\n 2.0 - (geometricLight + normalLight) / shadowTerminatorCutoff,\n 0.0,\n 1.0\n )\n : clamp(1.0 - geometricLight / shadowTerminatorCutoff, 0.0, 1.0);\n shadowOrigin += si.shadowOffset * offsetAmount;\n }\n float shadowDistance=lightSample.dist-EPS;\n vec3 shadowDirection=lightDir;\n if(lightSample.sourceType==1){\n vec3 endpoint=si.position+lightDir*lightSample.dist+EPS*lightSample.normal;\n shadowDirection=normalize(endpoint-shadowOrigin);shadowDistance=distance(endpoint,shadowOrigin);\n }\n initRay(lightRay, shadowOrigin, shadowDirection);\n if (intersectSceneShadow(lightRay, shadowDistance, si.triangleIndex)) {\n return vec3(0.0);\n }\n\n#ifdef USE_ENVMAP\n // Match the endpoint used by a BSDF-sampled surface transmission, including\n // a separately displayed or grounded background and its coverage.\n if (isSurface && cosThetaL < 0.0 && lightSample.sourceType == 0) {\n vec4 background = sampleBackgroundFromRay(lightRay.o, lightDir);\n lightSample.emission = sampling_spectral_rgb_filter(background.rgb * background.a, pathChannel);\n }\n#endif\n\n // Delta lights cannot be sampled by the BSDF strategy, so their MIS weight\n // is exactly one even when their light-selection PMF is small.\n float misWeight = lightSample.isDelta\n ? 1.0\n : sampling_power_heuristic(lightPdf, scatteringPdf);\n${fragments['sample1'] ?? ''} return misWeight > 0.0\n ? misWeight * lightSample.emission * f / lightPdf\n : vec3(0.0);\n}\n\n#ifdef USE_COAT_NORMAL_FRAMES\nvec3 coat_frame_normal(vec3 inputNormal, vec3 face, vec3 view) {\n bool front = dot(face, view) >= 0.0;\n vec3 ffFace = front ? face : -face;\n vec3 ffInput = front ? inputNormal : -inputNormal;\n if (dot(inputNormal, face) <= 0.0 || dot(ffInput, view) <= 1e-6) { return ffFace; }\n return ffInput;\n}\n#endif\nvoid SampleMaterial(inout SurfaceInteraction si, OpenPbrResolvedMaterial mat, inout Path path) {\n vec3 matRnd = vec3(sample2D(bounceDim(BSDF_DIRECTION)), sample1D(bounceDim(BSDF_LOBE)));\n#ifdef USE_COAT_NORMAL_FRAMES\n vec3 originalFace = si.faceNormal;\n vec3 originalNormal = si.normal;\n#endif\n float ndv1 = -dot(si.faceNormal, path.ray.d);\n float ndv2 = -dot(si.normal, path.ray.d);\n if ((mat.transmissionWeight > 0.0 || mat.subsurfaceWeight > 0.0) && mat.thinWalled) {\n // Always treat thin material as entering medium\n if (ndv1 < 0.0) {\n si.faceNormal = -si.faceNormal;\n ndv1 = -ndv1;\n }\n if (ndv2 < 0.0) {\n si.normal = -si.normal;\n ndv2 = -ndv2;\n }\n }\n // In same edge cases normal is not torwards the camera while we can still see the face.\n // We need to choose faceNormal in this case.\n bool useFaceN = ndv1 >= 0.0 && ndv2 < 0.0;\n float ndv = useFaceN ? ndv1 : ndv2;\n vec3 normal = useFaceN ? si.faceNormal : si.normal;\n\n mat.inside = ndv <= 0.0 && !mat.thinWalled;\n // In or out\n mat.relativeIor = ndv > 0.0 ? (1.0 / mat.specularIor) : mat.specularIor;\n vec3 ffnormal = ndv >= 0.0 ? normal : -normal;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) {\n vec3 view = -path.ray.d;\n float geometricView = dot(originalFace, view);\n mat.geometricNormal = geometricView >= 0.0 ? originalFace : -originalFace;\n ffnormal = coat_frame_normal(originalNormal, originalFace, view);\n mat.coatNormal = coat_frame_normal(si.coatNormal, originalFace, view);\n mat.inside = geometricView <= 0.0 && !mat.thinWalled;\n mat.relativeIor = (geometricView > 0.0 || mat.thinWalled) ? 1.0 / mat.specularIor : mat.specularIor;\n }\n#endif\n\n\n float scatteringPdf;\n vec3 scatterDir;\n path.scatteringIsDelta = false;\n bool mediumSampled = false;\n bool crossedBoundary = false;\n OpenPbrPreparedBsdf prepared;\n\n#ifdef HAS_MEDIUM\n int mediumType = si.mediumType;\n float d = distance(si.position, path.ray.o);\n vec3 segmentOrigin = path.ray.o;\n vec3 extinction = si.mediumExtinction;\n vec3 scattering = min(si.mediumScattering, extinction);\n float majorant = max(max(extinction.x, extinction.y), extinction.z);\n if (mediumType > 0 && majorant > 0.0) {\n // Sample one RGB extinction channel and divide by the mixture PDF. This\n // is the homogeneous-medium estimator used by PBRT and avoids the very\n // large exp((majorant - extinction) * distance) weights produced by\n // majorant tracking when OpenPBR SSS radii differ strongly by channel.\n int mediumChannel = min(int(sample1D(bounceDim(MEDIUM_CHANNEL)) * 3.0), 2);\n float channelExtinction = extinction[mediumChannel];\n float scatterDist = channelExtinction > 0.0\n ? min(-log(max(sample1D(bounceDim(MEDIUM_DISTANCE)), 1e-7)) / channelExtinction, d)\n : d;\n mediumSampled = scatterDist < d;\n vec3 transmittance = exp(-extinction * scatterDist);\n vec3 density = mediumSampled\n ? extinction * transmittance\n : transmittance;\n float mediumPdf = max(\n (density.x + density.y + density.z) / 3.0,\n 1e-8\n );\n if (mediumSampled) {\n path.beta *= transmittance * scattering / mediumPdf;\n // Zero throughput cannot contribute at subsequent vertices or light connections.\n if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }\n // Move from the start of the segment, not from its end surface.\n path.ray.o = segmentOrigin + scatterDist * path.ray.d;\n si.position = path.ray.o;\n // A volume vertex has no originating surface to skip on continuation or shadow rays.\n si.triangleIndex = -1;\n si.instanceIndex = -1;\n path.li += DirectLight(si, mat, prepared, path, ffnormal, false) * path.beta;\n\n // Pick a new direction based on the phase function\n scatterDir = sampling_henyey_greenstein(\n -path.ray.d,\n si.mediumAnisotropy,\n sample2D(bounceDim(PHASE_DIRECTION))\n );\n scatteringPdf = sampling_henyey_greenstein_phase(\n dot(scatterDir, -path.ray.d),\n si.mediumAnisotropy\n );\n }\n else {\n path.beta *= transmittance / mediumPdf;\n // Zero throughput cannot contribute at subsequent vertices or light connections.\n if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }\n }\n }\n#endif\n\n // Direct lighting\n if (!mediumSampled) {\n // Match NEE and background radiance when RGB wavelength passes are added.\n vec3 surfaceEmission = sampling_spectral_rgb_filter(mat.emission, pathChannel);\n ${fragments['sample2'] ?? ''}path.li += emissiveHitMisWeight(si,path) * surfaceEmission * path.beta;${fragments['sample3'] ?? ''}\n if (mat.materialType == UNLIT) {\n path.abort = true;\n return;\n }\n vec3 surfaceTangent = vec3(0.0);\n#ifdef USE_TANGENT\n surfaceTangent = si.tangent;\n#endif\n mat.directionTangent = si.directionTangent;\n mat.directionBitangent = si.directionBitangent;\n mat.geometryTangent = si.geometryTangent;\n mat.geometryBitangent = si.geometryBitangent;\n prepared = openpbr_prepare(surfaceTangent, mat, -path.ray.d, ffnormal);\n path.li += DirectLight(si, mat, prepared, path, ffnormal, true) * path.beta;\n${fragments['sample4'] ?? ''} // Sample BSDF for color and outgoing direction\n bool isNextRefraction;\n vec3 f = openpbr_sample_prepared(\n prepared,\n matRnd,\n scatterDir,\n scatteringPdf,\n isNextRefraction\n );\n // Null-boundary transmission is discrete and has no NEE competitor.\n path.scatteringIsDelta = !prepared.material.thinWalled &&\n abs(prepared.material.relativeIor - 1.0) <= 1e-6 &&\n prepared.probabilities[OPENPBR_LOBE_TRANSMISSION] >= 1.0 - 1e-6;\n // Match WebGPU: rejected VNDF/refraction proposals have no continuation.\n // Tracing their fallback direction with the incoming throughput invents\n // light paths, especially after total internal reflection inside glass.\n if (!(scatteringPdf > 0.0) || any(isnan(f)) || any(isinf(f)) ||\n dot(scatterDir, scatterDir) < 0.5) {\n path.scatteringPdf = 0.0;\n path.abort = true;\n return;\n }\n${fragments['sample5'] ?? ''} path.beta *= f / scatteringPdf;\n // Zero throughput cannot contribute at subsequent vertices or light connections.\n if (all(equal(path.beta, vec3(0.0)))) { path.abort = true; return; }\n crossedBoundary = !mat.thinWalled &&\n isNextRefraction;\n path.isNextRefraction = isNextRefraction;\n // TODO prefer the opaque surface when transmission surface and opaque surface are overlapped.\n // Or the ray go out from transmission material will miss the opque surface.\n path.ray.o = si.position + EPS * scatterDir;\n#ifdef USE_COAT_NORMAL_FRAMES\n if (mat.coatNormalEnabled) { path.ray.o = si.position + EPS * (dot(originalFace, scatterDir) >= 0.0 ? originalFace : -originalFace); }\n#endif\n }\n\n path.scatteringPdf = scatteringPdf;\n initRay(path.ray, path.ray.o, scatterDir);\n if (mediumSampled) {${fragments['sample6'] ?? ''}\n path.isNextRefraction = false;\n }\n path.fromEye = false;\n\n#ifdef HAS_MEDIUM\n // A reflected ray stays in its current medium. Only a sampled transmission\n // event crosses the boundary of a medium-bearing closed mesh.\n if (!mediumSampled && crossedBoundary && mat.mediumType > 0) {\n if (ndv1 >= 0.0) {\n si.mediumType = mat.mediumType;\n si.mediumExtinction = mat.mediumExtinction;\n si.mediumScattering = mat.mediumScattering;\n path.scatteringMediumEntered = path.scatteringMediumEntered || any(greaterThan(mat.mediumScattering, vec3(0.0)));\n si.mediumAnisotropy = mat.mediumAnisotropy;\n }\n else {\n si.mediumType = 0;\n si.mediumExtinction = vec3(0.0);\n si.mediumScattering = vec3(0.0);\n si.mediumAnisotropy = 0.0;\n }\n }\n#endif\n}\n`;\n}\nexport default createSampleMaterialGlsl();\n"]}
|
|
@@ -12,34 +12,34 @@ export default glsl `
|
|
|
12
12
|
|
|
13
13
|
const uint SHADOW_CATCHER_LIGHT_SAMPLES = 4u;
|
|
14
14
|
|
|
15
|
-
uint
|
|
16
|
-
return candidate == 0u ?
|
|
15
|
+
uint lA(uint candidate, uint slot) {
|
|
16
|
+
return candidate == 0u ? aX(slot) : aX(9u + (candidate - 1u) * 3u + slot);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
vec2 sampleShadowCatcher(SurfaceInteraction si, int bounce, inout Path path) {
|
|
22
|
-
vec3
|
|
22
|
+
vec3 sg = -path.ray.d;
|
|
23
23
|
vec2 counts = vec2(0.0);
|
|
24
24
|
|
|
25
25
|
#if defined(NUM_LIGHTS) || defined(USE_ENVMAP)
|
|
26
26
|
for (uint candidate = 0u; candidate < SHADOW_CATCHER_LIGHT_SAMPLES; candidate++) {
|
|
27
27
|
LightSampleRec lightSample;
|
|
28
|
-
vec3
|
|
29
|
-
sample2D(
|
|
30
|
-
sample1D(
|
|
28
|
+
vec3 ob = vec3(
|
|
29
|
+
sample2D(lA(candidate, LIGHT_POSITION)),
|
|
30
|
+
sample1D(lA(candidate, LIGHT_SELECT))
|
|
31
31
|
);
|
|
32
|
-
sampleLight(si.position,
|
|
32
|
+
sampleLight(si.position, ob, lightSample, false);
|
|
33
33
|
|
|
34
34
|
vec3 lightDir = lightSample.direction;
|
|
35
35
|
float cosThetaL = dot(si.normal, lightDir);
|
|
36
|
-
float
|
|
37
|
-
if (lightSample.pdf > 0.0 &&
|
|
36
|
+
float rG = dot(si.normal, sg) * cosThetaL;
|
|
37
|
+
if (lightSample.pdf > 0.0 && rG >= 0.0) {
|
|
38
38
|
if (dot(lightSample.emission, luminance) * abs(cosThetaL) > 0.0) {
|
|
39
39
|
Ray ray;
|
|
40
40
|
initRay(ray, si.position + EPS * lightDir, lightDir);
|
|
41
|
-
bool
|
|
42
|
-
counts += vec2(
|
|
41
|
+
bool mz = intersectSceneShadow(ray, lightSample.dist - EPS, si.triangleIndex);
|
|
42
|
+
counts += vec2(mz ? 1.0 : 0.0, 1.0);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
}
|