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
|
@@ -1,1013 +0,0 @@
|
|
|
1
|
-
import { Matrix4, Vector2 } from 'three';
|
|
2
|
-
import { MaterialBase } from './MaterialBase.js';
|
|
3
|
-
import {
|
|
4
|
-
MeshBVHUniformStruct, UIntVertexAttributeTexture,
|
|
5
|
-
shaderStructs, shaderIntersectFunction,
|
|
6
|
-
} from 'three-mesh-bvh';
|
|
7
|
-
import { shaderMaterialStructs, shaderLightStruct } from '../shader/shaderStructs.js';
|
|
8
|
-
import { MaterialsTexture } from '../uniforms/MaterialsTexture.js';
|
|
9
|
-
import { RenderTarget2DArray } from '../uniforms/RenderTarget2DArray.js';
|
|
10
|
-
import { shaderMaterialSampling } from '../shader/shaderMaterialSampling.js';
|
|
11
|
-
import { shaderEnvMapSampling } from '../shader/shaderEnvMapSampling.js';
|
|
12
|
-
import { shaderLightSampling } from '../shader/shaderLightSampling.js';
|
|
13
|
-
import { shaderSobolCommon, shaderSobolSampling } from '../shader/shaderSobolSampling.js';
|
|
14
|
-
import { shaderUtils } from '../shader/shaderUtils.js';
|
|
15
|
-
import { shaderLayerTexelFetchFunctions } from '../shader/shaderLayerTexelFetchFunctions.js';
|
|
16
|
-
import { shaderRandFunctions } from '../shader/shaderRandFunctions.js';
|
|
17
|
-
import { PhysicalCameraUniform } from '../uniforms/PhysicalCameraUniform.js';
|
|
18
|
-
import { EquirectHdrInfoUniform } from '../uniforms/EquirectHdrInfoUniform.js';
|
|
19
|
-
import { LightsInfoUniformStruct } from '../uniforms/LightsInfoUniformStruct.js';
|
|
20
|
-
import { IESProfilesTexture } from '../uniforms/IESProfilesTexture.js';
|
|
21
|
-
import { AttributesTextureArray } from '../uniforms/AttributesTextureArray.js';
|
|
22
|
-
|
|
23
|
-
export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
24
|
-
|
|
25
|
-
onBeforeRender() {
|
|
26
|
-
|
|
27
|
-
this.setDefine( 'FEATURE_DOF', this.physicalCamera.bokehSize === 0 ? 0 : 1 );
|
|
28
|
-
this.setDefine( 'FEATURE_BACKGROUND_MAP', this.backgroundMap ? 1 : 0 );
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
constructor( parameters ) {
|
|
33
|
-
|
|
34
|
-
super( {
|
|
35
|
-
|
|
36
|
-
transparent: true,
|
|
37
|
-
depthWrite: false,
|
|
38
|
-
|
|
39
|
-
defines: {
|
|
40
|
-
FEATURE_MIS: 1,
|
|
41
|
-
FEATURE_RUSSIAN_ROULETTE: 1,
|
|
42
|
-
FEATURE_DOF: 1,
|
|
43
|
-
FEATURE_BACKGROUND_MAP: 0,
|
|
44
|
-
// 0 = Perspective
|
|
45
|
-
// 1 = Orthographic
|
|
46
|
-
// 2 = Equirectangular
|
|
47
|
-
CAMERA_TYPE: 0,
|
|
48
|
-
|
|
49
|
-
ATTR_NORMAL: 0,
|
|
50
|
-
ATTR_TANGENT: 1,
|
|
51
|
-
ATTR_UV: 2,
|
|
52
|
-
ATTR_COLOR: 3,
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
uniforms: {
|
|
56
|
-
resolution: { value: new Vector2() },
|
|
57
|
-
|
|
58
|
-
bounces: { value: 10 },
|
|
59
|
-
transmissiveBounces: { value: 10 },
|
|
60
|
-
physicalCamera: { value: new PhysicalCameraUniform() },
|
|
61
|
-
|
|
62
|
-
bvh: { value: new MeshBVHUniformStruct() },
|
|
63
|
-
attributesArray: { value: new AttributesTextureArray() },
|
|
64
|
-
materialIndexAttribute: { value: new UIntVertexAttributeTexture() },
|
|
65
|
-
materials: { value: new MaterialsTexture() },
|
|
66
|
-
textures: { value: new RenderTarget2DArray().texture },
|
|
67
|
-
lights: { value: new LightsInfoUniformStruct() },
|
|
68
|
-
iesProfiles: { value: new IESProfilesTexture().texture },
|
|
69
|
-
cameraWorldMatrix: { value: new Matrix4() },
|
|
70
|
-
invProjectionMatrix: { value: new Matrix4() },
|
|
71
|
-
backgroundBlur: { value: 0.0 },
|
|
72
|
-
environmentIntensity: { value: 1.0 },
|
|
73
|
-
environmentRotation: { value: new Matrix4() },
|
|
74
|
-
envMapInfo: { value: new EquirectHdrInfoUniform() },
|
|
75
|
-
backgroundMap: { value: null },
|
|
76
|
-
|
|
77
|
-
seed: { value: 0 },
|
|
78
|
-
opacity: { value: 1 },
|
|
79
|
-
filterGlossyFactor: { value: 0.0 },
|
|
80
|
-
|
|
81
|
-
backgroundAlpha: { value: 1.0 },
|
|
82
|
-
sobolTexture: { value: null },
|
|
83
|
-
},
|
|
84
|
-
|
|
85
|
-
vertexShader: /* glsl */`
|
|
86
|
-
|
|
87
|
-
varying vec2 vUv;
|
|
88
|
-
void main() {
|
|
89
|
-
|
|
90
|
-
vec4 mvPosition = vec4( position, 1.0 );
|
|
91
|
-
mvPosition = modelViewMatrix * mvPosition;
|
|
92
|
-
gl_Position = projectionMatrix * mvPosition;
|
|
93
|
-
|
|
94
|
-
vUv = uv;
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
`,
|
|
99
|
-
|
|
100
|
-
fragmentShader: /* glsl */`
|
|
101
|
-
#define RAY_OFFSET 1e-4
|
|
102
|
-
#define INFINITY 1e20
|
|
103
|
-
|
|
104
|
-
precision highp isampler2D;
|
|
105
|
-
precision highp usampler2D;
|
|
106
|
-
precision highp sampler2DArray;
|
|
107
|
-
vec4 envMapTexelToLinear( vec4 a ) { return a; }
|
|
108
|
-
#include <common>
|
|
109
|
-
|
|
110
|
-
${ shaderRandFunctions }
|
|
111
|
-
${ shaderSobolCommon }
|
|
112
|
-
${ shaderSobolSampling }
|
|
113
|
-
${ shaderStructs }
|
|
114
|
-
${ shaderIntersectFunction }
|
|
115
|
-
${ shaderMaterialStructs }
|
|
116
|
-
${ shaderLightStruct }
|
|
117
|
-
|
|
118
|
-
${ shaderLayerTexelFetchFunctions }
|
|
119
|
-
${ shaderUtils }
|
|
120
|
-
${ shaderMaterialSampling }
|
|
121
|
-
${ shaderEnvMapSampling }
|
|
122
|
-
|
|
123
|
-
uniform mat4 environmentRotation;
|
|
124
|
-
uniform float backgroundBlur;
|
|
125
|
-
uniform float backgroundAlpha;
|
|
126
|
-
|
|
127
|
-
#if FEATURE_BACKGROUND_MAP
|
|
128
|
-
|
|
129
|
-
uniform sampler2D backgroundMap;
|
|
130
|
-
|
|
131
|
-
#endif
|
|
132
|
-
|
|
133
|
-
#if FEATURE_DOF
|
|
134
|
-
|
|
135
|
-
uniform PhysicalCamera physicalCamera;
|
|
136
|
-
|
|
137
|
-
#endif
|
|
138
|
-
|
|
139
|
-
uniform vec2 resolution;
|
|
140
|
-
uniform int bounces;
|
|
141
|
-
uniform int transmissiveBounces;
|
|
142
|
-
uniform mat4 cameraWorldMatrix;
|
|
143
|
-
uniform mat4 invProjectionMatrix;
|
|
144
|
-
uniform sampler2DArray attributesArray;
|
|
145
|
-
uniform usampler2D materialIndexAttribute;
|
|
146
|
-
uniform BVH bvh;
|
|
147
|
-
uniform float environmentIntensity;
|
|
148
|
-
uniform float filterGlossyFactor;
|
|
149
|
-
uniform int seed;
|
|
150
|
-
uniform float opacity;
|
|
151
|
-
uniform sampler2D materials;
|
|
152
|
-
uniform LightsInfo lights;
|
|
153
|
-
uniform sampler2DArray iesProfiles;
|
|
154
|
-
|
|
155
|
-
${ shaderLightSampling }
|
|
156
|
-
|
|
157
|
-
uniform EquirectHdrInfo envMapInfo;
|
|
158
|
-
|
|
159
|
-
uniform sampler2DArray textures;
|
|
160
|
-
varying vec2 vUv;
|
|
161
|
-
|
|
162
|
-
float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
|
|
163
|
-
|
|
164
|
-
return clamp(
|
|
165
|
-
max(
|
|
166
|
-
roughness,
|
|
167
|
-
accumulatedRoughness * filterGlossyFactor * 5.0 ),
|
|
168
|
-
0.0,
|
|
169
|
-
1.0
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
vec3 sampleBackground( vec3 direction, vec2 uv ) {
|
|
175
|
-
|
|
176
|
-
vec3 sampleDir = normalize( direction + getHemisphereSample( direction, uv ) * 0.5 * backgroundBlur );
|
|
177
|
-
|
|
178
|
-
#if FEATURE_BACKGROUND_MAP
|
|
179
|
-
|
|
180
|
-
return sampleEquirectEnvMapColor( sampleDir, backgroundMap );
|
|
181
|
-
|
|
182
|
-
#else
|
|
183
|
-
|
|
184
|
-
return environmentIntensity * sampleEquirectEnvMapColor( sampleDir, envMapInfo.map );
|
|
185
|
-
|
|
186
|
-
#endif
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// step through multiple surface hits and accumulate color attenuation based on transmissive surfaces
|
|
191
|
-
bool attenuateHit(
|
|
192
|
-
BVH bvh, vec3 rayOrigin, vec3 rayDirection, float rayDist,
|
|
193
|
-
int traversals, int transparentTraversals, bool isShadowRay, out vec3 color
|
|
194
|
-
) {
|
|
195
|
-
|
|
196
|
-
// hit results
|
|
197
|
-
uvec4 faceIndices = uvec4( 0u );
|
|
198
|
-
vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
|
|
199
|
-
vec3 barycoord = vec3( 0.0 );
|
|
200
|
-
float side = 1.0;
|
|
201
|
-
float dist = 0.0;
|
|
202
|
-
|
|
203
|
-
color = vec3( 1.0 );
|
|
204
|
-
|
|
205
|
-
// TODO: we should be using sobol sampling here instead of rand but the sobol bounce and path indices need to be incremented
|
|
206
|
-
// and then reset.
|
|
207
|
-
for ( int i = 0; i < traversals; i ++ ) {
|
|
208
|
-
|
|
209
|
-
if ( bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist ) ) {
|
|
210
|
-
|
|
211
|
-
if ( dist > rayDist ) {
|
|
212
|
-
|
|
213
|
-
return true;
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// TODO: attenuate the contribution based on the PDF of the resulting ray including refraction values
|
|
218
|
-
// Should be able to work using the material BSDF functions which will take into account specularity, etc.
|
|
219
|
-
// TODO: should we account for emissive surfaces here?
|
|
220
|
-
|
|
221
|
-
vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, barycoord, faceIndices.xyz ).xy;
|
|
222
|
-
vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, barycoord, faceIndices.xyz );
|
|
223
|
-
|
|
224
|
-
uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;
|
|
225
|
-
Material material = readMaterialInfo( materials, materialIndex );
|
|
226
|
-
|
|
227
|
-
// adjust the ray to the new surface
|
|
228
|
-
bool isEntering = side == 1.0;
|
|
229
|
-
rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
|
|
230
|
-
|
|
231
|
-
if ( ! material.castShadow && isShadowRay ) {
|
|
232
|
-
|
|
233
|
-
continue;
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Opacity Test
|
|
238
|
-
|
|
239
|
-
// albedo
|
|
240
|
-
vec4 albedo = vec4( material.color, material.opacity );
|
|
241
|
-
if ( material.map != - 1 ) {
|
|
242
|
-
|
|
243
|
-
vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
|
|
244
|
-
albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if ( material.vertexColors ) {
|
|
249
|
-
|
|
250
|
-
albedo *= vertexColor;
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// alphaMap
|
|
255
|
-
if ( material.alphaMap != - 1 ) {
|
|
256
|
-
|
|
257
|
-
albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// transmission
|
|
262
|
-
float transmission = material.transmission;
|
|
263
|
-
if ( material.transmissionMap != - 1 ) {
|
|
264
|
-
|
|
265
|
-
vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
|
|
266
|
-
transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// metalness
|
|
271
|
-
float metalness = material.metalness;
|
|
272
|
-
if ( material.metalnessMap != - 1 ) {
|
|
273
|
-
|
|
274
|
-
vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
|
|
275
|
-
metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
float alphaTest = material.alphaTest;
|
|
280
|
-
bool useAlphaTest = alphaTest != 0.0;
|
|
281
|
-
float transmissionFactor = ( 1.0 - metalness ) * transmission;
|
|
282
|
-
if (
|
|
283
|
-
transmissionFactor < rand() && ! (
|
|
284
|
-
// material sidedness
|
|
285
|
-
material.side != 0.0 && side == material.side
|
|
286
|
-
|
|
287
|
-
// alpha test
|
|
288
|
-
|| useAlphaTest && albedo.a < alphaTest
|
|
289
|
-
|
|
290
|
-
// opacity
|
|
291
|
-
|| material.transparent && ! useAlphaTest && albedo.a < rand()
|
|
292
|
-
)
|
|
293
|
-
) {
|
|
294
|
-
|
|
295
|
-
return true;
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if ( side == 1.0 && isEntering ) {
|
|
300
|
-
|
|
301
|
-
// only attenuate by surface color on the way in
|
|
302
|
-
color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );
|
|
303
|
-
|
|
304
|
-
} else if ( side == - 1.0 ) {
|
|
305
|
-
|
|
306
|
-
// attenuate by medium once we hit the opposite side of the model
|
|
307
|
-
color *= transmissionAttenuation( dist, material.attenuationColor, material.attenuationDistance );
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
bool isTransmissiveRay = dot( rayDirection, faceNormal * side ) < 0.0;
|
|
312
|
-
if ( ( isTransmissiveRay || isEntering ) && transparentTraversals > 0 ) {
|
|
313
|
-
|
|
314
|
-
transparentTraversals --;
|
|
315
|
-
i --;
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
} else {
|
|
321
|
-
|
|
322
|
-
return false;
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return true;
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
vec3 ndcToRayOrigin( vec2 coord ) {
|
|
333
|
-
|
|
334
|
-
vec4 rayOrigin4 = cameraWorldMatrix * invProjectionMatrix * vec4( coord, - 1.0, 1.0 );
|
|
335
|
-
return rayOrigin4.xyz / rayOrigin4.w;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
void getCameraRay( out vec3 rayDirection, out vec3 rayOrigin ) {
|
|
339
|
-
|
|
340
|
-
vec2 ssd = vec2( 1.0 ) / resolution;
|
|
341
|
-
|
|
342
|
-
// Jitter the camera ray by finding a uv coordinate at a random sample
|
|
343
|
-
// around this pixel's UV coordinate for AA
|
|
344
|
-
vec2 ruv = sobol2( 0 );
|
|
345
|
-
vec2 jitteredUv = vUv + vec2( tentFilter( ruv.x ) * ssd.x, tentFilter( ruv.y ) * ssd.y );
|
|
346
|
-
|
|
347
|
-
#if CAMERA_TYPE == 2
|
|
348
|
-
|
|
349
|
-
// Equirectangular projection
|
|
350
|
-
vec4 rayDirection4 = vec4( equirectUvToDirection( jitteredUv ), 0.0 );
|
|
351
|
-
vec4 rayOrigin4 = vec4( 0.0, 0.0, 0.0, 1.0 );
|
|
352
|
-
|
|
353
|
-
rayDirection4 = cameraWorldMatrix * rayDirection4;
|
|
354
|
-
rayOrigin4 = cameraWorldMatrix * rayOrigin4;
|
|
355
|
-
|
|
356
|
-
rayDirection = normalize( rayDirection4.xyz );
|
|
357
|
-
rayOrigin = rayOrigin4.xyz / rayOrigin4.w;
|
|
358
|
-
|
|
359
|
-
#else
|
|
360
|
-
|
|
361
|
-
// get [- 1, 1] normalized device coordinates
|
|
362
|
-
vec2 ndc = 2.0 * jitteredUv - vec2( 1.0 );
|
|
363
|
-
rayOrigin = ndcToRayOrigin( ndc );
|
|
364
|
-
|
|
365
|
-
#if CAMERA_TYPE == 1
|
|
366
|
-
|
|
367
|
-
// Orthographic projection
|
|
368
|
-
rayDirection = ( cameraWorldMatrix * vec4( 0.0, 0.0, - 1.0, 0.0 ) ).xyz;
|
|
369
|
-
rayDirection = normalize( rayDirection );
|
|
370
|
-
|
|
371
|
-
#else
|
|
372
|
-
|
|
373
|
-
// Perspective projection
|
|
374
|
-
rayDirection = normalize( mat3(cameraWorldMatrix) * ( invProjectionMatrix * vec4( ndc, 0.0, 1.0 ) ).xyz );
|
|
375
|
-
|
|
376
|
-
#endif
|
|
377
|
-
|
|
378
|
-
#endif
|
|
379
|
-
|
|
380
|
-
#if FEATURE_DOF
|
|
381
|
-
{
|
|
382
|
-
|
|
383
|
-
// depth of field
|
|
384
|
-
vec3 focalPoint = rayOrigin + normalize( rayDirection ) * physicalCamera.focusDistance;
|
|
385
|
-
|
|
386
|
-
// get the aperture sample
|
|
387
|
-
// if blades === 0 then we assume a circle
|
|
388
|
-
vec3 shapeUVW= sobol3( 1 );
|
|
389
|
-
int blades = physicalCamera.apertureBlades;
|
|
390
|
-
float anamorphicRatio = physicalCamera.anamorphicRatio;
|
|
391
|
-
vec2 apertureSample = blades == 0 ? sampleCircle( shapeUVW.xy ) : sampleRegularNGon( blades, shapeUVW );
|
|
392
|
-
apertureSample *= physicalCamera.bokehSize * 0.5 * 1e-3;
|
|
393
|
-
|
|
394
|
-
// rotate the aperture shape
|
|
395
|
-
apertureSample =
|
|
396
|
-
rotateVector( apertureSample, physicalCamera.apertureRotation ) *
|
|
397
|
-
saturate( vec2( anamorphicRatio, 1.0 / anamorphicRatio ) );
|
|
398
|
-
|
|
399
|
-
// create the new ray
|
|
400
|
-
rayOrigin += ( cameraWorldMatrix * vec4( apertureSample, 0.0, 0.0 ) ).xyz;
|
|
401
|
-
rayDirection = focalPoint - rayOrigin;
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
#endif
|
|
405
|
-
|
|
406
|
-
rayDirection = normalize( rayDirection );
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
void main() {
|
|
411
|
-
|
|
412
|
-
rng_initialize( gl_FragCoord.xy, seed );
|
|
413
|
-
sobolPixelIndex = ( uint( gl_FragCoord.x ) << 16 ) | ( uint( gl_FragCoord.y ) );
|
|
414
|
-
sobolPathIndex = uint( seed );
|
|
415
|
-
|
|
416
|
-
vec3 rayDirection;
|
|
417
|
-
vec3 rayOrigin;
|
|
418
|
-
|
|
419
|
-
getCameraRay( rayDirection, rayOrigin );
|
|
420
|
-
|
|
421
|
-
// inverse environment rotation
|
|
422
|
-
mat3 envRotation3x3 = mat3( environmentRotation );
|
|
423
|
-
mat3 invEnvRotation3x3 = inverse( envRotation3x3 );
|
|
424
|
-
|
|
425
|
-
// final color
|
|
426
|
-
gl_FragColor = vec4( 0.0 );
|
|
427
|
-
gl_FragColor.a = 1.0;
|
|
428
|
-
|
|
429
|
-
// hit results
|
|
430
|
-
uvec4 faceIndices = uvec4( 0u );
|
|
431
|
-
vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
|
|
432
|
-
vec3 barycoord = vec3( 0.0 );
|
|
433
|
-
float side = 1.0;
|
|
434
|
-
float dist = 0.0;
|
|
435
|
-
|
|
436
|
-
// path tracing state
|
|
437
|
-
float accumulatedRoughness = 0.0;
|
|
438
|
-
float accumulatedClearcoatRoughness = 0.0;
|
|
439
|
-
bool transmissiveRay = true;
|
|
440
|
-
int transparentTraversals = transmissiveBounces;
|
|
441
|
-
vec3 throughputColor = vec3( 1.0 );
|
|
442
|
-
SampleRec sampleRec;
|
|
443
|
-
int i;
|
|
444
|
-
bool isShadowRay = false;
|
|
445
|
-
|
|
446
|
-
for ( i = 0; i < bounces; i ++ ) {
|
|
447
|
-
|
|
448
|
-
sobolBounceIndex ++;
|
|
449
|
-
|
|
450
|
-
bool hit = bvhIntersectFirstHit( bvh, rayOrigin, rayDirection, faceIndices, faceNormal, barycoord, side, dist );
|
|
451
|
-
bool firstRay = i == 0 && transparentTraversals == transmissiveBounces;
|
|
452
|
-
LightSampleRec lightHit = lightsClosestHit( lights.tex, lights.count, rayOrigin, rayDirection );
|
|
453
|
-
|
|
454
|
-
if ( lightHit.hit && ( lightHit.dist < dist || ! hit ) ) {
|
|
455
|
-
|
|
456
|
-
if ( firstRay || transmissiveRay ) {
|
|
457
|
-
|
|
458
|
-
gl_FragColor.rgb += lightHit.emission * throughputColor;
|
|
459
|
-
|
|
460
|
-
} else {
|
|
461
|
-
|
|
462
|
-
#if FEATURE_MIS
|
|
463
|
-
|
|
464
|
-
// NOTE: we skip MIS for punctual lights since they are not supported in forward PT case
|
|
465
|
-
if ( lightHit.type == SPOT_LIGHT_TYPE || lightHit.type == DIR_LIGHT_TYPE || lightHit.type == POINT_LIGHT_TYPE ) {
|
|
466
|
-
|
|
467
|
-
gl_FragColor.rgb += lightHit.emission * throughputColor;
|
|
468
|
-
|
|
469
|
-
} else {
|
|
470
|
-
|
|
471
|
-
// weight the contribution
|
|
472
|
-
float misWeight = misHeuristic( sampleRec.pdf, lightHit.pdf / float( lights.count + 1u ) );
|
|
473
|
-
gl_FragColor.rgb += lightHit.emission * throughputColor * misWeight;
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
#else
|
|
478
|
-
|
|
479
|
-
gl_FragColor.rgb += lightHit.emission * throughputColor;
|
|
480
|
-
|
|
481
|
-
#endif
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
-
break;
|
|
485
|
-
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
if ( ! hit ) {
|
|
489
|
-
|
|
490
|
-
if ( firstRay || transmissiveRay ) {
|
|
491
|
-
|
|
492
|
-
gl_FragColor.rgb += sampleBackground( envRotation3x3 * rayDirection, sobol2( 2 ) ) * throughputColor;
|
|
493
|
-
gl_FragColor.a = backgroundAlpha;
|
|
494
|
-
|
|
495
|
-
} else {
|
|
496
|
-
|
|
497
|
-
#if FEATURE_MIS
|
|
498
|
-
|
|
499
|
-
// get the PDF of the hit envmap point
|
|
500
|
-
vec3 envColor;
|
|
501
|
-
float envPdf = sampleEnvMap( envMapInfo, envRotation3x3 * rayDirection, envColor );
|
|
502
|
-
envPdf /= float( lights.count + 1u );
|
|
503
|
-
|
|
504
|
-
// and weight the contribution
|
|
505
|
-
float misWeight = misHeuristic( sampleRec.pdf, envPdf );
|
|
506
|
-
gl_FragColor.rgb += environmentIntensity * envColor * throughputColor * misWeight;
|
|
507
|
-
|
|
508
|
-
#else
|
|
509
|
-
|
|
510
|
-
gl_FragColor.rgb +=
|
|
511
|
-
environmentIntensity *
|
|
512
|
-
sampleEquirectEnvMapColor( envRotation3x3 * rayDirection, envMapInfo.map ) *
|
|
513
|
-
throughputColor;
|
|
514
|
-
|
|
515
|
-
#endif
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
break;
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;
|
|
523
|
-
Material material = readMaterialInfo( materials, materialIndex );
|
|
524
|
-
|
|
525
|
-
if ( material.matte && firstRay ) {
|
|
526
|
-
|
|
527
|
-
gl_FragColor = vec4( 0.0 );
|
|
528
|
-
break;
|
|
529
|
-
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// if we've determined that this is a shadow ray and we've hit an item with no shadow casting
|
|
533
|
-
// then skip it
|
|
534
|
-
if ( ! material.castShadow && isShadowRay ) {
|
|
535
|
-
|
|
536
|
-
rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
|
|
537
|
-
continue;
|
|
538
|
-
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// uv coord for textures
|
|
542
|
-
vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, barycoord, faceIndices.xyz ).xy;
|
|
543
|
-
vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, barycoord, faceIndices.xyz );
|
|
544
|
-
|
|
545
|
-
// albedo
|
|
546
|
-
vec4 albedo = vec4( material.color, material.opacity );
|
|
547
|
-
if ( material.map != - 1 ) {
|
|
548
|
-
|
|
549
|
-
vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
|
|
550
|
-
albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
if ( material.vertexColors ) {
|
|
554
|
-
|
|
555
|
-
albedo *= vertexColor;
|
|
556
|
-
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// alphaMap
|
|
560
|
-
if ( material.alphaMap != - 1 ) {
|
|
561
|
-
|
|
562
|
-
albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// possibly skip this sample if it's transparent, alpha test is enabled, or we hit the wrong material side
|
|
567
|
-
// and it's single sided.
|
|
568
|
-
// - alpha test is disabled when it === 0
|
|
569
|
-
// - the material sidedness test is complicated because we want light to pass through the back side but still
|
|
570
|
-
// be able to see the front side. This boolean checks if the side we hit is the front side on the first ray
|
|
571
|
-
// and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.
|
|
572
|
-
float alphaTest = material.alphaTest;
|
|
573
|
-
bool useAlphaTest = alphaTest != 0.0;
|
|
574
|
-
if (
|
|
575
|
-
// material sidedness
|
|
576
|
-
material.side != 0.0 && side != material.side
|
|
577
|
-
|
|
578
|
-
// alpha test
|
|
579
|
-
|| useAlphaTest && albedo.a < alphaTest
|
|
580
|
-
|
|
581
|
-
// opacity
|
|
582
|
-
|| material.transparent && ! useAlphaTest && albedo.a < sobol( 3 )
|
|
583
|
-
) {
|
|
584
|
-
|
|
585
|
-
rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
|
|
586
|
-
|
|
587
|
-
// only allow a limited number of transparency discards otherwise we could
|
|
588
|
-
// crash the context with too long a loop.
|
|
589
|
-
i -= sign( transparentTraversals );
|
|
590
|
-
transparentTraversals -= sign( transparentTraversals );
|
|
591
|
-
continue;
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// fetch the interpolated smooth normal
|
|
596
|
-
vec3 normal = normalize( textureSampleBarycoord(
|
|
597
|
-
attributesArray,
|
|
598
|
-
ATTR_NORMAL,
|
|
599
|
-
barycoord,
|
|
600
|
-
faceIndices.xyz
|
|
601
|
-
).xyz );
|
|
602
|
-
|
|
603
|
-
// roughness
|
|
604
|
-
float roughness = material.roughness;
|
|
605
|
-
if ( material.roughnessMap != - 1 ) {
|
|
606
|
-
|
|
607
|
-
vec3 uvPrime = material.roughnessMapTransform * vec3( uv, 1 );
|
|
608
|
-
roughness *= texture2D( textures, vec3( uvPrime.xy, material.roughnessMap ) ).g;
|
|
609
|
-
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// metalness
|
|
613
|
-
float metalness = material.metalness;
|
|
614
|
-
if ( material.metalnessMap != - 1 ) {
|
|
615
|
-
|
|
616
|
-
vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
|
|
617
|
-
metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// emission
|
|
622
|
-
vec3 emission = material.emissiveIntensity * material.emissive;
|
|
623
|
-
if ( material.emissiveMap != - 1 ) {
|
|
624
|
-
|
|
625
|
-
vec3 uvPrime = material.emissiveMapTransform * vec3( uv, 1 );
|
|
626
|
-
emission *= texture2D( textures, vec3( uvPrime.xy, material.emissiveMap ) ).xyz;
|
|
627
|
-
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// transmission
|
|
631
|
-
float transmission = material.transmission;
|
|
632
|
-
if ( material.transmissionMap != - 1 ) {
|
|
633
|
-
|
|
634
|
-
vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
|
|
635
|
-
transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
// normal
|
|
640
|
-
if ( material.flatShading ) {
|
|
641
|
-
|
|
642
|
-
// if we're rendering a flat shaded object then use the face normals - the face normal
|
|
643
|
-
// is provided based on the side the ray hits the mesh so flip it to align with the
|
|
644
|
-
// interpolated vertex normals.
|
|
645
|
-
normal = faceNormal * side;
|
|
646
|
-
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
vec3 baseNormal = normal;
|
|
650
|
-
if ( material.normalMap != - 1 ) {
|
|
651
|
-
|
|
652
|
-
vec4 tangentSample = textureSampleBarycoord(
|
|
653
|
-
attributesArray,
|
|
654
|
-
ATTR_TANGENT,
|
|
655
|
-
barycoord,
|
|
656
|
-
faceIndices.xyz
|
|
657
|
-
);
|
|
658
|
-
|
|
659
|
-
// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
|
|
660
|
-
// resulting in NaNs and slow path tracing.
|
|
661
|
-
if ( length( tangentSample.xyz ) > 0.0 ) {
|
|
662
|
-
|
|
663
|
-
vec3 tangent = normalize( tangentSample.xyz );
|
|
664
|
-
vec3 bitangent = normalize( cross( normal, tangent ) * tangentSample.w );
|
|
665
|
-
mat3 vTBN = mat3( tangent, bitangent, normal );
|
|
666
|
-
|
|
667
|
-
vec3 uvPrime = material.normalMapTransform * vec3( uv, 1 );
|
|
668
|
-
vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.normalMap ) ).xyz * 2.0 - 1.0;
|
|
669
|
-
texNormal.xy *= material.normalScale;
|
|
670
|
-
normal = vTBN * texNormal;
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
normal *= side;
|
|
677
|
-
|
|
678
|
-
// clearcoat
|
|
679
|
-
float clearcoat = material.clearcoat;
|
|
680
|
-
if ( material.clearcoatMap != - 1 ) {
|
|
681
|
-
|
|
682
|
-
vec3 uvPrime = material.clearcoatMapTransform * vec3( uv, 1 );
|
|
683
|
-
clearcoat *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatMap ) ).r;
|
|
684
|
-
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// clearcoatRoughness
|
|
688
|
-
float clearcoatRoughness = material.clearcoatRoughness;
|
|
689
|
-
if ( material.clearcoatRoughnessMap != - 1 ) {
|
|
690
|
-
|
|
691
|
-
vec3 uvPrime = material.clearcoatRoughnessMapTransform * vec3( uv, 1 );
|
|
692
|
-
clearcoatRoughness *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatRoughnessMap ) ).g;
|
|
693
|
-
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
// clearcoatNormal
|
|
697
|
-
vec3 clearcoatNormal = baseNormal;
|
|
698
|
-
if ( material.clearcoatNormalMap != - 1 ) {
|
|
699
|
-
|
|
700
|
-
vec4 tangentSample = textureSampleBarycoord(
|
|
701
|
-
attributesArray,
|
|
702
|
-
ATTR_TANGENT,
|
|
703
|
-
barycoord,
|
|
704
|
-
faceIndices.xyz
|
|
705
|
-
);
|
|
706
|
-
|
|
707
|
-
// some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
|
|
708
|
-
// resulting in NaNs and slow path tracing.
|
|
709
|
-
if ( length( tangentSample.xyz ) > 0.0 ) {
|
|
710
|
-
|
|
711
|
-
vec3 tangent = normalize( tangentSample.xyz );
|
|
712
|
-
vec3 bitangent = normalize( cross( clearcoatNormal, tangent ) * tangentSample.w );
|
|
713
|
-
mat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );
|
|
714
|
-
|
|
715
|
-
vec3 uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1 );
|
|
716
|
-
vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.clearcoatNormalMap ) ).xyz * 2.0 - 1.0;
|
|
717
|
-
texNormal.xy *= material.clearcoatNormalScale;
|
|
718
|
-
clearcoatNormal = vTBN * texNormal;
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
clearcoatNormal *= side;
|
|
725
|
-
|
|
726
|
-
// sheenColor
|
|
727
|
-
vec3 sheenColor = material.sheenColor;
|
|
728
|
-
if ( material.sheenColorMap != - 1 ) {
|
|
729
|
-
|
|
730
|
-
vec3 uvPrime = material.sheenColorMapTransform * vec3( uv, 1 );
|
|
731
|
-
sheenColor *= texture2D( textures, vec3( uvPrime.xy, material.sheenColorMap ) ).rgb;
|
|
732
|
-
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
// sheenRoughness
|
|
736
|
-
float sheenRoughness = material.sheenRoughness;
|
|
737
|
-
if ( material.sheenRoughnessMap != - 1 ) {
|
|
738
|
-
|
|
739
|
-
vec3 uvPrime = material.sheenRoughnessMapTransform * vec3( uv, 1 );
|
|
740
|
-
sheenRoughness *= texture2D( textures, vec3( uvPrime.xy, material.sheenRoughnessMap ) ).a;
|
|
741
|
-
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
// iridescence
|
|
745
|
-
float iridescence = material.iridescence;
|
|
746
|
-
if ( material.iridescenceMap != - 1 ) {
|
|
747
|
-
|
|
748
|
-
vec3 uvPrime = material.iridescenceMapTransform * vec3( uv, 1 );
|
|
749
|
-
iridescence *= texture2D( textures, vec3( uvPrime.xy, material.iridescenceMap ) ).r;
|
|
750
|
-
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
// iridescence thickness
|
|
754
|
-
float iridescenceThickness = material.iridescenceThicknessMaximum;
|
|
755
|
-
if ( material.iridescenceThicknessMap != - 1 ) {
|
|
756
|
-
|
|
757
|
-
vec3 uvPrime = material.iridescenceThicknessMapTransform * vec3( uv, 1 );
|
|
758
|
-
float iridescenceThicknessSampled = texture2D( textures, vec3( uvPrime.xy, material.iridescenceThicknessMap ) ).g;
|
|
759
|
-
iridescenceThickness = mix( material.iridescenceThicknessMinimum, material.iridescenceThicknessMaximum, iridescenceThicknessSampled );
|
|
760
|
-
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
iridescence = iridescenceThickness == 0.0 ? 0.0 : iridescence;
|
|
764
|
-
|
|
765
|
-
// specular color
|
|
766
|
-
vec3 specularColor = material.specularColor;
|
|
767
|
-
if ( material.specularColorMap != - 1 ) {
|
|
768
|
-
|
|
769
|
-
vec3 uvPrime = material.specularColorMapTransform * vec3( uv, 1 );
|
|
770
|
-
specularColor *= texture2D( textures, vec3( uvPrime.xy, material.specularColorMap ) ).rgb;
|
|
771
|
-
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// specular intensity
|
|
775
|
-
float specularIntensity = material.specularIntensity;
|
|
776
|
-
if ( material.specularIntensityMap != - 1 ) {
|
|
777
|
-
|
|
778
|
-
vec3 uvPrime = material.specularIntensityMapTransform * vec3( uv, 1 );
|
|
779
|
-
specularIntensity *= texture2D( textures, vec3( uvPrime.xy, material.specularIntensityMap ) ).a;
|
|
780
|
-
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
SurfaceRec surfaceRec;
|
|
784
|
-
surfaceRec.normal = normal;
|
|
785
|
-
surfaceRec.faceNormal = faceNormal;
|
|
786
|
-
surfaceRec.transmission = transmission;
|
|
787
|
-
surfaceRec.ior = material.ior;
|
|
788
|
-
surfaceRec.emission = emission;
|
|
789
|
-
surfaceRec.metalness = metalness;
|
|
790
|
-
surfaceRec.color = albedo.rgb;
|
|
791
|
-
surfaceRec.clearcoat = clearcoat;
|
|
792
|
-
surfaceRec.sheen = material.sheen;
|
|
793
|
-
surfaceRec.sheenColor = sheenColor;
|
|
794
|
-
surfaceRec.iridescence = iridescence;
|
|
795
|
-
surfaceRec.iridescenceIor = material.iridescenceIor;
|
|
796
|
-
surfaceRec.iridescenceThickness = iridescenceThickness;
|
|
797
|
-
surfaceRec.specularColor = specularColor;
|
|
798
|
-
surfaceRec.specularIntensity = specularIntensity;
|
|
799
|
-
surfaceRec.attenuationColor = material.attenuationColor;
|
|
800
|
-
surfaceRec.attenuationDistance = material.attenuationDistance;
|
|
801
|
-
|
|
802
|
-
// apply perceptual roughness factor from gltf. sheen perceptual roughness is
|
|
803
|
-
// applied by its brdf function
|
|
804
|
-
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces
|
|
805
|
-
surfaceRec.roughness = roughness * roughness;
|
|
806
|
-
surfaceRec.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;
|
|
807
|
-
surfaceRec.sheenRoughness = sheenRoughness;
|
|
808
|
-
|
|
809
|
-
// frontFace is used to determine transmissive properties and PDF. If no transmission is used
|
|
810
|
-
// then we can just always assume this is a front face.
|
|
811
|
-
surfaceRec.frontFace = side == 1.0 || transmission == 0.0;
|
|
812
|
-
surfaceRec.eta = material.thinFilm || surfaceRec.frontFace ? 1.0 / material.ior : material.ior;
|
|
813
|
-
surfaceRec.f0 = iorRatioToF0( surfaceRec.eta );
|
|
814
|
-
surfaceRec.thinFilm = material.thinFilm;
|
|
815
|
-
|
|
816
|
-
// Compute the filtered roughness value to use during specular reflection computations.
|
|
817
|
-
// The accumulated roughness value is scaled by a user setting and a "magic value" of 5.0.
|
|
818
|
-
// If we're exiting something transmissive then scale the factor down significantly so we can retain
|
|
819
|
-
// sharp internal reflections
|
|
820
|
-
surfaceRec.filteredRoughness = applyFilteredGlossy( surfaceRec.roughness, accumulatedRoughness );
|
|
821
|
-
surfaceRec.filteredClearcoatRoughness = applyFilteredGlossy( surfaceRec.clearcoatRoughness, accumulatedClearcoatRoughness );
|
|
822
|
-
|
|
823
|
-
mat3 normalBasis = getBasisFromNormal( surfaceRec.normal );
|
|
824
|
-
mat3 invBasis = inverse( normalBasis );
|
|
825
|
-
|
|
826
|
-
mat3 clearcoatNormalBasis = getBasisFromNormal( clearcoatNormal );
|
|
827
|
-
mat3 clearcoatInvBasis = inverse( clearcoatNormalBasis );
|
|
828
|
-
|
|
829
|
-
vec3 outgoing = - normalize( invBasis * rayDirection );
|
|
830
|
-
vec3 clearcoatOutgoing = - normalize( clearcoatInvBasis * rayDirection );
|
|
831
|
-
sampleRec = bsdfSample( outgoing, clearcoatOutgoing, normalBasis, invBasis, clearcoatNormalBasis, clearcoatInvBasis, surfaceRec );
|
|
832
|
-
|
|
833
|
-
bool wasBelowSurface = dot( rayDirection, faceNormal ) > 0.0;
|
|
834
|
-
isShadowRay = sampleRec.specularPdf < sobol( 4 );
|
|
835
|
-
|
|
836
|
-
vec3 prevRayDirection = rayDirection;
|
|
837
|
-
rayDirection = normalize( normalBasis * sampleRec.direction );
|
|
838
|
-
|
|
839
|
-
bool isBelowSurface = dot( rayDirection, faceNormal ) < 0.0;
|
|
840
|
-
rayOrigin = stepRayOrigin( rayOrigin, prevRayDirection, isBelowSurface ? - faceNormal : faceNormal, dist );
|
|
841
|
-
|
|
842
|
-
// direct env map sampling
|
|
843
|
-
#if FEATURE_MIS
|
|
844
|
-
|
|
845
|
-
// uniformly pick a light or environment map
|
|
846
|
-
if( sobol( 5 ) > 1.0 / float( lights.count + 1u ) ) {
|
|
847
|
-
|
|
848
|
-
// sample a light or environment
|
|
849
|
-
LightSampleRec lightSampleRec = randomLightSample( lights.tex, iesProfiles, lights.count, rayOrigin, sobol3( 6 ) );
|
|
850
|
-
|
|
851
|
-
bool isSampleBelowSurface = dot( faceNormal, lightSampleRec.direction ) < 0.0;
|
|
852
|
-
if ( isSampleBelowSurface ) {
|
|
853
|
-
|
|
854
|
-
lightSampleRec.pdf = 0.0;
|
|
855
|
-
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
// check if a ray could even reach the light area
|
|
859
|
-
vec3 attenuatedColor;
|
|
860
|
-
if (
|
|
861
|
-
lightSampleRec.pdf > 0.0 &&
|
|
862
|
-
isDirectionValid( lightSampleRec.direction, normal, faceNormal ) &&
|
|
863
|
-
! attenuateHit( bvh, rayOrigin, lightSampleRec.direction, lightSampleRec.dist, bounces - i, transparentTraversals, isShadowRay, attenuatedColor )
|
|
864
|
-
) {
|
|
865
|
-
|
|
866
|
-
// get the material pdf
|
|
867
|
-
vec3 sampleColor;
|
|
868
|
-
float lightMaterialPdf = bsdfResult( outgoing, clearcoatOutgoing, normalize( invBasis * lightSampleRec.direction ), normalize( clearcoatInvBasis * lightSampleRec.direction ), surfaceRec, sampleColor );
|
|
869
|
-
bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );
|
|
870
|
-
if ( lightMaterialPdf > 0.0 && isValidSampleColor ) {
|
|
871
|
-
|
|
872
|
-
// weight the direct light contribution
|
|
873
|
-
float lightPdf = lightSampleRec.pdf / float( lights.count + 1u );
|
|
874
|
-
float misWeight = lightSampleRec.type == SPOT_LIGHT_TYPE || lightSampleRec.type == DIR_LIGHT_TYPE || lightSampleRec.type == POINT_LIGHT_TYPE ? 1.0 : misHeuristic( lightPdf, lightMaterialPdf );
|
|
875
|
-
gl_FragColor.rgb += attenuatedColor * lightSampleRec.emission * throughputColor * sampleColor * misWeight / lightPdf;
|
|
876
|
-
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
} else {
|
|
882
|
-
|
|
883
|
-
// find a sample in the environment map to include in the contribution
|
|
884
|
-
vec3 envColor, envDirection;
|
|
885
|
-
float envPdf = sampleEnvMapProbability( envMapInfo, sobol2( 7 ), envColor, envDirection );
|
|
886
|
-
envDirection = invEnvRotation3x3 * envDirection;
|
|
887
|
-
|
|
888
|
-
// this env sampling is not set up for transmissive sampling and yields overly bright
|
|
889
|
-
// results so we ignore the sample in this case.
|
|
890
|
-
// TODO: this should be improved but how? The env samples could traverse a few layers?
|
|
891
|
-
bool isSampleBelowSurface = dot( faceNormal, envDirection ) < 0.0;
|
|
892
|
-
if ( isSampleBelowSurface ) {
|
|
893
|
-
|
|
894
|
-
envPdf = 0.0;
|
|
895
|
-
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
// check if a ray could even reach the surface
|
|
899
|
-
vec3 attenuatedColor;
|
|
900
|
-
if (
|
|
901
|
-
envPdf > 0.0 &&
|
|
902
|
-
isDirectionValid( envDirection, normal, faceNormal ) &&
|
|
903
|
-
! attenuateHit( bvh, rayOrigin, envDirection, INFINITY, bounces - i, transparentTraversals, isShadowRay, attenuatedColor )
|
|
904
|
-
) {
|
|
905
|
-
|
|
906
|
-
// get the material pdf
|
|
907
|
-
vec3 sampleColor;
|
|
908
|
-
float envMaterialPdf = bsdfResult( outgoing, clearcoatOutgoing, normalize( invBasis * envDirection ), normalize( clearcoatInvBasis * envDirection ), surfaceRec, sampleColor );
|
|
909
|
-
bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );
|
|
910
|
-
if ( envMaterialPdf > 0.0 && isValidSampleColor ) {
|
|
911
|
-
|
|
912
|
-
// weight the direct light contribution
|
|
913
|
-
envPdf /= float( lights.count + 1u );
|
|
914
|
-
float misWeight = misHeuristic( envPdf, envMaterialPdf );
|
|
915
|
-
gl_FragColor.rgb += attenuatedColor * environmentIntensity * envColor * throughputColor * sampleColor * misWeight / envPdf;
|
|
916
|
-
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
}
|
|
922
|
-
#endif
|
|
923
|
-
|
|
924
|
-
// accumulate a roughness value to offset diffuse, specular, diffuse rays that have high contribution
|
|
925
|
-
// to a single pixel resulting in fireflies
|
|
926
|
-
if ( ! isBelowSurface ) {
|
|
927
|
-
|
|
928
|
-
// determine if this is a rough normal or not by checking how far off straight up it is
|
|
929
|
-
vec3 halfVector = normalize( outgoing + sampleRec.direction );
|
|
930
|
-
accumulatedRoughness += sin( acosApprox( halfVector.z ) );
|
|
931
|
-
|
|
932
|
-
vec3 clearcoatHalfVector = normalize( clearcoatOutgoing + sampleRec.clearcoatDirection );
|
|
933
|
-
accumulatedClearcoatRoughness += sin( acosApprox( clearcoatHalfVector.z ) );
|
|
934
|
-
|
|
935
|
-
transmissiveRay = false;
|
|
936
|
-
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
// if we're bouncing around the inside a transmissive material then decrement
|
|
940
|
-
// perform this separate from a bounce
|
|
941
|
-
bool isTransmissiveRay = dot( rayDirection, faceNormal * side ) < 0.0;
|
|
942
|
-
if ( ( isTransmissiveRay || isBelowSurface ) && transparentTraversals > 0 ) {
|
|
943
|
-
|
|
944
|
-
transparentTraversals --;
|
|
945
|
-
i --;
|
|
946
|
-
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
// accumulate color
|
|
950
|
-
gl_FragColor.rgb += ( emission * throughputColor );
|
|
951
|
-
|
|
952
|
-
// skip the sample if our PDF or ray is impossible
|
|
953
|
-
if ( sampleRec.pdf <= 0.0 || ! isDirectionValid( rayDirection, normal, faceNormal) ) {
|
|
954
|
-
|
|
955
|
-
break;
|
|
956
|
-
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
#if FEATURE_RUSSIAN_ROULETTE
|
|
960
|
-
|
|
961
|
-
// russian roulette path termination
|
|
962
|
-
// https://www.arnoldrenderer.com/research/physically_based_shader_design_in_arnold.pdf
|
|
963
|
-
uint minBounces = 3u;
|
|
964
|
-
float depthProb = float( sobolBounceIndex < minBounces );
|
|
965
|
-
|
|
966
|
-
float rrProb = luminance( throughputColor * sampleRec.color / sampleRec.pdf );
|
|
967
|
-
rrProb /= luminance( throughputColor );
|
|
968
|
-
rrProb = sqrt( rrProb );
|
|
969
|
-
rrProb = max( rrProb, depthProb );
|
|
970
|
-
rrProb = min( rrProb, 1.0 );
|
|
971
|
-
if ( sobol( 8 ) > rrProb ) {
|
|
972
|
-
|
|
973
|
-
break;
|
|
974
|
-
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
// perform sample clamping here to avoid bright pixels
|
|
978
|
-
throughputColor *= min( 1.0 / rrProb, 20.0 );
|
|
979
|
-
|
|
980
|
-
#endif
|
|
981
|
-
|
|
982
|
-
throughputColor *= sampleRec.color / sampleRec.pdf;
|
|
983
|
-
|
|
984
|
-
// attenuate the throughput color by the medium color
|
|
985
|
-
if ( side == - 1.0 ) {
|
|
986
|
-
|
|
987
|
-
throughputColor *= transmissionAttenuation( dist, surfaceRec.attenuationColor, surfaceRec.attenuationDistance );
|
|
988
|
-
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
// discard the sample if there are any NaNs
|
|
992
|
-
if ( any( isnan( throughputColor ) ) || any( isinf( throughputColor ) ) ) {
|
|
993
|
-
|
|
994
|
-
break;
|
|
995
|
-
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
gl_FragColor.a *= opacity;
|
|
1002
|
-
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
|
-
`
|
|
1006
|
-
|
|
1007
|
-
} );
|
|
1008
|
-
|
|
1009
|
-
this.setValues( parameters );
|
|
1010
|
-
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
}
|