three-gpu-pathtracer 0.0.13 → 0.0.14
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/LICENSE +21 -21
- package/README.md +981 -961
- package/build/index.module.js +6965 -6508
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +6959 -6505
- package/build/index.umd.cjs.map +1 -1
- package/package.json +73 -73
- package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
- package/src/core/MaterialReducer.js +256 -256
- package/src/core/PathTracingRenderer.js +346 -346
- package/src/core/PathTracingSceneGenerator.js +69 -69
- package/src/core/QuiltPathTracingRenderer.js +223 -223
- package/src/index.js +36 -40
- package/src/materials/MaterialBase.js +56 -56
- package/src/materials/{GraphMaterial.js → debug/GraphMaterial.js} +243 -243
- package/src/materials/{AlphaDisplayMaterial.js → fullscreen/AlphaDisplayMaterial.js} +48 -48
- package/src/materials/{BlendMaterial.js → fullscreen/BlendMaterial.js} +67 -67
- package/src/materials/{DenoiseMaterial.js → fullscreen/DenoiseMaterial.js} +142 -142
- package/src/materials/{LambertPathTracingMaterial.js → pathtracing/LambertPathTracingMaterial.js} +296 -285
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +635 -0
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +179 -0
- package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +81 -0
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +317 -0
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +54 -0
- package/src/materials/{AmbientOcclusionMaterial.js → surface/AmbientOcclusionMaterial.js} +207 -199
- package/src/materials/surface/FogVolumeMaterial.js +23 -0
- package/src/objects/EquirectCamera.js +13 -13
- package/src/objects/PhysicalCamera.js +28 -28
- package/src/objects/PhysicalSpotLight.js +14 -14
- package/src/objects/ShapedAreaLight.js +12 -12
- package/src/shader/bsdf/bsdfSampling.glsl.js +490 -0
- package/src/shader/bsdf/fog.glsl.js +23 -0
- package/src/shader/bsdf/ggx.glsl.js +102 -0
- package/src/shader/bsdf/iridescence.glsl.js +135 -0
- package/src/shader/bsdf/sheen.glsl.js +98 -0
- package/src/shader/{shaderLayerTexelFetchFunctions.js → common/arraySamplerTexelFetch.glsl.js} +25 -25
- package/src/shader/common/bvhAnyHit.glsl.js +76 -0
- package/src/shader/common/fresnel.glsl.js +98 -0
- package/src/shader/common/intersectShapes.glsl.js +62 -0
- package/src/shader/common/math.glsl.js +81 -0
- package/src/shader/common/utils.glsl.js +116 -0
- package/src/shader/{shaderRandFunctions.js → rand/pcg.glsl.js} +57 -57
- package/src/shader/{shaderSobolSampling.js → rand/sobol.glsl.js} +256 -256
- package/src/shader/sampling/equirectSampling.glsl.js +62 -0
- package/src/shader/sampling/lightSampling.glsl.js +223 -0
- package/src/shader/sampling/shapeSampling.glsl.js +86 -0
- package/src/shader/structs/cameraStruct.glsl.js +13 -0
- package/src/shader/structs/equirectStruct.glsl.js +14 -0
- package/src/shader/structs/fogMaterialBvh.glsl.js +62 -0
- package/src/shader/structs/lightsStruct.glsl.js +78 -0
- package/src/shader/{shaderStructs.js → structs/materialStruct.glsl.js} +207 -327
- package/src/textures/GradientEquirectTexture.js +35 -35
- package/src/textures/ProceduralEquirectTexture.js +75 -75
- package/src/uniforms/AttributesTextureArray.js +35 -35
- package/src/uniforms/EquirectHdrInfoUniform.js +277 -273
- package/src/uniforms/FloatAttributeTextureArray.js +169 -169
- package/src/uniforms/IESProfilesTexture.js +100 -100
- package/src/uniforms/LightsInfoUniformStruct.js +212 -212
- package/src/uniforms/MaterialsTexture.js +503 -426
- package/src/uniforms/PhysicalCameraUniform.js +36 -36
- package/src/uniforms/RenderTarget2DArray.js +97 -97
- package/src/uniforms/utils.js +30 -30
- package/src/utils/BlurredEnvMapGenerator.js +116 -116
- package/src/utils/GeometryPreparationUtils.js +214 -214
- package/src/utils/IESLoader.js +325 -325
- package/src/utils/SobolNumberMapGenerator.js +80 -80
- package/src/utils/UVUnwrapper.js +101 -101
- package/src/utils/macroify.js +9 -0
- package/src/workers/PathTracingSceneWorker.js +42 -42
- package/src/materials/PhysicalPathTracingMaterial.js +0 -1013
- package/src/shader/shaderBvhAnyHit.js +0 -76
- package/src/shader/shaderEnvMapSampling.js +0 -58
- package/src/shader/shaderGGXFunctions.js +0 -100
- package/src/shader/shaderIridescenceFunctions.js +0 -135
- package/src/shader/shaderLightSampling.js +0 -229
- package/src/shader/shaderMaterialSampling.js +0 -510
- package/src/shader/shaderSheenFunctions.js +0 -98
- package/src/shader/shaderUtils.js +0 -377
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
export const attenuateHitGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
// step through multiple surface hits and accumulate color attenuation based on transmissive surfaces
|
|
4
|
+
// returns true if a solid surface was hit
|
|
5
|
+
bool attenuateHit(
|
|
6
|
+
BVH bvh, vec3 rayOrigin, vec3 rayDirection, float rayDist,
|
|
7
|
+
int traversals, int transmissiveTraversals, bool isShadowRay,
|
|
8
|
+
Material fogMaterial,
|
|
9
|
+
out vec3 color
|
|
10
|
+
) {
|
|
11
|
+
|
|
12
|
+
vec3 ogRayOrigin = rayOrigin;
|
|
13
|
+
|
|
14
|
+
// hit results
|
|
15
|
+
uvec4 faceIndices = uvec4( 0u );
|
|
16
|
+
vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
|
|
17
|
+
vec3 barycoord = vec3( 0.0 );
|
|
18
|
+
float side = 1.0;
|
|
19
|
+
float dist = 0.0;
|
|
20
|
+
LightSampleRecord lightSampleRec;
|
|
21
|
+
|
|
22
|
+
color = vec3( 1.0 );
|
|
23
|
+
|
|
24
|
+
// TODO: we should be using sobol sampling here instead of rand but the sobol bounce and path indices need to be incremented
|
|
25
|
+
// and then reset.
|
|
26
|
+
for ( int i = 0; i < traversals; i ++ ) {
|
|
27
|
+
|
|
28
|
+
int hitType = traceScene(
|
|
29
|
+
rayOrigin, rayDirection,
|
|
30
|
+
bvh, lights, fogMaterial,
|
|
31
|
+
faceIndices, faceNormal, barycoord, side, dist,
|
|
32
|
+
lightSampleRec
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if ( hitType == FOG_HIT ) {
|
|
36
|
+
|
|
37
|
+
return true;
|
|
38
|
+
|
|
39
|
+
} else if ( hitType == LIGHT_HIT ) {
|
|
40
|
+
|
|
41
|
+
float totalDist = distance( ogRayOrigin, rayOrigin + rayDirection * lightSampleRec.dist );
|
|
42
|
+
return totalDist < rayDist - max( totalDist, rayDist ) * 1e-4;
|
|
43
|
+
|
|
44
|
+
} else if ( hitType == SURFACE_HIT ) {
|
|
45
|
+
|
|
46
|
+
float totalDist = distance( ogRayOrigin, rayOrigin + rayDirection * dist );
|
|
47
|
+
if ( totalDist > rayDist ) {
|
|
48
|
+
|
|
49
|
+
return false;
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// TODO: attenuate the contribution based on the PDF of the resulting ray including refraction values
|
|
54
|
+
// Should be able to work using the material BSDF functions which will take into account specularity, etc.
|
|
55
|
+
// TODO: should we account for emissive surfaces here?
|
|
56
|
+
|
|
57
|
+
uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;
|
|
58
|
+
Material material = readMaterialInfo( materials, materialIndex );
|
|
59
|
+
|
|
60
|
+
// adjust the ray to the new surface
|
|
61
|
+
bool isEntering = side == 1.0;
|
|
62
|
+
rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
|
|
63
|
+
|
|
64
|
+
#if FEATURE_FOG
|
|
65
|
+
|
|
66
|
+
if ( material.fogVolume ) {
|
|
67
|
+
|
|
68
|
+
fogMaterial = material;
|
|
69
|
+
fogMaterial.fogVolume = side == 1.0;
|
|
70
|
+
i -= sign( transmissiveTraversals );
|
|
71
|
+
transmissiveTraversals --;
|
|
72
|
+
continue;
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#endif
|
|
77
|
+
|
|
78
|
+
if ( ! material.castShadow && isShadowRay ) {
|
|
79
|
+
|
|
80
|
+
continue;
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, barycoord, faceIndices.xyz ).xy;
|
|
85
|
+
vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, barycoord, faceIndices.xyz );
|
|
86
|
+
|
|
87
|
+
// albedo
|
|
88
|
+
vec4 albedo = vec4( material.color, material.opacity );
|
|
89
|
+
if ( material.map != - 1 ) {
|
|
90
|
+
|
|
91
|
+
vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
|
|
92
|
+
albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if ( material.vertexColors ) {
|
|
97
|
+
|
|
98
|
+
albedo *= vertexColor;
|
|
99
|
+
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// alphaMap
|
|
103
|
+
if ( material.alphaMap != - 1 ) {
|
|
104
|
+
|
|
105
|
+
albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// transmission
|
|
110
|
+
float transmission = material.transmission;
|
|
111
|
+
if ( material.transmissionMap != - 1 ) {
|
|
112
|
+
|
|
113
|
+
vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
|
|
114
|
+
transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// metalness
|
|
119
|
+
float metalness = material.metalness;
|
|
120
|
+
if ( material.metalnessMap != - 1 ) {
|
|
121
|
+
|
|
122
|
+
vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
|
|
123
|
+
metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
float alphaTest = material.alphaTest;
|
|
128
|
+
bool useAlphaTest = alphaTest != 0.0;
|
|
129
|
+
float transmissionFactor = ( 1.0 - metalness ) * transmission;
|
|
130
|
+
if (
|
|
131
|
+
transmissionFactor < rand() && ! (
|
|
132
|
+
// material sidedness
|
|
133
|
+
material.side != 0.0 && side == material.side
|
|
134
|
+
|
|
135
|
+
// alpha test
|
|
136
|
+
|| useAlphaTest && albedo.a < alphaTest
|
|
137
|
+
|
|
138
|
+
// opacity
|
|
139
|
+
|| material.transparent && ! useAlphaTest && albedo.a < rand()
|
|
140
|
+
)
|
|
141
|
+
) {
|
|
142
|
+
|
|
143
|
+
return true;
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if ( side == 1.0 && isEntering ) {
|
|
148
|
+
|
|
149
|
+
// only attenuate by surface color on the way in
|
|
150
|
+
color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );
|
|
151
|
+
|
|
152
|
+
} else if ( side == - 1.0 ) {
|
|
153
|
+
|
|
154
|
+
// attenuate by medium once we hit the opposite side of the model
|
|
155
|
+
color *= transmissionAttenuation( dist, material.attenuationColor, material.attenuationDistance );
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
bool isTransmissiveRay = dot( rayDirection, faceNormal * side ) < 0.0;
|
|
160
|
+
if ( ( isTransmissiveRay || isEntering ) && transmissiveTraversals > 0 ) {
|
|
161
|
+
|
|
162
|
+
i -= sign( transmissiveTraversals );
|
|
163
|
+
transmissiveTraversals --;
|
|
164
|
+
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
} else {
|
|
168
|
+
|
|
169
|
+
return false;
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return true;
|
|
176
|
+
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
`;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export const cameraUtilsGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
vec3 ndcToRayOrigin( vec2 coord ) {
|
|
4
|
+
|
|
5
|
+
vec4 rayOrigin4 = cameraWorldMatrix * invProjectionMatrix * vec4( coord, - 1.0, 1.0 );
|
|
6
|
+
return rayOrigin4.xyz / rayOrigin4.w;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
void getCameraRay( out vec3 rayDirection, out vec3 rayOrigin ) {
|
|
10
|
+
|
|
11
|
+
vec2 ssd = vec2( 1.0 ) / resolution;
|
|
12
|
+
|
|
13
|
+
// Jitter the camera ray by finding a uv coordinate at a random sample
|
|
14
|
+
// around this pixel's UV coordinate for AA
|
|
15
|
+
vec2 ruv = sobol2( 0 );
|
|
16
|
+
vec2 jitteredUv = vUv + vec2( tentFilter( ruv.x ) * ssd.x, tentFilter( ruv.y ) * ssd.y );
|
|
17
|
+
|
|
18
|
+
#if CAMERA_TYPE == 2
|
|
19
|
+
|
|
20
|
+
// Equirectangular projection
|
|
21
|
+
vec4 rayDirection4 = vec4( equirectUvToDirection( jitteredUv ), 0.0 );
|
|
22
|
+
vec4 rayOrigin4 = vec4( 0.0, 0.0, 0.0, 1.0 );
|
|
23
|
+
|
|
24
|
+
rayDirection4 = cameraWorldMatrix * rayDirection4;
|
|
25
|
+
rayOrigin4 = cameraWorldMatrix * rayOrigin4;
|
|
26
|
+
|
|
27
|
+
rayDirection = normalize( rayDirection4.xyz );
|
|
28
|
+
rayOrigin = rayOrigin4.xyz / rayOrigin4.w;
|
|
29
|
+
|
|
30
|
+
#else
|
|
31
|
+
|
|
32
|
+
// get [- 1, 1] normalized device coordinates
|
|
33
|
+
vec2 ndc = 2.0 * jitteredUv - vec2( 1.0 );
|
|
34
|
+
rayOrigin = ndcToRayOrigin( ndc );
|
|
35
|
+
|
|
36
|
+
#if CAMERA_TYPE == 1
|
|
37
|
+
|
|
38
|
+
// Orthographic projection
|
|
39
|
+
rayDirection = ( cameraWorldMatrix * vec4( 0.0, 0.0, - 1.0, 0.0 ) ).xyz;
|
|
40
|
+
rayDirection = normalize( rayDirection );
|
|
41
|
+
|
|
42
|
+
#else
|
|
43
|
+
|
|
44
|
+
// Perspective projection
|
|
45
|
+
rayDirection = normalize( mat3(cameraWorldMatrix) * ( invProjectionMatrix * vec4( ndc, 0.0, 1.0 ) ).xyz );
|
|
46
|
+
|
|
47
|
+
#endif
|
|
48
|
+
|
|
49
|
+
#endif
|
|
50
|
+
|
|
51
|
+
#if FEATURE_DOF
|
|
52
|
+
{
|
|
53
|
+
|
|
54
|
+
// depth of field
|
|
55
|
+
vec3 focalPoint = rayOrigin + normalize( rayDirection ) * physicalCamera.focusDistance;
|
|
56
|
+
|
|
57
|
+
// get the aperture sample
|
|
58
|
+
// if blades === 0 then we assume a circle
|
|
59
|
+
vec3 shapeUVW= sobol3( 1 );
|
|
60
|
+
int blades = physicalCamera.apertureBlades;
|
|
61
|
+
float anamorphicRatio = physicalCamera.anamorphicRatio;
|
|
62
|
+
vec2 apertureSample = blades == 0 ? sampleCircle( shapeUVW.xy ) : sampleRegularPolygon( blades, shapeUVW );
|
|
63
|
+
apertureSample *= physicalCamera.bokehSize * 0.5 * 1e-3;
|
|
64
|
+
|
|
65
|
+
// rotate the aperture shape
|
|
66
|
+
apertureSample =
|
|
67
|
+
rotateVector( apertureSample, physicalCamera.apertureRotation ) *
|
|
68
|
+
saturate( vec2( anamorphicRatio, 1.0 / anamorphicRatio ) );
|
|
69
|
+
|
|
70
|
+
// create the new ray
|
|
71
|
+
rayOrigin += ( cameraWorldMatrix * vec4( apertureSample, 0.0, 0.0 ) ).xyz;
|
|
72
|
+
rayDirection = focalPoint - rayOrigin;
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
#endif
|
|
76
|
+
|
|
77
|
+
rayDirection = normalize( rayDirection );
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
`;
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
|
|
2
|
+
export const getSurfaceRecordGLSL = /* glsl */`
|
|
3
|
+
|
|
4
|
+
#define SKIP_SURFACE 0
|
|
5
|
+
#define HIT_SURFACE 1
|
|
6
|
+
int getSurfaceRecord(
|
|
7
|
+
Material material, sampler2DArray attributesArray,
|
|
8
|
+
float side, vec3 barycoord, uvec4 faceIndices, vec3 faceNormal, float accumulatedRoughness,
|
|
9
|
+
|
|
10
|
+
out SurfaceRecord surf
|
|
11
|
+
) {
|
|
12
|
+
|
|
13
|
+
if ( material.fogVolume ) {
|
|
14
|
+
|
|
15
|
+
vec3 normal = vec3( 0, 0, 1 );
|
|
16
|
+
|
|
17
|
+
SurfaceRecord fogSurface;
|
|
18
|
+
fogSurface.volumeParticle = true;
|
|
19
|
+
fogSurface.color = material.color;
|
|
20
|
+
fogSurface.emission = material.emissiveIntensity * material.emissive;
|
|
21
|
+
fogSurface.normal = normal;
|
|
22
|
+
fogSurface.faceNormal = normal;
|
|
23
|
+
fogSurface.clearcoatNormal = normal;
|
|
24
|
+
|
|
25
|
+
surf = fogSurface;
|
|
26
|
+
return HIT_SURFACE;
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// uv coord for textures
|
|
31
|
+
vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, barycoord, faceIndices.xyz ).xy;
|
|
32
|
+
vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, barycoord, faceIndices.xyz );
|
|
33
|
+
|
|
34
|
+
// albedo
|
|
35
|
+
vec4 albedo = vec4( material.color, material.opacity );
|
|
36
|
+
if ( material.map != - 1 ) {
|
|
37
|
+
|
|
38
|
+
vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
|
|
39
|
+
albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if ( material.vertexColors ) {
|
|
43
|
+
|
|
44
|
+
albedo *= vertexColor;
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// alphaMap
|
|
49
|
+
if ( material.alphaMap != - 1 ) {
|
|
50
|
+
|
|
51
|
+
albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// possibly skip this sample if it's transparent, alpha test is enabled, or we hit the wrong material side
|
|
56
|
+
// and it's single sided.
|
|
57
|
+
// - alpha test is disabled when it === 0
|
|
58
|
+
// - the material sidedness test is complicated because we want light to pass through the back side but still
|
|
59
|
+
// be able to see the front side. This boolean checks if the side we hit is the front side on the first ray
|
|
60
|
+
// and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.
|
|
61
|
+
float alphaTest = material.alphaTest;
|
|
62
|
+
bool useAlphaTest = alphaTest != 0.0;
|
|
63
|
+
if (
|
|
64
|
+
// material sidedness
|
|
65
|
+
material.side != 0.0 && side != material.side
|
|
66
|
+
|
|
67
|
+
// alpha test
|
|
68
|
+
|| useAlphaTest && albedo.a < alphaTest
|
|
69
|
+
|
|
70
|
+
// opacity
|
|
71
|
+
|| material.transparent && ! useAlphaTest && albedo.a < sobol( 3 )
|
|
72
|
+
) {
|
|
73
|
+
|
|
74
|
+
return SKIP_SURFACE;
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// fetch the interpolated smooth normal
|
|
79
|
+
vec3 normal = normalize( textureSampleBarycoord(
|
|
80
|
+
attributesArray,
|
|
81
|
+
ATTR_NORMAL,
|
|
82
|
+
barycoord,
|
|
83
|
+
faceIndices.xyz
|
|
84
|
+
).xyz );
|
|
85
|
+
|
|
86
|
+
// roughness
|
|
87
|
+
float roughness = material.roughness;
|
|
88
|
+
if ( material.roughnessMap != - 1 ) {
|
|
89
|
+
|
|
90
|
+
vec3 uvPrime = material.roughnessMapTransform * vec3( uv, 1 );
|
|
91
|
+
roughness *= texture2D( textures, vec3( uvPrime.xy, material.roughnessMap ) ).g;
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// metalness
|
|
96
|
+
float metalness = material.metalness;
|
|
97
|
+
if ( material.metalnessMap != - 1 ) {
|
|
98
|
+
|
|
99
|
+
vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
|
|
100
|
+
metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// emission
|
|
105
|
+
vec3 emission = material.emissiveIntensity * material.emissive;
|
|
106
|
+
if ( material.emissiveMap != - 1 ) {
|
|
107
|
+
|
|
108
|
+
vec3 uvPrime = material.emissiveMapTransform * vec3( uv, 1 );
|
|
109
|
+
emission *= texture2D( textures, vec3( uvPrime.xy, material.emissiveMap ) ).xyz;
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// transmission
|
|
114
|
+
float transmission = material.transmission;
|
|
115
|
+
if ( material.transmissionMap != - 1 ) {
|
|
116
|
+
|
|
117
|
+
vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
|
|
118
|
+
transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// normal
|
|
123
|
+
if ( material.flatShading ) {
|
|
124
|
+
|
|
125
|
+
// if we're rendering a flat shaded object then use the face normals - the face normal
|
|
126
|
+
// is provided based on the side the ray hits the mesh so flip it to align with the
|
|
127
|
+
// interpolated vertex normals.
|
|
128
|
+
normal = faceNormal * side;
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
vec3 baseNormal = normal;
|
|
133
|
+
if ( material.normalMap != - 1 ) {
|
|
134
|
+
|
|
135
|
+
vec4 tangentSample = textureSampleBarycoord(
|
|
136
|
+
attributesArray,
|
|
137
|
+
ATTR_TANGENT,
|
|
138
|
+
barycoord,
|
|
139
|
+
faceIndices.xyz
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
|
|
143
|
+
// resulting in NaNs and slow path tracing.
|
|
144
|
+
if ( length( tangentSample.xyz ) > 0.0 ) {
|
|
145
|
+
|
|
146
|
+
vec3 tangent = normalize( tangentSample.xyz );
|
|
147
|
+
vec3 bitangent = normalize( cross( normal, tangent ) * tangentSample.w );
|
|
148
|
+
mat3 vTBN = mat3( tangent, bitangent, normal );
|
|
149
|
+
|
|
150
|
+
vec3 uvPrime = material.normalMapTransform * vec3( uv, 1 );
|
|
151
|
+
vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.normalMap ) ).xyz * 2.0 - 1.0;
|
|
152
|
+
texNormal.xy *= material.normalScale;
|
|
153
|
+
normal = vTBN * texNormal;
|
|
154
|
+
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
normal *= side;
|
|
160
|
+
|
|
161
|
+
// clearcoat
|
|
162
|
+
float clearcoat = material.clearcoat;
|
|
163
|
+
if ( material.clearcoatMap != - 1 ) {
|
|
164
|
+
|
|
165
|
+
vec3 uvPrime = material.clearcoatMapTransform * vec3( uv, 1 );
|
|
166
|
+
clearcoat *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatMap ) ).r;
|
|
167
|
+
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// clearcoatRoughness
|
|
171
|
+
float clearcoatRoughness = material.clearcoatRoughness;
|
|
172
|
+
if ( material.clearcoatRoughnessMap != - 1 ) {
|
|
173
|
+
|
|
174
|
+
vec3 uvPrime = material.clearcoatRoughnessMapTransform * vec3( uv, 1 );
|
|
175
|
+
clearcoatRoughness *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatRoughnessMap ) ).g;
|
|
176
|
+
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// clearcoatNormal
|
|
180
|
+
vec3 clearcoatNormal = baseNormal;
|
|
181
|
+
if ( material.clearcoatNormalMap != - 1 ) {
|
|
182
|
+
|
|
183
|
+
vec4 tangentSample = textureSampleBarycoord(
|
|
184
|
+
attributesArray,
|
|
185
|
+
ATTR_TANGENT,
|
|
186
|
+
barycoord,
|
|
187
|
+
faceIndices.xyz
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
|
|
191
|
+
// resulting in NaNs and slow path tracing.
|
|
192
|
+
if ( length( tangentSample.xyz ) > 0.0 ) {
|
|
193
|
+
|
|
194
|
+
vec3 tangent = normalize( tangentSample.xyz );
|
|
195
|
+
vec3 bitangent = normalize( cross( clearcoatNormal, tangent ) * tangentSample.w );
|
|
196
|
+
mat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );
|
|
197
|
+
|
|
198
|
+
vec3 uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1 );
|
|
199
|
+
vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.clearcoatNormalMap ) ).xyz * 2.0 - 1.0;
|
|
200
|
+
texNormal.xy *= material.clearcoatNormalScale;
|
|
201
|
+
clearcoatNormal = vTBN * texNormal;
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
clearcoatNormal *= side;
|
|
208
|
+
|
|
209
|
+
// sheenColor
|
|
210
|
+
vec3 sheenColor = material.sheenColor;
|
|
211
|
+
if ( material.sheenColorMap != - 1 ) {
|
|
212
|
+
|
|
213
|
+
vec3 uvPrime = material.sheenColorMapTransform * vec3( uv, 1 );
|
|
214
|
+
sheenColor *= texture2D( textures, vec3( uvPrime.xy, material.sheenColorMap ) ).rgb;
|
|
215
|
+
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// sheenRoughness
|
|
219
|
+
float sheenRoughness = material.sheenRoughness;
|
|
220
|
+
if ( material.sheenRoughnessMap != - 1 ) {
|
|
221
|
+
|
|
222
|
+
vec3 uvPrime = material.sheenRoughnessMapTransform * vec3( uv, 1 );
|
|
223
|
+
sheenRoughness *= texture2D( textures, vec3( uvPrime.xy, material.sheenRoughnessMap ) ).a;
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// iridescence
|
|
228
|
+
float iridescence = material.iridescence;
|
|
229
|
+
if ( material.iridescenceMap != - 1 ) {
|
|
230
|
+
|
|
231
|
+
vec3 uvPrime = material.iridescenceMapTransform * vec3( uv, 1 );
|
|
232
|
+
iridescence *= texture2D( textures, vec3( uvPrime.xy, material.iridescenceMap ) ).r;
|
|
233
|
+
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// iridescence thickness
|
|
237
|
+
float iridescenceThickness = material.iridescenceThicknessMaximum;
|
|
238
|
+
if ( material.iridescenceThicknessMap != - 1 ) {
|
|
239
|
+
|
|
240
|
+
vec3 uvPrime = material.iridescenceThicknessMapTransform * vec3( uv, 1 );
|
|
241
|
+
float iridescenceThicknessSampled = texture2D( textures, vec3( uvPrime.xy, material.iridescenceThicknessMap ) ).g;
|
|
242
|
+
iridescenceThickness = mix( material.iridescenceThicknessMinimum, material.iridescenceThicknessMaximum, iridescenceThicknessSampled );
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
iridescence = iridescenceThickness == 0.0 ? 0.0 : iridescence;
|
|
247
|
+
|
|
248
|
+
// specular color
|
|
249
|
+
vec3 specularColor = material.specularColor;
|
|
250
|
+
if ( material.specularColorMap != - 1 ) {
|
|
251
|
+
|
|
252
|
+
vec3 uvPrime = material.specularColorMapTransform * vec3( uv, 1 );
|
|
253
|
+
specularColor *= texture2D( textures, vec3( uvPrime.xy, material.specularColorMap ) ).rgb;
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// specular intensity
|
|
258
|
+
float specularIntensity = material.specularIntensity;
|
|
259
|
+
if ( material.specularIntensityMap != - 1 ) {
|
|
260
|
+
|
|
261
|
+
vec3 uvPrime = material.specularIntensityMapTransform * vec3( uv, 1 );
|
|
262
|
+
specularIntensity *= texture2D( textures, vec3( uvPrime.xy, material.specularIntensityMap ) ).a;
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
surf.volumeParticle = false;
|
|
267
|
+
|
|
268
|
+
surf.faceNormal = faceNormal;
|
|
269
|
+
surf.normal = normal;
|
|
270
|
+
|
|
271
|
+
surf.metalness = metalness;
|
|
272
|
+
surf.color = albedo.rgb;
|
|
273
|
+
surf.emission = emission;
|
|
274
|
+
|
|
275
|
+
surf.ior = material.ior;
|
|
276
|
+
surf.transmission = transmission;
|
|
277
|
+
surf.thinFilm = material.thinFilm;
|
|
278
|
+
surf.attenuationColor = material.attenuationColor;
|
|
279
|
+
surf.attenuationDistance = material.attenuationDistance;
|
|
280
|
+
|
|
281
|
+
surf.clearcoatNormal = clearcoatNormal;
|
|
282
|
+
surf.clearcoat = clearcoat;
|
|
283
|
+
|
|
284
|
+
surf.sheen = material.sheen;
|
|
285
|
+
surf.sheenColor = sheenColor;
|
|
286
|
+
|
|
287
|
+
surf.iridescence = iridescence;
|
|
288
|
+
surf.iridescenceIor = material.iridescenceIor;
|
|
289
|
+
surf.iridescenceThickness = iridescenceThickness;
|
|
290
|
+
|
|
291
|
+
surf.specularColor = specularColor;
|
|
292
|
+
surf.specularIntensity = specularIntensity;
|
|
293
|
+
|
|
294
|
+
// apply perceptual roughness factor from gltf. sheen perceptual roughness is
|
|
295
|
+
// applied by its brdf function
|
|
296
|
+
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces
|
|
297
|
+
surf.roughness = roughness * roughness;
|
|
298
|
+
surf.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;
|
|
299
|
+
surf.sheenRoughness = sheenRoughness;
|
|
300
|
+
|
|
301
|
+
// frontFace is used to determine transmissive properties and PDF. If no transmission is used
|
|
302
|
+
// then we can just always assume this is a front face.
|
|
303
|
+
surf.frontFace = side == 1.0 || transmission == 0.0;
|
|
304
|
+
surf.eta = material.thinFilm || surf.frontFace ? 1.0 / material.ior : material.ior;
|
|
305
|
+
surf.f0 = iorRatioToF0( surf.eta );
|
|
306
|
+
|
|
307
|
+
// Compute the filtered roughness value to use during specular reflection computations.
|
|
308
|
+
// The accumulated roughness value is scaled by a user setting and a "magic value" of 5.0.
|
|
309
|
+
// If we're exiting something transmissive then scale the factor down significantly so we can retain
|
|
310
|
+
// sharp internal reflections
|
|
311
|
+
surf.filteredRoughness = applyFilteredGlossy( surf.roughness, accumulatedRoughness );
|
|
312
|
+
surf.filteredClearcoatRoughness = applyFilteredGlossy( surf.clearcoatRoughness, accumulatedRoughness );
|
|
313
|
+
|
|
314
|
+
return HIT_SURFACE;
|
|
315
|
+
|
|
316
|
+
}
|
|
317
|
+
`;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export const traceSceneGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
#define NO_HIT 0
|
|
4
|
+
#define SURFACE_HIT 1
|
|
5
|
+
#define LIGHT_HIT 2
|
|
6
|
+
#define FOG_HIT 3
|
|
7
|
+
|
|
8
|
+
int traceScene(
|
|
9
|
+
|
|
10
|
+
vec3 rayOrigin, vec3 rayDirection,
|
|
11
|
+
BVH bvh, LightsInfo lights, Material fogMaterial,
|
|
12
|
+
out uvec4 faceIndices, out vec3 faceNormal, out vec3 barycoord, out float side, out float dist,
|
|
13
|
+
out LightSampleRecord lightSampleRec
|
|
14
|
+
|
|
15
|
+
) {
|
|
16
|
+
|
|
17
|
+
bool hit = bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );
|
|
18
|
+
bool lightHit = lightsClosestHit( lights.tex, lights.count, rayOrigin, rayDirection, lightSampleRec );
|
|
19
|
+
|
|
20
|
+
#if FEATURE_FOG
|
|
21
|
+
|
|
22
|
+
if ( fogMaterial.fogVolume ) {
|
|
23
|
+
|
|
24
|
+
float particleDist = intersectFogVolume( fogMaterial, sobol( 1 ) );
|
|
25
|
+
if ( particleDist + 1e-4 < dist && ( particleDist + 1e-4 < lightSampleRec.dist || ! lightHit ) ) {
|
|
26
|
+
|
|
27
|
+
side = 1.0;
|
|
28
|
+
faceNormal = normalize( - rayDirection );
|
|
29
|
+
dist = particleDist;
|
|
30
|
+
return FOG_HIT;
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
if ( lightHit && ( lightSampleRec.dist < dist || ! hit ) ) {
|
|
39
|
+
|
|
40
|
+
return LIGHT_HIT;
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if ( hit ) {
|
|
45
|
+
|
|
46
|
+
return SURFACE_HIT;
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return NO_HIT;
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
`;
|