three-gpu-pathtracer 0.0.23 → 0.0.25

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.
Files changed (83) hide show
  1. package/README.md +53 -528
  2. package/build/index.module.js +319 -66
  3. package/build/index.module.js.map +1 -1
  4. package/build/index.umd.cjs +318 -64
  5. package/build/index.umd.cjs.map +1 -1
  6. package/package.json +35 -18
  7. package/src/core/PathTracingSceneGenerator.js +21 -2
  8. package/src/core/WebGLPathTracer.js +16 -7
  9. package/src/core/utils/mergeGeometries.js +14 -1
  10. package/src/core/utils/sceneUpdateUtils.js +8 -12
  11. package/src/detectors/PrecisionMaterial.js +9 -9
  12. package/src/index.d.ts +2 -1
  13. package/src/index.js +1 -0
  14. package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +2 -1
  15. package/src/materials/pathtracing/glsl/attenuate_hit_function.glsl.js +2 -1
  16. package/src/materials/pathtracing/glsl/camera_util_functions.glsl.js +1 -1
  17. package/src/materials/pathtracing/glsl/get_surface_record_function.glsl.js +2 -1
  18. package/src/materials/surface/AmbientOcclusionMaterial.js +2 -0
  19. package/src/objects/PhysicalSpotLight.js +2 -0
  20. package/src/shader/bsdf/bsdf_functions.glsl.js +0 -1
  21. package/src/shader/bvh/inside_fog_volume_function.glsl.js +1 -1
  22. package/src/shader/structs/material_struct.glsl.js +3 -1
  23. package/src/textures/BlueNoiseTexture.js +6 -6
  24. package/src/textures/ProceduralEquirectTexture.js +8 -7
  25. package/src/textures/turquinMetal.png +0 -0
  26. package/src/uniforms/EquirectHdrInfoUniform.js +9 -4
  27. package/src/uniforms/FloatAttributeTextureArray.js +11 -11
  28. package/src/uniforms/MaterialsTexture.js +13 -10
  29. package/src/webgpu/API.md +762 -0
  30. package/src/webgpu/AtlasTexture.js +471 -0
  31. package/src/webgpu/BlurredEnvMapGenerator.js +129 -0
  32. package/src/webgpu/EquirectBackgroundInfo.js +97 -0
  33. package/src/webgpu/EquirectHdrInfoNode.js +151 -0
  34. package/src/webgpu/LightsInfoNode.js +224 -0
  35. package/src/webgpu/MegaKernelPathTracer.js +277 -0
  36. package/src/webgpu/PathTracerBackend.js +216 -0
  37. package/src/webgpu/TurquinTexture.js +169 -0
  38. package/src/webgpu/WaveFrontPathTracer.js +586 -0
  39. package/src/webgpu/WebGPUPathTracer.js +1302 -0
  40. package/src/webgpu/compute/ComputeKernel.js +92 -0
  41. package/src/webgpu/compute/CopyBufferKernel.js +40 -0
  42. package/src/webgpu/compute/PathTracerMegaKernel.js +470 -0
  43. package/src/webgpu/compute/SampleDebugKernel.js +51 -0
  44. package/src/webgpu/compute/TallySampleCountsKernel.js +111 -0
  45. package/src/webgpu/compute/ZeroOutBufferKernel.js +35 -0
  46. package/src/webgpu/compute/ZeroOutKernel.js +31 -0
  47. package/src/webgpu/compute/wavefront/LogicKernel.js +349 -0
  48. package/src/webgpu/compute/wavefront/MaterialKernel.js +371 -0
  49. package/src/webgpu/compute/wavefront/PopulatePixelIndicesKernel.js +72 -0
  50. package/src/webgpu/compute/wavefront/QueueLengthToDispatchKernel.js +38 -0
  51. package/src/webgpu/compute/wavefront/ResetSlotsKernel.js +66 -0
  52. package/src/webgpu/compute/wavefront/TraceRayKernel.js +71 -0
  53. package/src/webgpu/compute/wavefront/TraceShadowRayKernel.js +67 -0
  54. package/src/webgpu/compute/wavefront/structs.js +155 -0
  55. package/src/webgpu/constants.js +62 -0
  56. package/src/webgpu/denoise/OIDNDenoiser.js +431 -0
  57. package/src/webgpu/index.d.ts +176 -0
  58. package/src/webgpu/index.js +11 -0
  59. package/src/webgpu/materials/GltfCompliantMaterial.js +608 -0
  60. package/src/webgpu/materials/GraphMaterial.js +331 -0
  61. package/src/webgpu/materials/PathtracingMaterial.js +89 -0
  62. package/src/webgpu/materials/RenderToScreenMaterial.js +150 -0
  63. package/src/webgpu/materials/debug/AtlasDebugMaterial.js +41 -0
  64. package/src/webgpu/materials/debug/SampleDensityMaterial.js +61 -0
  65. package/src/webgpu/nodes/PathtracerBVHComputeData.js +1037 -0
  66. package/src/webgpu/nodes/debugBounds.wgsl.js +228 -0
  67. package/src/webgpu/nodes/eon.wgsl.js +262 -0
  68. package/src/webgpu/nodes/ggx.wgsl.js +190 -0
  69. package/src/webgpu/nodes/lights.wgsl.js +203 -0
  70. package/src/webgpu/nodes/material.wgsl.js +990 -0
  71. package/src/webgpu/nodes/rand/bluedither.wgsl.js +92 -0
  72. package/src/webgpu/nodes/rand/pcg.wgsl.js +81 -0
  73. package/src/webgpu/nodes/rand/sobol.wgsl.js +287 -0
  74. package/src/webgpu/nodes/random.wgsl.js +20 -0
  75. package/src/webgpu/nodes/reset.wgsl.js +21 -0
  76. package/src/webgpu/nodes/sampling.wgsl.js +193 -0
  77. package/src/webgpu/nodes/sheen.wgsl.js +148 -0
  78. package/src/webgpu/nodes/structs.wgsl.js +272 -0
  79. package/src/webgpu/nodes/utils.wgsl.js +366 -0
  80. package/src/webgpu/shims/ArrayCameraShim.js +74 -0
  81. package/src/webgpu/shims/EquirectCameraShim.js +37 -0
  82. package/src/webgpu/shims/PhysicalCameraShim.js +151 -0
  83. package/src/webgpu/upscale/FSRUpscaler.js +108 -0
