three-gpu-pathtracer 0.0.4 → 0.0.5
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/README.md +60 -10
- package/build/index.module.js +854 -154
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +854 -152
- package/build/index.umd.cjs.map +1 -1
- package/package.json +1 -1
- package/src/core/DynamicPathTracingSceneGenerator.js +16 -11
- package/src/core/EquirectCamera.js +13 -0
- package/src/core/PathTracingRenderer.js +19 -1
- package/src/core/PathTracingSceneGenerator.js +36 -20
- package/src/index.js +1 -0
- package/src/materials/PhysicalPathTracingMaterial.js +197 -33
- package/src/shader/shaderEnvMapSampling.js +0 -8
- package/src/shader/shaderLightSampling.js +87 -0
- package/src/shader/shaderMaterialSampling.js +207 -51
- package/src/shader/shaderStructs.js +68 -8
- package/src/shader/shaderUtils.js +41 -0
- package/src/uniforms/LightsTexture.js +83 -0
- package/src/uniforms/MaterialsTexture.js +93 -25
- package/src/workers/PathTracingSceneWorker.js +2 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const shaderLightSampling = /* glsl */`
|
|
2
|
+
|
|
3
|
+
struct LightSampleRec {
|
|
4
|
+
bool hit;
|
|
5
|
+
float dist;
|
|
6
|
+
vec3 direction;
|
|
7
|
+
float pdf;
|
|
8
|
+
vec3 emission;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
LightSampleRec lightsClosestHit( sampler2D lights, uint lightCount, vec3 rayOrigin, vec3 rayDirection ) {
|
|
12
|
+
|
|
13
|
+
LightSampleRec lightSampleRec;
|
|
14
|
+
lightSampleRec.hit = false;
|
|
15
|
+
|
|
16
|
+
uint l;
|
|
17
|
+
for ( l = 0u; l < lightCount; l++ ) {
|
|
18
|
+
|
|
19
|
+
Light light = readLightInfo( lights, l );
|
|
20
|
+
|
|
21
|
+
vec3 u = light.u;
|
|
22
|
+
vec3 v = light.v;
|
|
23
|
+
|
|
24
|
+
// check for backface
|
|
25
|
+
vec3 normal = normalize( cross( u, v ) );
|
|
26
|
+
if ( dot( normal, rayDirection ) < 0.0 ) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
u *= 1.0 / dot(u, u);
|
|
31
|
+
v *= 1.0 / dot(v, v);
|
|
32
|
+
|
|
33
|
+
float dist;
|
|
34
|
+
if ( intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) {
|
|
35
|
+
|
|
36
|
+
if ( dist < lightSampleRec.dist || !lightSampleRec.hit ) {
|
|
37
|
+
|
|
38
|
+
lightSampleRec.hit = true;
|
|
39
|
+
lightSampleRec.dist = dist;
|
|
40
|
+
float cosTheta = dot( rayDirection, normal );
|
|
41
|
+
lightSampleRec.pdf = ( dist * dist ) / ( light.area * cosTheta );
|
|
42
|
+
lightSampleRec.emission = light.color * light.intensity;
|
|
43
|
+
lightSampleRec.direction = rayDirection;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return lightSampleRec;
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
LightSampleRec randomRectAreaLightSample( Light light, vec3 rayOrigin ) {
|
|
55
|
+
|
|
56
|
+
LightSampleRec lightSampleRec;
|
|
57
|
+
lightSampleRec.hit = true;
|
|
58
|
+
|
|
59
|
+
lightSampleRec.emission = light.color * light.intensity;
|
|
60
|
+
|
|
61
|
+
vec3 randomPos = light.position + light.u * ( rand() - 0.5 ) + light.v * ( rand() - 0.5 );
|
|
62
|
+
vec3 toLight = randomPos - rayOrigin;
|
|
63
|
+
float lightDistSq = dot( toLight, toLight );
|
|
64
|
+
lightSampleRec.dist = length( toLight );
|
|
65
|
+
|
|
66
|
+
vec3 direction = normalize( toLight );
|
|
67
|
+
lightSampleRec.direction = direction;
|
|
68
|
+
|
|
69
|
+
vec3 lightNormal = normalize( cross( light.u, light.v ) );
|
|
70
|
+
lightSampleRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );
|
|
71
|
+
|
|
72
|
+
return lightSampleRec;
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
LightSampleRec randomLightSample( sampler2D lights, uint lightCount, vec3 rayOrigin ) {
|
|
77
|
+
|
|
78
|
+
// pick a random light
|
|
79
|
+
uint l = uint( rand() * float( lightCount ) );
|
|
80
|
+
Light light = readLightInfo( lights, l );
|
|
81
|
+
|
|
82
|
+
// sample the light
|
|
83
|
+
return randomRectAreaLightSample( light, rayOrigin );
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
`;
|
|
@@ -13,12 +13,16 @@ struct SurfaceRec {
|
|
|
13
13
|
vec3 emission;
|
|
14
14
|
float transmission;
|
|
15
15
|
float ior;
|
|
16
|
+
float clearcoat;
|
|
17
|
+
float clearcoatRoughness;
|
|
18
|
+
float filteredClearcoatRoughness;
|
|
16
19
|
};
|
|
17
20
|
|
|
18
21
|
struct SampleRec {
|
|
19
22
|
float specularPdf;
|
|
20
23
|
float pdf;
|
|
21
24
|
vec3 direction;
|
|
25
|
+
vec3 clearcoatDirection;
|
|
22
26
|
vec3 color;
|
|
23
27
|
};
|
|
24
28
|
|
|
@@ -57,10 +61,10 @@ vec3 diffuseColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
57
61
|
// specular
|
|
58
62
|
float specularPDF( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
59
63
|
|
|
60
|
-
// See equation (
|
|
64
|
+
// See equation (27) in http://jcgt.org/published/0003/02/03/
|
|
61
65
|
float filteredRoughness = surf.filteredRoughness;
|
|
62
66
|
vec3 halfVector = getHalfVector( wi, wo );
|
|
63
|
-
return ggxPDF(
|
|
67
|
+
return ggxPDF( wo, halfVector, filteredRoughness ) / ( 4.0 * dot( wi, halfVector ) );
|
|
64
68
|
|
|
65
69
|
}
|
|
66
70
|
|
|
@@ -214,7 +218,97 @@ vec3 transmissionColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
214
218
|
|
|
215
219
|
}
|
|
216
220
|
|
|
217
|
-
|
|
221
|
+
// clearcoat
|
|
222
|
+
float clearcoatPDF( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
223
|
+
|
|
224
|
+
// See equation (27) in http://jcgt.org/published/0003/02/03/
|
|
225
|
+
float filteredClearcoatRoughness = surf.filteredClearcoatRoughness;
|
|
226
|
+
vec3 halfVector = getHalfVector( wi, wo );
|
|
227
|
+
return ggxPDF( wo, halfVector, filteredClearcoatRoughness ) / ( 4.0 * dot( wi, halfVector ) );
|
|
228
|
+
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
vec3 clearcoatDirection( vec3 wo, SurfaceRec surf ) {
|
|
232
|
+
|
|
233
|
+
// sample ggx vndf distribution which gives a new normal
|
|
234
|
+
float filteredClearcoatRoughness = surf.filteredClearcoatRoughness;
|
|
235
|
+
vec3 halfVector = ggxDirection(
|
|
236
|
+
wo,
|
|
237
|
+
filteredClearcoatRoughness,
|
|
238
|
+
filteredClearcoatRoughness,
|
|
239
|
+
rand(),
|
|
240
|
+
rand()
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// apply to new ray by reflecting off the new normal
|
|
244
|
+
return - reflect( wo, halfVector );
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
void clearcoatColor( inout vec3 color, vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
249
|
+
|
|
250
|
+
float ior = 1.5;
|
|
251
|
+
bool frontFace = surf.frontFace;
|
|
252
|
+
float filteredClearcoatRoughness = surf.filteredClearcoatRoughness;
|
|
253
|
+
|
|
254
|
+
vec3 halfVector = getHalfVector( wo, wi );
|
|
255
|
+
float iorRatio = frontFace ? 1.0 / ior : ior;
|
|
256
|
+
float G = ggxShadowMaskG2( wi, wo, filteredClearcoatRoughness );
|
|
257
|
+
float D = ggxDistribution( halfVector, filteredClearcoatRoughness );
|
|
258
|
+
|
|
259
|
+
float F = schlickFresnelFromIor( dot( wi, halfVector ), ior );
|
|
260
|
+
float cosTheta = min( wo.z, 1.0 );
|
|
261
|
+
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
262
|
+
bool cannotRefract = iorRatio * sinTheta > 1.0;
|
|
263
|
+
if ( cannotRefract ) {
|
|
264
|
+
|
|
265
|
+
F = 1.0;
|
|
266
|
+
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
float fClearcoat = F * D * G / ( 4.0 * abs( wi.z * wo.z ) );
|
|
270
|
+
|
|
271
|
+
color = color * ( 1.0 - surf.clearcoat * F ) + fClearcoat * surf.clearcoat * wi.z;
|
|
272
|
+
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
void getLobeWeights( vec3 wo, vec3 clearcoatWo, SurfaceRec surf, out float diffuseWeight, out float specularWeight, out float transmissionWeight, out float clearcoatWeight ) {
|
|
276
|
+
|
|
277
|
+
float ior = surf.ior;
|
|
278
|
+
float metalness = surf.metalness;
|
|
279
|
+
float transmission = surf.transmission;
|
|
280
|
+
bool frontFace = surf.frontFace;
|
|
281
|
+
|
|
282
|
+
float ratio = frontFace ? 1.0 / ior : ior;
|
|
283
|
+
float cosTheta = min( wo.z, 1.0 );
|
|
284
|
+
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
285
|
+
float reflectance = schlickFresnelFromIor( cosTheta, ratio );
|
|
286
|
+
bool cannotRefract = ratio * sinTheta > 1.0;
|
|
287
|
+
if ( cannotRefract ) {
|
|
288
|
+
|
|
289
|
+
reflectance = 1.0;
|
|
290
|
+
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
float transSpecularProb = mix( reflectance, 1.0, metalness );
|
|
294
|
+
float diffSpecularProb = 0.5 + 0.5 * metalness;
|
|
295
|
+
|
|
296
|
+
clearcoatWeight = surf.clearcoat * schlickFresnel( clearcoatWo.z, 0.04 );
|
|
297
|
+
diffuseWeight = ( 1.0 - transmission ) * ( 1.0 - diffSpecularProb ) * ( 1.0 - clearcoatWeight );
|
|
298
|
+
specularWeight = transmission * transSpecularProb + ( 1.0 - transmission ) * diffSpecularProb * ( 1.0 - clearcoatWeight );
|
|
299
|
+
transmissionWeight = transmission * ( 1.0 - transSpecularProb ) * ( 1.0 - clearcoatWeight );
|
|
300
|
+
|
|
301
|
+
float totalWeight = diffuseWeight + specularWeight + transmissionWeight + clearcoatWeight;
|
|
302
|
+
float invTotalWeight = 1.0 / totalWeight;
|
|
303
|
+
|
|
304
|
+
diffuseWeight *= invTotalWeight;
|
|
305
|
+
specularWeight *= invTotalWeight;
|
|
306
|
+
transmissionWeight *= invTotalWeight;
|
|
307
|
+
clearcoatWeight *= invTotalWeight;
|
|
308
|
+
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
float bsdfPdf( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf, out float specularPdf, float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight ) {
|
|
218
312
|
|
|
219
313
|
float ior = surf.ior;
|
|
220
314
|
float metalness = surf.metalness;
|
|
@@ -235,46 +329,82 @@ float bsdfPdf( vec3 wo, vec3 wi, SurfaceRec surf, out float specularPdf ) {
|
|
|
235
329
|
float spdf = 0.0;
|
|
236
330
|
float dpdf = 0.0;
|
|
237
331
|
float tpdf = 0.0;
|
|
332
|
+
float cpdf = 0.0;
|
|
238
333
|
|
|
239
334
|
if ( wi.z < 0.0 ) {
|
|
240
335
|
|
|
241
|
-
|
|
336
|
+
if( transmissionWeight > 0.0 ) {
|
|
337
|
+
|
|
338
|
+
tpdf = transmissionPDF( wo, wi, surf );
|
|
339
|
+
|
|
340
|
+
}
|
|
242
341
|
|
|
243
342
|
} else {
|
|
244
343
|
|
|
245
|
-
|
|
246
|
-
|
|
344
|
+
if( diffuseWeight > 0.0 ) {
|
|
345
|
+
|
|
346
|
+
dpdf = diffusePDF( wo, wi, surf );
|
|
347
|
+
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if( specularWeight > 0.0 ) {
|
|
351
|
+
|
|
352
|
+
spdf = specularPDF( wo, wi, surf );
|
|
353
|
+
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if( clearcoatWi.z >= 0.0 && clearcoatWeight > 0.0 ) {
|
|
359
|
+
|
|
360
|
+
cpdf = clearcoatPDF( clearcoatWo, clearcoatWi, surf );
|
|
247
361
|
|
|
248
362
|
}
|
|
249
363
|
|
|
250
|
-
float transSpecularProb = mix( reflectance, 1.0, metalness );
|
|
251
|
-
float diffSpecularProb = 0.5 + 0.5 * metalness;
|
|
252
364
|
float pdf =
|
|
253
|
-
|
|
254
|
-
+
|
|
255
|
-
+
|
|
256
|
-
+
|
|
365
|
+
dpdf * diffuseWeight
|
|
366
|
+
+ spdf * specularWeight
|
|
367
|
+
+ tpdf * transmissionWeight
|
|
368
|
+
+ cpdf * clearcoatWeight;
|
|
257
369
|
|
|
258
370
|
// retrieve specular rays for the shadows flag
|
|
259
|
-
specularPdf = spdf *
|
|
371
|
+
specularPdf = spdf * specularWeight + cpdf * clearcoatWeight;
|
|
260
372
|
|
|
261
373
|
return pdf;
|
|
262
374
|
|
|
263
375
|
}
|
|
264
376
|
|
|
265
|
-
vec3 bsdfColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
377
|
+
vec3 bsdfColor( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf, float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight ) {
|
|
266
378
|
|
|
267
379
|
vec3 color = vec3( 0.0 );
|
|
268
380
|
if ( wi.z < 0.0 ) {
|
|
269
381
|
|
|
270
|
-
|
|
382
|
+
if( transmissionWeight > 0.0 ) {
|
|
383
|
+
|
|
384
|
+
color = transmissionColor( wo, wi, surf );
|
|
385
|
+
|
|
386
|
+
}
|
|
271
387
|
|
|
272
388
|
} else {
|
|
273
389
|
|
|
274
|
-
|
|
275
|
-
|
|
390
|
+
if( diffuseWeight > 0.0 ) {
|
|
391
|
+
|
|
392
|
+
color = diffuseColor( wo, wi, surf );
|
|
393
|
+
color *= 1.0 - surf.transmission;
|
|
394
|
+
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if( specularWeight > 0.0 ) {
|
|
276
398
|
|
|
277
|
-
|
|
399
|
+
color += specularColor( wo, wi, surf );
|
|
400
|
+
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if( clearcoatWi.z >= 0.0 && clearcoatWeight > 0.0 ) {
|
|
406
|
+
|
|
407
|
+
clearcoatColor( color, clearcoatWo, clearcoatWi, surf );
|
|
278
408
|
|
|
279
409
|
}
|
|
280
410
|
|
|
@@ -282,63 +412,89 @@ vec3 bsdfColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
282
412
|
|
|
283
413
|
}
|
|
284
414
|
|
|
285
|
-
float bsdfResult( vec3 wo, vec3 wi, SurfaceRec surf, out vec3 color ) {
|
|
415
|
+
float bsdfResult( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf, out vec3 color ) {
|
|
416
|
+
|
|
417
|
+
float diffuseWeight;
|
|
418
|
+
float specularWeight;
|
|
419
|
+
float transmissionWeight;
|
|
420
|
+
float clearcoatWeight;
|
|
421
|
+
getLobeWeights( wo, clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
286
422
|
|
|
287
423
|
float specularPdf;
|
|
288
|
-
color = bsdfColor( wo, wi, surf );
|
|
289
|
-
return bsdfPdf( wo, wi, surf, specularPdf );
|
|
424
|
+
color = bsdfColor( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
425
|
+
return bsdfPdf( wo, clearcoatWo, wi, clearcoatWi, surf, specularPdf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
290
426
|
|
|
291
427
|
}
|
|
292
428
|
|
|
293
|
-
SampleRec bsdfSample( vec3 wo, SurfaceRec surf ) {
|
|
429
|
+
SampleRec bsdfSample( vec3 wo, vec3 clearcoatWo, mat3 normalBasis, mat3 invBasis, mat3 clearcoatNormalBasis, mat3 clearcoatInvBasis, SurfaceRec surf ) {
|
|
294
430
|
|
|
295
|
-
float
|
|
296
|
-
float
|
|
297
|
-
float
|
|
298
|
-
|
|
431
|
+
float diffuseWeight;
|
|
432
|
+
float specularWeight;
|
|
433
|
+
float transmissionWeight;
|
|
434
|
+
float clearcoatWeight;
|
|
435
|
+
getLobeWeights( wo, clearcoatWo, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
299
436
|
|
|
300
|
-
float
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if ( cannotRefract ) {
|
|
437
|
+
float pdf[4];
|
|
438
|
+
pdf[0] = diffuseWeight;
|
|
439
|
+
pdf[1] = specularWeight;
|
|
440
|
+
pdf[2] = transmissionWeight;
|
|
441
|
+
pdf[3] = clearcoatWeight;
|
|
306
442
|
|
|
307
|
-
|
|
443
|
+
float cdf[4];
|
|
444
|
+
cdf[0] = pdf[0];
|
|
445
|
+
cdf[1] = pdf[1] + cdf[0];
|
|
446
|
+
cdf[2] = pdf[2] + cdf[1];
|
|
447
|
+
cdf[3] = pdf[3] + cdf[2];
|
|
308
448
|
|
|
309
|
-
|
|
449
|
+
if( cdf[3] != 0.0 ) {
|
|
310
450
|
|
|
311
|
-
|
|
312
|
-
|
|
451
|
+
float invMaxCdf = 1.0 / cdf[3];
|
|
452
|
+
cdf[0] *= invMaxCdf;
|
|
453
|
+
cdf[1] *= invMaxCdf;
|
|
454
|
+
cdf[2] *= invMaxCdf;
|
|
455
|
+
cdf[3] *= invMaxCdf;
|
|
456
|
+
|
|
457
|
+
} else {
|
|
313
458
|
|
|
314
|
-
|
|
315
|
-
|
|
459
|
+
cdf[0] = 1.0;
|
|
460
|
+
cdf[1] = 0.0;
|
|
461
|
+
cdf[2] = 0.0;
|
|
462
|
+
cdf[3] = 0.0;
|
|
316
463
|
|
|
317
|
-
|
|
464
|
+
}
|
|
318
465
|
|
|
319
|
-
|
|
466
|
+
vec3 wi;
|
|
467
|
+
vec3 clearcoatWi;
|
|
320
468
|
|
|
321
|
-
|
|
469
|
+
float r = rand();
|
|
470
|
+
if ( r <= cdf[0] ) {
|
|
322
471
|
|
|
323
|
-
|
|
472
|
+
wi = diffuseDirection( wo, surf );
|
|
473
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
324
474
|
|
|
325
|
-
} else {
|
|
475
|
+
} else if ( r <= cdf[1] ) {
|
|
326
476
|
|
|
327
|
-
|
|
328
|
-
|
|
477
|
+
wi = specularDirection( wo, surf );
|
|
478
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
329
479
|
|
|
330
|
-
|
|
480
|
+
} else if ( r <= cdf[2] ) {
|
|
331
481
|
|
|
332
|
-
|
|
482
|
+
wi = transmissionDirection( wo, surf );
|
|
483
|
+
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
333
484
|
|
|
334
|
-
|
|
485
|
+
} else if ( r <= cdf[3] ) {
|
|
335
486
|
|
|
336
|
-
|
|
487
|
+
clearcoatWi = clearcoatDirection( clearcoatWo, surf );
|
|
488
|
+
wi = normalize( invBasis * normalize( clearcoatNormalBasis * clearcoatWi ) );
|
|
337
489
|
|
|
338
490
|
}
|
|
339
491
|
|
|
340
|
-
|
|
341
|
-
result.
|
|
492
|
+
SampleRec result;
|
|
493
|
+
result.pdf = bsdfPdf( wo, clearcoatWo, wi, clearcoatWi, surf, result.specularPdf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
494
|
+
result.color = bsdfColor( wo, clearcoatWo, wi, clearcoatWi, surf, diffuseWeight, specularWeight, transmissionWeight, clearcoatWeight );
|
|
495
|
+
result.direction = wi;
|
|
496
|
+
result.clearcoatDirection = clearcoatWi;
|
|
497
|
+
|
|
342
498
|
return result;
|
|
343
499
|
|
|
344
500
|
}
|
|
@@ -41,6 +41,13 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
41
41
|
int normalMap;
|
|
42
42
|
vec2 normalScale;
|
|
43
43
|
|
|
44
|
+
float clearcoat;
|
|
45
|
+
int clearcoatMap;
|
|
46
|
+
int clearcoatNormalMap;
|
|
47
|
+
vec2 clearcoatNormalScale;
|
|
48
|
+
float clearcoatRoughness;
|
|
49
|
+
int clearcoatRoughnessMap;
|
|
50
|
+
|
|
44
51
|
int alphaMap;
|
|
45
52
|
|
|
46
53
|
bool castShadow;
|
|
@@ -56,6 +63,9 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
56
63
|
mat3 transmissionMapTransform;
|
|
57
64
|
mat3 emissiveMapTransform;
|
|
58
65
|
mat3 normalMapTransform;
|
|
66
|
+
mat3 clearcoatMapTransform;
|
|
67
|
+
mat3 clearcoatNormalMapTransform;
|
|
68
|
+
mat3 clearcoatRoughnessMapTransform;
|
|
59
69
|
|
|
60
70
|
};
|
|
61
71
|
|
|
@@ -76,7 +86,7 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
76
86
|
|
|
77
87
|
Material readMaterialInfo( sampler2D tex, uint index ) {
|
|
78
88
|
|
|
79
|
-
uint i = index *
|
|
89
|
+
uint i = index * 26u;
|
|
80
90
|
|
|
81
91
|
vec4 s0 = texelFetch1D( tex, i + 0u );
|
|
82
92
|
vec4 s1 = texelFetch1D( tex, i + 1u );
|
|
@@ -85,6 +95,7 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
85
95
|
vec4 s4 = texelFetch1D( tex, i + 4u );
|
|
86
96
|
vec4 s5 = texelFetch1D( tex, i + 5u );
|
|
87
97
|
vec4 s6 = texelFetch1D( tex, i + 6u );
|
|
98
|
+
vec4 s7 = texelFetch1D( tex, i + 7u );
|
|
88
99
|
|
|
89
100
|
Material m;
|
|
90
101
|
m.color = s0.rgb;
|
|
@@ -106,16 +117,23 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
106
117
|
m.normalMap = int( round( s4.r ) );
|
|
107
118
|
m.normalScale = s4.gb;
|
|
108
119
|
|
|
109
|
-
m.
|
|
120
|
+
m.clearcoat = s4.a;
|
|
121
|
+
m.clearcoatMap = int( round( s5.r ) );
|
|
122
|
+
m.clearcoatRoughness = s5.g;
|
|
123
|
+
m.clearcoatRoughnessMap = int( round( s5.b ) );
|
|
124
|
+
m.clearcoatNormalMap = int( round( s5.a ) );
|
|
125
|
+
m.clearcoatNormalScale = s6.rg;
|
|
126
|
+
|
|
127
|
+
m.alphaMap = int( round( s6.b ) );
|
|
110
128
|
|
|
111
|
-
m.opacity =
|
|
112
|
-
m.alphaTest =
|
|
113
|
-
m.side =
|
|
114
|
-
m.matte = bool(
|
|
129
|
+
m.opacity = s6.a;
|
|
130
|
+
m.alphaTest = s7.r;
|
|
131
|
+
m.side = s7.g;
|
|
132
|
+
m.matte = bool( s7.b );
|
|
115
133
|
|
|
116
|
-
m.castShadow = ! bool(
|
|
134
|
+
m.castShadow = ! bool( s7.a );
|
|
117
135
|
|
|
118
|
-
uint firstTextureTransformIdx = i +
|
|
136
|
+
uint firstTextureTransformIdx = i + 8u;
|
|
119
137
|
|
|
120
138
|
m.mapTransform = m.map == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx);
|
|
121
139
|
m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );
|
|
@@ -123,9 +141,51 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
123
141
|
m.transmissionMapTransform = m.transmissionMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 6u );
|
|
124
142
|
m.emissiveMapTransform = m.emissiveMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 8u );
|
|
125
143
|
m.normalMapTransform = m.normalMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 10u );
|
|
144
|
+
m.clearcoatMapTransform = m.clearcoatMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 12u );
|
|
145
|
+
m.clearcoatNormalMapTransform = m.clearcoatNormalMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 14u );
|
|
146
|
+
m.clearcoatRoughnessMapTransform = m.clearcoatRoughnessMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 16u );
|
|
126
147
|
|
|
127
148
|
return m;
|
|
128
149
|
|
|
129
150
|
}
|
|
130
151
|
|
|
131
152
|
`;
|
|
153
|
+
|
|
154
|
+
export const shaderLightStruct = /* glsl */ `
|
|
155
|
+
struct Light {
|
|
156
|
+
|
|
157
|
+
vec3 position;
|
|
158
|
+
|
|
159
|
+
vec3 color;
|
|
160
|
+
float intensity;
|
|
161
|
+
|
|
162
|
+
vec3 u;
|
|
163
|
+
vec3 v;
|
|
164
|
+
float area;
|
|
165
|
+
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
Light readLightInfo( sampler2D tex, uint index ) {
|
|
169
|
+
|
|
170
|
+
uint i = index * 4u;
|
|
171
|
+
|
|
172
|
+
vec4 s0 = texelFetch1D( tex, i + 0u );
|
|
173
|
+
vec4 s1 = texelFetch1D( tex, i + 1u );
|
|
174
|
+
vec4 s2 = texelFetch1D( tex, i + 2u );
|
|
175
|
+
vec4 s3 = texelFetch1D( tex, i + 3u );
|
|
176
|
+
|
|
177
|
+
Light l;
|
|
178
|
+
l.position = s0.rgb;
|
|
179
|
+
|
|
180
|
+
l.color = s1.rgb;
|
|
181
|
+
l.intensity = s1.a;
|
|
182
|
+
|
|
183
|
+
l.u = s2.rgb;
|
|
184
|
+
l.v = s3.rgb;
|
|
185
|
+
l.area = s3.a;
|
|
186
|
+
|
|
187
|
+
return l;
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
`;
|
|
@@ -236,6 +236,47 @@ export const shaderUtils = /* glsl */`
|
|
|
236
236
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
240
|
+
// falls in the bounds of the rectangle on that same plane.
|
|
241
|
+
// Plane intersection: https://lousodrome.net/blog/light/2020/07/03/intersection-of-a-ray-and-a-plane/
|
|
242
|
+
bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, out float dist ) {
|
|
243
|
+
|
|
244
|
+
float t = dot( center - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
245
|
+
|
|
246
|
+
if ( t > EPSILON ) {
|
|
247
|
+
|
|
248
|
+
vec3 p = rayOrigin + rayDirection * t;
|
|
249
|
+
vec3 vi = p - center;
|
|
250
|
+
|
|
251
|
+
// check if p falls inside the rectangle
|
|
252
|
+
float a1 = dot( u, vi );
|
|
253
|
+
if ( abs( a1 ) <= 0.5 ) {
|
|
254
|
+
|
|
255
|
+
float a2 = dot( v, vi );
|
|
256
|
+
if ( abs( a2 ) <= 0.5 ) {
|
|
257
|
+
|
|
258
|
+
dist = t;
|
|
259
|
+
return true;
|
|
260
|
+
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return false;
|
|
268
|
+
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// power heuristic for multiple importance sampling
|
|
272
|
+
float misHeuristic( float a, float b ) {
|
|
273
|
+
|
|
274
|
+
float aa = a * a;
|
|
275
|
+
float bb = b * b;
|
|
276
|
+
return aa / ( aa + bb );
|
|
277
|
+
|
|
278
|
+
}
|
|
279
|
+
|
|
239
280
|
// An acos with input values bound to the range [-1, 1].
|
|
240
281
|
float acosSafe( float x ) {
|
|
241
282
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, Vector3, Quaternion } from 'three';
|
|
2
|
+
|
|
3
|
+
const LIGHT_PIXELS = 4;
|
|
4
|
+
|
|
5
|
+
export class LightsTexture extends DataTexture {
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
|
|
9
|
+
super( new Float32Array( 4 ), 1, 1 );
|
|
10
|
+
|
|
11
|
+
this.format = RGBAFormat;
|
|
12
|
+
this.type = FloatType;
|
|
13
|
+
this.wrapS = ClampToEdgeWrapping;
|
|
14
|
+
this.wrapT = ClampToEdgeWrapping;
|
|
15
|
+
this.generateMipmaps = false;
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
updateFrom( lights ) {
|
|
20
|
+
|
|
21
|
+
let index = 0;
|
|
22
|
+
const pixelCount = lights.length * LIGHT_PIXELS;
|
|
23
|
+
const dimension = Math.ceil( Math.sqrt( pixelCount ) );
|
|
24
|
+
|
|
25
|
+
if ( this.image.width !== dimension ) {
|
|
26
|
+
|
|
27
|
+
this.dispose();
|
|
28
|
+
|
|
29
|
+
this.image.data = new Float32Array( dimension * dimension * 4 );
|
|
30
|
+
this.image.width = dimension;
|
|
31
|
+
this.image.height = dimension;
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const floatArray = this.image.data;
|
|
36
|
+
|
|
37
|
+
const u = new Vector3();
|
|
38
|
+
const v = new Vector3();
|
|
39
|
+
const worldQuaternion = new Quaternion();
|
|
40
|
+
|
|
41
|
+
for ( let i = 0, l = lights.length; i < l; i ++ ) {
|
|
42
|
+
|
|
43
|
+
const l = lights[ i ];
|
|
44
|
+
|
|
45
|
+
// position
|
|
46
|
+
l.getWorldPosition( v );
|
|
47
|
+
floatArray[ index ++ ] = v.x;
|
|
48
|
+
floatArray[ index ++ ] = v.y;
|
|
49
|
+
floatArray[ index ++ ] = v.z;
|
|
50
|
+
index ++;
|
|
51
|
+
|
|
52
|
+
// color
|
|
53
|
+
floatArray[ index ++ ] = l.color.r;
|
|
54
|
+
floatArray[ index ++ ] = l.color.g;
|
|
55
|
+
floatArray[ index ++ ] = l.color.b;
|
|
56
|
+
|
|
57
|
+
// intensity
|
|
58
|
+
floatArray[ index ++ ] = l.intensity;
|
|
59
|
+
|
|
60
|
+
// u vector
|
|
61
|
+
l.getWorldQuaternion( worldQuaternion );
|
|
62
|
+
u.set( l.width, 0, 0 ).applyQuaternion( worldQuaternion );
|
|
63
|
+
floatArray[ index ++ ] = u.x;
|
|
64
|
+
floatArray[ index ++ ] = u.y;
|
|
65
|
+
floatArray[ index ++ ] = u.z;
|
|
66
|
+
index ++;
|
|
67
|
+
|
|
68
|
+
// v vector
|
|
69
|
+
v.set( 0, l.height, 0 ).applyQuaternion( worldQuaternion );
|
|
70
|
+
floatArray[ index ++ ] = v.x;
|
|
71
|
+
floatArray[ index ++ ] = v.y;
|
|
72
|
+
floatArray[ index ++ ] = v.z;
|
|
73
|
+
|
|
74
|
+
// area
|
|
75
|
+
floatArray[ index ++ ] = u.cross( v ).length();
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.needsUpdate = true;
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}
|