@@ -0,0 +1,148 @@
1
+ import { wgslTagFn } from 'three-mesh-bvh/webgpu';
2
+ import { surfaceRecordStruct } from './structs.wgsl.js';
3
+
4
+ // TODO: LTC sheen (Zeltner et al. 2022, "Practical Multiple-Scattering Sheen Using Linearly
5
+ // Transformed Cosines") is likely a better model and is what OpenPBR / Blender Cycles use to
6
+ // support sheen BRDF importance sampling & energy conservation.
7
+
8
+ // "Charlie" velvet, Estevez & Kulla, Imageworks 2017
9
+ // http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
10
+
11
+ // See equation (2)
12
+ const velvetDFunc = wgslTagFn/* wgsl */`
13
+
14
+ fn velvetD( cosThetaH: f32, roughness: f32 ) -> f32 {
15
+
16
+ var alpha = max( roughness, 0.07 );
17
+ alpha = alpha * alpha;
18
+
19
+ let invAlpha = 1.0 / alpha;
20
+ let sqrCosThetaH = cosThetaH * cosThetaH;
21
+ let sinThetaH = max( 1.0 - sqrCosThetaH, 0.001 );
22
+
23
+ return ( 2.0 + invAlpha ) * pow( sinThetaH, 0.5 * invAlpha ) / ( 2.0 * PI );
24
+
25
+ }
26
+
27
+ `;
28
+
29
+ const velvetParamsInterpolateFunc = wgslTagFn/* wgsl */`
30
+
31
+ fn velvetParamsInterpolate( i: i32, oneMinusAlphaSquared: f32 ) -> f32 {
32
+
33
+ let p0 = array<f32, 5>( 25.3245, 3.32435, 0.16801, - 1.27393, - 4.85967 );
34
+ let p1 = array<f32, 5>( 21.5473, 3.82987, 0.19823, - 1.97760, - 4.32054 );
35
+
36
+ return mix( p1[ i ], p0[ i ], oneMinusAlphaSquared );
37
+
38
+ }
39
+
40
+ `;
41
+
42
+ const velvetLFunc = wgslTagFn/* wgsl */`
43
+
44
+ fn velvetL( x: f32, alpha: f32 ) -> f32 {
45
+
46
+ let oneMinusAlpha = 1.0 - alpha;
47
+ let oneMinusAlphaSquared = oneMinusAlpha * oneMinusAlpha;
48
+
49
+ let a = ${ velvetParamsInterpolateFunc }( 0, oneMinusAlphaSquared );
50
+ let b = ${ velvetParamsInterpolateFunc }( 1, oneMinusAlphaSquared );
51
+ let c = ${ velvetParamsInterpolateFunc }( 2, oneMinusAlphaSquared );
52
+ let d = ${ velvetParamsInterpolateFunc }( 3, oneMinusAlphaSquared );
53
+ let e = ${ velvetParamsInterpolateFunc }( 4, oneMinusAlphaSquared );
54
+
55
+ return a / ( 1.0 + b * pow( abs( x ), c ) ) + d * x + e;
56
+
57
+ }
58
+
59
+ `;
60
+
61
+ // See equation (3)
62
+ const velvetLambdaFunc = wgslTagFn/* wgsl */`
63
+
64
+ fn velvetLambda( cosTheta: f32, alpha: f32 ) -> f32 {
65
+
66
+ if ( abs( cosTheta ) < 0.5 ) {
67
+
68
+ return exp( ${ velvetLFunc }( cosTheta, alpha ) );
69
+
70
+ } else {
71
+
72
+ return exp( 2.0 * ${ velvetLFunc }( 0.5, alpha ) - ${ velvetLFunc }( 1.0 - cosTheta, alpha ) );
73
+
74
+ }
75
+
76
+ }
77
+
78
+ `;
79
+
80
+ // See Section 3, Shadowing Term
81
+ const velvetGFunc = wgslTagFn/* wgsl */`
82
+
83
+ fn velvetG( cosThetaO: f32, cosThetaI: f32, roughness: f32 ) -> f32 {
84
+
85
+ var alpha = max( roughness, 0.07 );
86
+ alpha = alpha * alpha;
87
+
88
+ return 1.0 / ( 1.0 + ${ velvetLambdaFunc }( cosThetaO, alpha ) + ${ velvetLambdaFunc }( cosThetaI, alpha ) );
89
+
90
+ }
91
+
92
+ `;
93
+
94
+ // analytic directional albedo fit, used for energy compensation when layering ( Section 5 )
95
+ const directionalAlbedoSheenFunc = wgslTagFn/* wgsl */`
96
+
97
+ fn directionalAlbedoSheen( cosThetaIn: f32, alpha: f32 ) -> f32 {
98
+
99
+ let cosTheta = saturate( cosThetaIn );
100
+ let c = 1.0 - cosTheta;
101
+ let c3 = c * c * c;
102
+
103
+ return 0.65584461 * c3 + 1.0 / ( 4.16526551 + exp( -7.97291361 * sqrt( alpha ) + 6.33516894 ) );
104
+
105
+ }
106
+
107
+ `;
108
+
109
+ // See Section 5, Layering - the factor the base lobes are attenuated by so the sheen layer
110
+ // does not add energy on top of a fully reflective base
111
+ export const sheenAlbedoScalingFunc = wgslTagFn/* wgsl */`
112
+
113
+ fn sheenAlbedoScaling( wo: vec3f, wi: vec3f, surf: ${ surfaceRecordStruct } ) -> f32 {
114
+
115
+ var alpha = max( surf.sheenRoughness, 0.07 );
116
+ alpha = alpha * alpha;
117
+
118
+ let maxSheenColor = max( max( surf.sheenColor.r, surf.sheenColor.g ), surf.sheenColor.b );
119
+
120
+ let eWo = ${ directionalAlbedoSheenFunc }( clamp( wo.z, 0.001, 1.0 ), alpha );
121
+ let eWi = ${ directionalAlbedoSheenFunc }( clamp( wi.z, 0.001, 1.0 ), alpha );
122
+
123
+ return min( 1.0 - maxSheenColor * eWo, 1.0 - maxSheenColor * eWi );
124
+
125
+ }
126
+
127
+ `;
128
+
129
+ export const sheenColorFunc = wgslTagFn/* wgsl */`
130
+
131
+ fn sheenColor( wo: vec3f, wi: vec3f, wh: vec3f, surf: ${ surfaceRecordStruct } ) -> vec3f {
132
+
133
+ let cosThetaO = clamp( wo.z, 0.001, 1.0 );
134
+ let cosThetaI = clamp( wi.z, 0.001, 1.0 );
135
+ let cosThetaH = wh.z;
136
+
137
+ let D = ${ velvetDFunc }( cosThetaH, surf.sheenRoughness );
138
+ let G = ${ velvetGFunc }( cosThetaO, cosThetaI, surf.sheenRoughness );
139
+
140
+ // See equation (1) in http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
141
+ var color = surf.sheenColor;
142
+ color *= D * G / ( 4.0 * abs( cosThetaO * cosThetaI ) );
143
+
144
+ return color;
145
+
146
+ }
147
+
148
+ `;
@@ -0,0 +1,272 @@
1
+ import { wgsl } from 'three/tsl';
2
+ import { StructTypeNode } from 'three/webgpu';
3
+
4
+ // TODO: Move to node-based constants that are embedded with wgslTagFn
5
+ export const constants = wgsl( /* wgsl */ `
6
+
7
+ const PI: f32 = 3.141592653589793;
8
+ const EPSILON: f32 = 1e-5;
9
+ const MIN_ROUGHNESS: f32 = 1e-3;
10
+ const MIN_INCIDENT_COS: f32 = 1e-3;
11
+
12
+ ` );
13
+
14
+ export const scatterRecordStruct = new StructTypeNode( {
15
+ color: 'vec3f',
16
+ isTransmissive: 'bool',
17
+ direction: 'vec3f',
18
+ pdf: 'float',
19
+ }, 'ScatterRecord' );
20
+
21
+ export const transmissionFresnelStruct = new StructTypeNode( {
22
+ reflectance: 'vec3f',
23
+ transmittance: 'vec3f',
24
+ reflectProbability: 'float',
25
+ }, 'TransmissionFresnel' );
26
+
27
+ // NOTE: all "*Map" fields are bit-packed integers of texture index & settings:
28
+ // bits 0-22: texture index
29
+ // bits 23-25: uv channel
30
+ // bits 26-27: wrapS setting
31
+ // bits 28-29: wrapT setting
32
+ // bit 30: filter setting
33
+ // bit 31: negative bit used for indicating unused texture
34
+ export const materialStruct = new StructTypeNode( {
35
+ // offset 0
36
+ color: 'vec3',
37
+ map: 'int',
38
+
39
+ // offset 4 floats
40
+ metalness: 'float',
41
+ metalnessMap: 'int',
42
+
43
+ roughness: 'float',
44
+ roughnessMap: 'int',
45
+
46
+ // offset 8 floats
47
+ ior: 'float',
48
+ transmission: 'float',
49
+ transmissionMap: 'int',
50
+
51
+ emissiveIntensity: 'float',
52
+ // offset 12 floats
53
+ emissive: 'vec3',
54
+ emissiveMap: 'int',
55
+
56
+ // offset 16 floats
57
+ normalMap: 'int',
58
+ normalScale: 'vec2',
59
+
60
+ // offset 20 floats
61
+ clearcoat: 'float',
62
+ clearcoatMap: 'int',
63
+ clearcoatNormalMap: 'int',
64
+ // offset 24 floats
65
+ clearcoatNormalScale: 'vec2',
66
+ clearcoatRoughness: 'float',
67
+ clearcoatRoughnessMap: 'int',
68
+
69
+ // offset 28 floats
70
+ iridescenceMap: 'int',
71
+ iridescenceThicknessMap: 'int',
72
+ iridescence: 'float',
73
+ iridescenceIor: 'float',
74
+ // offset 32 floats
75
+ iridescenceThicknessMinimum: 'float',
76
+ iridescenceThicknessMaximum: 'float',
77
+ diffuseRoughness: 'float',
78
+ dispersion: 'float',
79
+
80
+ // offset 36 floats
81
+ specularColor: 'vec3',
82
+ specularColorMap: 'int',
83
+
84
+ // offset 40 floats
85
+ specularIntensity: 'float',
86
+ specularIntensityMap: 'int',
87
+ thinWall: 'int', // actually a boolean
88
+
89
+ // offset 44 floats
90
+ attenuationColor: 'vec3',
91
+ attenuationDistance: 'float',
92
+
93
+ // offset 48 floats
94
+ alphaMap: 'int',
95
+
96
+ castShadow: 'int', // actually a boolean
97
+ opacity: 'float',
98
+ alphaTest: 'float',
99
+
100
+ // offset 52 floats
101
+ side: 'float',
102
+ matte: 'int', // actually a boolean
103
+
104
+ sheen: 'float',
105
+ // offset 56 floats
106
+ sheenColor: 'vec3',
107
+ sheenColorMap: 'int',
108
+ // offset 60 floats
109
+ sheenRoughness: 'float',
110
+ sheenRoughnessMap: 'int',
111
+
112
+ // All those are booleans
113
+ vertexColors: 'int',
114
+ flatShading: 'int',
115
+ // offset 64 floats
116
+ transparent: 'int',
117
+ fogVolume: 'int',
118
+ // offset 66 floats
119
+ anisotropy: 'float',
120
+ anisotropyRotation: 'float',
121
+ // offset 68 floats
122
+ anisotropyMap: 'int',
123
+
124
+ // offset 72 floats
125
+ mapTransform: 'mat3',
126
+ // offset 84 floats
127
+ metalnessMapTransform: 'mat3',
128
+ // offset 96 floats
129
+ roughnessMapTransform: 'mat3',
130
+ // offset 108 floats
131
+ transmissionMapTransform: 'mat3',
132
+ // offset 120 floats
133
+ emissiveMapTransform: 'mat3',
134
+ // offset 132 floats
135
+ normalMapTransform: 'mat3',
136
+ // offset 144 floats
137
+ clearcoatMapTransform: 'mat3',
138
+ // offset 156 floats
139
+ clearcoatNormalMapTransform: 'mat3',
140
+ // offset 168 floats
141
+ clearcoatRoughnessMapTransform: 'mat3',
142
+ // offset 180 floats
143
+ sheenColorMapTransform: 'mat3',
144
+ // offset 192 floats
145
+ sheenRoughnessMapTransform: 'mat3',
146
+ // offset 204 floats
147
+ iridescenceMapTransform: 'mat3',
148
+ // offset 216 floats
149
+ iridescenceThicknessMapTransform: 'mat3',
150
+ // offset 228 floats
151
+ specularColorMapTransform: 'mat3',
152
+ // offset 240 floats
153
+ specularIntensityMapTransform: 'mat3',
154
+ // offset 252 floats
155
+ alphaMapTransform: 'mat3',
156
+
157
+ // offset 264 floats
158
+ anisotropyMapTransform: 'mat3',
159
+ // total size = 276
160
+ }, 'Material' );
161
+
162
+ export const surfaceRecordStruct = new StructTypeNode( {
163
+ // surface type
164
+ volumeParticle: 'bool',
165
+
166
+ // geometry
167
+ faceNormal: 'vec3f',
168
+ frontFace: 'bool',
169
+ normal: 'vec3f',
170
+ normalBasis: 'mat3x3f',
171
+ normalInvBasis: 'mat3x3f',
172
+
173
+ // cached properties
174
+ eta: 'f32',
175
+ f0: 'f32',
176
+
177
+ // material
178
+ roughness: 'f32',
179
+ diffuseRoughness: 'f32',
180
+ metalness: 'f32',
181
+ anisotropy: 'f32',
182
+ color: 'vec3f',
183
+ emission: 'vec3f',
184
+ opacity: 'f32',
185
+
186
+ // transmission
187
+ ior: 'f32',
188
+ transmission: 'f32',
189
+ thinWall: 'bool',
190
+ attenuationColor: 'vec3f',
191
+ attenuationDistance: ' f32',
192
+
193
+ // clearcoat
194
+ clearcoatNormal: 'vec3f',
195
+ clearcoatBasis: 'mat3x3f',
196
+ clearcoatInvBasis: 'mat3x3f',
197
+ clearcoat: 'f32',
198
+ clearcoatRoughness: 'f32',
199
+
200
+ // sheen
201
+ sheen: 'f32',
202
+ sheenColor: 'vec3f',
203
+ sheenRoughness: 'f32',
204
+
205
+ // iridescence
206
+ iridescence: 'f32',
207
+ iridescenceIor: 'f32',
208
+ iridescenceThickness: 'f32',
209
+
210
+ // specular
211
+ specularColor: 'vec3f',
212
+ specularIntensity: 'f32',
213
+ }, 'SurfaceRecord' );
214
+
215
+ export const environmentInfoStruct = new StructTypeNode( {
216
+ rotation: 'mat3x3f',
217
+ intensity: 'float',
218
+ blur: 'float',
219
+ totalSum: 'float',
220
+ }, 'EnvironmentInfo' );
221
+
222
+ // Result of importance-sampling the environment map: a world-space direction,
223
+ // its radiance, and the pdf (in solid-angle measure) of having sampled it.
224
+ export const environmentSampleStruct = new StructTypeNode( {
225
+ color: 'vec3f',
226
+ direction: 'vec3f',
227
+ pdf: 'float',
228
+ }, 'EnvironmentSample' );
229
+
230
+ // A single scene light unpacked from the lights data texture.
231
+ export const lightStruct = new StructTypeNode( {
232
+ position: 'vec3f',
233
+ lightType: 'int',
234
+ color: 'vec3f',
235
+ intensity: 'float',
236
+ u: 'vec3f',
237
+ v: 'vec3f',
238
+ area: 'float',
239
+ radius: 'float',
240
+ decay: 'float',
241
+ distance: 'float',
242
+ coneCos: 'float',
243
+ penumbraCos: 'float',
244
+ iesProfile: 'int',
245
+ }, 'Light' );
246
+
247
+ // Result of sampling (or intersecting) a light: a world-space direction toward the light,
248
+ // the distance to it, its emitted radiance, and the pdf (solid-angle measure) of the sample.
249
+ export const lightRecordStruct = new StructTypeNode( {
250
+ dist: 'float',
251
+ direction: 'vec3f',
252
+ pdf: 'float',
253
+ emission: 'vec3f',
254
+ lightType: 'int',
255
+ }, 'LightRecord' );
256
+
257
+ export const lobeWeightsStruct = new StructTypeNode( {
258
+ diffuse: 'float',
259
+ specular: 'float',
260
+ transmission: 'float',
261
+ clearcoat: 'float',
262
+ }, 'LobeWeights' );
263
+
264
+ export const bxdfContextStruct = new StructTypeNode( {
265
+
266
+ V: 'vec3f', // view dir
267
+ L: 'vec3f', // light dir
268
+ H: 'vec3f', // half dir
269
+
270
+ VdotH: 'float',
271
+
272
+ }, 'BxDFContext' );