three-gpu-pathtracer 0.0.20 → 0.0.21
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 +111 -464
- package/build/index.module.js +5691 -5312
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +5369 -5003
- package/build/index.umd.cjs.map +1 -1
- package/package.json +12 -6
- package/src/core/PathTracingRenderer.js +59 -46
- package/src/core/PathTracingSceneGenerator.js +245 -10
- package/src/core/WebGLPathTracer.js +472 -0
- package/src/core/utils/BakedGeometry.js +35 -0
- package/src/core/utils/BufferAttributeUtils.js +64 -0
- package/src/{utils → core/utils}/GeometryPreparationUtils.js +35 -35
- package/src/core/utils/MeshDiff.js +102 -0
- package/src/core/utils/StaticGeometryGenerator.js +285 -0
- package/src/core/utils/convertToStaticGeometry.js +344 -0
- package/src/core/utils/mergeGeometries.js +218 -0
- package/src/core/utils/sceneUpdateUtils.js +96 -0
- package/src/index.d.ts +274 -0
- package/src/index.js +4 -20
- package/src/materials/MaterialBase.js +4 -0
- package/src/materials/fullscreen/ClampedInterpolationMaterial.js +112 -0
- package/src/materials/fullscreen/DenoiseMaterial.js +4 -0
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +73 -76
- package/src/materials/pathtracing/glsl/{attenuateHit.glsl.js → attenuate_hit_function.glsl.js} +1 -1
- package/src/materials/pathtracing/glsl/{cameraUtils.glsl.js → camera_util_functions.glsl.js} +1 -1
- package/src/materials/pathtracing/glsl/{directLightContribution.glsl.js → direct_light_contribution_function.glsl.js} +1 -1
- package/src/materials/pathtracing/glsl/{getSurfaceRecord.glsl.js → get_surface_record_function.glsl.js} +1 -1
- package/src/materials/pathtracing/glsl/index.js +6 -0
- package/src/materials/pathtracing/glsl/{renderStructs.glsl.js → render_structs.glsl.js} +1 -1
- package/src/materials/pathtracing/glsl/{traceScene.glsl.js → trace_scene_function.glsl.js} +1 -3
- package/src/materials/surface/AmbientOcclusionMaterial.js +8 -8
- package/src/objects/PhysicalSpotLight.js +2 -2
- package/src/shader/bsdf/{bsdfSampling.glsl.js → bsdf_functions.glsl.js} +19 -72
- package/src/shader/bsdf/{fog.glsl.js → fog_functions.glsl.js} +1 -1
- package/src/shader/bsdf/{ggx.glsl.js → ggx_functions.glsl.js} +1 -1
- package/src/shader/bsdf/index.js +5 -0
- package/src/shader/bsdf/{iridescence.glsl.js → iridescence_functions.glsl.js} +1 -1
- package/src/shader/bsdf/{sheen.glsl.js → sheen_functions.glsl.js} +1 -1
- package/src/shader/bvh/index.js +2 -0
- package/src/shader/{structs/fogMaterialBvh.glsl.js → bvh/inside_fog_volume_function.glsl.js} +1 -1
- package/src/shader/{common/bvhAnyHit.glsl.js → bvh/ray_any_hit_function.glsl.js} +1 -1
- package/src/shader/common/{fresnel.glsl.js → fresnel_functions.glsl.js} +1 -1
- package/src/shader/common/index.js +5 -0
- package/src/shader/common/{math.glsl.js → math_functions.glsl.js} +1 -1
- package/src/shader/common/{intersectShapes.glsl.js → shape_intersection_functions.glsl.js} +1 -1
- package/src/shader/common/{arraySamplerTexelFetch.glsl.js → texture_sample_functions.glsl.js} +1 -1
- package/src/shader/common/{utils.glsl.js → util_functions.glsl.js} +1 -1
- package/src/shader/rand/index.js +3 -0
- package/src/shader/rand/pcg.glsl.js +1 -1
- package/src/shader/rand/sobol.glsl.js +4 -4
- package/src/shader/rand/{stratifiedTexture.glsl.js → stratified.glsl.js} +7 -2
- package/src/shader/sampling/{equirectSampling.glsl.js → equirect_sampling_functions.glsl.js} +1 -2
- package/src/shader/sampling/index.js +3 -0
- package/src/shader/sampling/{lightSampling.glsl.js → light_sampling_functions.glsl.js} +3 -3
- package/src/shader/sampling/{shapeSampling.glsl.js → shape_sampling_functions.glsl.js} +1 -1
- package/src/shader/structs/{cameraStruct.glsl.js → camera_struct.glsl.js} +1 -1
- package/src/shader/structs/{equirectStruct.glsl.js → equirect_struct.glsl.js} +1 -1
- package/src/shader/structs/index.js +5 -0
- package/src/shader/structs/{lightsStruct.glsl.js → lights_struct.glsl.js} +1 -1
- package/src/shader/structs/{materialStruct.glsl.js → material_struct.glsl.js} +2 -2
- package/src/shader/structs/surface_record_struct.glsl.js +63 -0
- package/src/uniforms/EquirectHdrInfoUniform.js +16 -11
- package/src/uniforms/LightsInfoUniformStruct.js +21 -10
- package/src/uniforms/MaterialsTexture.js +27 -86
- package/src/uniforms/RenderTarget2DArray.js +60 -20
- package/src/utils/BlurredEnvMapGenerator.js +12 -5
- package/src/utils/SobolNumberMapGenerator.js +3 -3
- package/src/utils/bufferToHash.js +22 -0
- package/src/core/DynamicPathTracingSceneGenerator.js +0 -164
- package/src/core/MaterialReducer.js +0 -256
- package/src/materials/pathtracing/LambertPathTracingMaterial.js +0 -297
- package/src/uniforms/IESProfilesTexture.js +0 -100
- package/src/uniforms/utils.js +0 -30
- package/src/utils/IESLoader.js +0 -327
- package/src/workers/PathTracingSceneWorker.js +0 -52
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { PerspectiveCamera, Scene, Vector2, Clock, NormalBlending, NoBlending, AdditiveBlending } from 'three';
|
|
2
|
+
import { PathTracingSceneGenerator } from './PathTracingSceneGenerator.js';
|
|
3
|
+
import { PathTracingRenderer } from './PathTracingRenderer.js';
|
|
4
|
+
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
|
|
5
|
+
import { GradientEquirectTexture } from '../textures/GradientEquirectTexture.js';
|
|
6
|
+
import { getIesTextures, getLights, getTextures } from './utils/sceneUpdateUtils.js';
|
|
7
|
+
import { ClampedInterpolationMaterial } from '../materials/fullscreen/ClampedInterpolationMaterial.js';
|
|
8
|
+
|
|
9
|
+
function supportsFloatBlending( renderer ) {
|
|
10
|
+
|
|
11
|
+
return renderer.extensions.get( 'EXT_float_blend' );
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const _resolution = new Vector2();
|
|
16
|
+
export class WebGLPathTracer {
|
|
17
|
+
|
|
18
|
+
get multipleImportanceSampling() {
|
|
19
|
+
|
|
20
|
+
return Boolean( this._pathTracer.material.defines.FEATURE_MIS );
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
set multipleImportanceSampling( v ) {
|
|
25
|
+
|
|
26
|
+
this._pathTracer.material.setDefine( 'FEATURE_MIS', v ? 1 : 0 );
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get transmissiveBounces() {
|
|
31
|
+
|
|
32
|
+
return this._pathTracer.material.transmissiveBounces;
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
set transmissiveBounces( v ) {
|
|
37
|
+
|
|
38
|
+
this._pathTracer.material.transmissiveBounces = v;
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get bounces() {
|
|
43
|
+
|
|
44
|
+
return this._pathTracer.material.bounces;
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
set bounces( v ) {
|
|
49
|
+
|
|
50
|
+
this._pathTracer.material.bounces = v;
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get filterGlossyFactor() {
|
|
55
|
+
|
|
56
|
+
return this._pathTracer.material.filterGlossyFactor;
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
set filterGlossyFactor( v ) {
|
|
61
|
+
|
|
62
|
+
this._pathTracer.material.filterGlossyFactor = v;
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get samples() {
|
|
67
|
+
|
|
68
|
+
return this._pathTracer.samples;
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get target() {
|
|
73
|
+
|
|
74
|
+
return this._pathTracer.target;
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get tiles() {
|
|
79
|
+
|
|
80
|
+
return this._pathTracer.tiles;
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
constructor( renderer ) {
|
|
85
|
+
|
|
86
|
+
// members
|
|
87
|
+
this._renderer = renderer;
|
|
88
|
+
this._generator = new PathTracingSceneGenerator();
|
|
89
|
+
this._pathTracer = new PathTracingRenderer( renderer );
|
|
90
|
+
this._queueReset = false;
|
|
91
|
+
this._clock = new Clock();
|
|
92
|
+
|
|
93
|
+
this._lowResPathTracer = new PathTracingRenderer( renderer );
|
|
94
|
+
this._lowResPathTracer.tiles.set( 1, 1 );
|
|
95
|
+
this._quad = new FullScreenQuad( new ClampedInterpolationMaterial( {
|
|
96
|
+
map: null,
|
|
97
|
+
transparent: true,
|
|
98
|
+
blending: NoBlending,
|
|
99
|
+
|
|
100
|
+
premultipliedAlpha: renderer.getContextAttributes().premultipliedAlpha,
|
|
101
|
+
} ) );
|
|
102
|
+
this._materials = null;
|
|
103
|
+
|
|
104
|
+
// options
|
|
105
|
+
this.renderDelay = 100;
|
|
106
|
+
this.minSamples = 5;
|
|
107
|
+
this.fadeDuration = 500;
|
|
108
|
+
this.enablePathTracing = true;
|
|
109
|
+
this.pausePathTracing = false;
|
|
110
|
+
this.dynamicLowRes = false;
|
|
111
|
+
this.lowResScale = 0.25;
|
|
112
|
+
this.renderScale = 1;
|
|
113
|
+
this.synchronizeRenderSize = true;
|
|
114
|
+
this.rasterizeScene = true;
|
|
115
|
+
this.renderToCanvas = true;
|
|
116
|
+
this.textureSize = new Vector2( 1024, 1024 );
|
|
117
|
+
this.rasterizeSceneCallback = ( scene, camera ) => {
|
|
118
|
+
|
|
119
|
+
this._renderer.render( scene, camera );
|
|
120
|
+
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
this.renderToCanvasCallback = ( target, renderer, quad ) => {
|
|
124
|
+
|
|
125
|
+
const currentAutoClear = renderer.autoClear;
|
|
126
|
+
renderer.autoClear = false;
|
|
127
|
+
quad.render( renderer );
|
|
128
|
+
renderer.autoClear = currentAutoClear;
|
|
129
|
+
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// initialize the scene so it doesn't fail
|
|
133
|
+
this.setScene( new Scene(), new PerspectiveCamera() );
|
|
134
|
+
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
setBVHWorker( worker ) {
|
|
138
|
+
|
|
139
|
+
this._generator.setBVHWorker( worker );
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
setScene( scene, camera, options = {} ) {
|
|
144
|
+
|
|
145
|
+
scene.updateMatrixWorld( true );
|
|
146
|
+
camera.updateMatrixWorld();
|
|
147
|
+
|
|
148
|
+
const generator = this._generator;
|
|
149
|
+
generator.setObjects( scene );
|
|
150
|
+
|
|
151
|
+
if ( this._buildAsync ) {
|
|
152
|
+
|
|
153
|
+
return generator.generateAsync( options.onProgress ).then( result => {
|
|
154
|
+
|
|
155
|
+
return this._updateFromResults( scene, camera, result );
|
|
156
|
+
|
|
157
|
+
} );
|
|
158
|
+
|
|
159
|
+
} else {
|
|
160
|
+
|
|
161
|
+
const result = generator.generate();
|
|
162
|
+
return this._updateFromResults( scene, camera, result );
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
setSceneAsync( ...args ) {
|
|
169
|
+
|
|
170
|
+
this._buildAsync = true;
|
|
171
|
+
const result = this.setScene( ...args );
|
|
172
|
+
this._buildAsync = false;
|
|
173
|
+
|
|
174
|
+
return result;
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
setCamera( camera ) {
|
|
179
|
+
|
|
180
|
+
this.camera = camera;
|
|
181
|
+
this.updateCamera();
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
updateCamera() {
|
|
186
|
+
|
|
187
|
+
const camera = this.camera;
|
|
188
|
+
camera.updateMatrixWorld();
|
|
189
|
+
|
|
190
|
+
this._pathTracer.setCamera( camera );
|
|
191
|
+
this._lowResPathTracer.setCamera( camera );
|
|
192
|
+
this.reset();
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
updateMaterials() {
|
|
197
|
+
|
|
198
|
+
const material = this._pathTracer.material;
|
|
199
|
+
const renderer = this._renderer;
|
|
200
|
+
const materials = this._materials;
|
|
201
|
+
const textureSize = this.textureSize;
|
|
202
|
+
|
|
203
|
+
// reduce texture sources here - we don't want to do this in the
|
|
204
|
+
// textures array because we need to pass the textures array into the
|
|
205
|
+
// material target
|
|
206
|
+
const textures = getTextures( materials );
|
|
207
|
+
material.textures.setTextures( renderer, textures, textureSize.x, textureSize.y );
|
|
208
|
+
material.materials.updateFrom( materials, textures );
|
|
209
|
+
this.reset();
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
updateLights() {
|
|
214
|
+
|
|
215
|
+
const scene = this.scene;
|
|
216
|
+
const renderer = this._renderer;
|
|
217
|
+
const material = this._pathTracer.material;
|
|
218
|
+
|
|
219
|
+
const lights = getLights( scene );
|
|
220
|
+
const iesTextures = getIesTextures( lights );
|
|
221
|
+
material.lights.updateFrom( lights, iesTextures );
|
|
222
|
+
material.iesProfiles.setTextures( renderer, iesTextures );
|
|
223
|
+
this.reset();
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
updateEnvironment() {
|
|
228
|
+
|
|
229
|
+
const scene = this.scene;
|
|
230
|
+
const material = this._pathTracer.material;
|
|
231
|
+
|
|
232
|
+
// update scene background
|
|
233
|
+
material.backgroundBlur = scene.backgroundBlurriness;
|
|
234
|
+
material.backgroundIntensity = scene.backgroundIntensity ?? 1;
|
|
235
|
+
material.backgroundRotation.makeRotationFromEuler( scene.backgroundRotation ).invert();
|
|
236
|
+
if ( scene.background === null ) {
|
|
237
|
+
|
|
238
|
+
material.backgroundMap = null;
|
|
239
|
+
material.backgroundAlpha = 0;
|
|
240
|
+
|
|
241
|
+
} else if ( scene.background.isColor ) {
|
|
242
|
+
|
|
243
|
+
this._colorBackground = this._colorBackground || new GradientEquirectTexture( 16 );
|
|
244
|
+
|
|
245
|
+
const colorBackground = this._colorBackground;
|
|
246
|
+
if ( ! colorBackground.topColor.equals( scene.background ) ) {
|
|
247
|
+
|
|
248
|
+
// set the texture color
|
|
249
|
+
colorBackground.topColor.set( scene.background );
|
|
250
|
+
colorBackground.bottomColor.set( scene.background );
|
|
251
|
+
colorBackground.update();
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// assign to material
|
|
256
|
+
material.backgroundMap = colorBackground;
|
|
257
|
+
material.backgroundAlpha = 1;
|
|
258
|
+
|
|
259
|
+
} else {
|
|
260
|
+
|
|
261
|
+
material.backgroundMap = scene.background;
|
|
262
|
+
material.backgroundAlpha = 1;
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// update scene environment
|
|
267
|
+
material.environmentIntensity = scene.environmentIntensity ?? 1;
|
|
268
|
+
material.environmentRotation.makeRotationFromEuler( scene.environmentRotation ).invert();
|
|
269
|
+
if ( this._previousEnvironment !== scene.environment ) {
|
|
270
|
+
|
|
271
|
+
if ( scene.environment ) {
|
|
272
|
+
|
|
273
|
+
// TODO: Consider setting this to the highest supported bit depth by checking for
|
|
274
|
+
// OES_texture_float_linear or OES_texture_half_float_linear. Requires changes to
|
|
275
|
+
// the equirect uniform
|
|
276
|
+
material.envMapInfo.updateFrom( scene.environment );
|
|
277
|
+
|
|
278
|
+
} else {
|
|
279
|
+
|
|
280
|
+
material.environmentIntensity = 0;
|
|
281
|
+
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
this._previousEnvironment = scene.environment;
|
|
287
|
+
this.reset();
|
|
288
|
+
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
_updateFromResults( scene, camera, results ) {
|
|
292
|
+
|
|
293
|
+
const {
|
|
294
|
+
materials,
|
|
295
|
+
geometry,
|
|
296
|
+
bvh,
|
|
297
|
+
bvhChanged,
|
|
298
|
+
} = results;
|
|
299
|
+
|
|
300
|
+
this._materials = materials;
|
|
301
|
+
|
|
302
|
+
const pathTracer = this._pathTracer;
|
|
303
|
+
const material = pathTracer.material;
|
|
304
|
+
|
|
305
|
+
if ( bvhChanged ) {
|
|
306
|
+
|
|
307
|
+
material.bvh.updateFrom( bvh );
|
|
308
|
+
material.attributesArray.updateFrom(
|
|
309
|
+
geometry.attributes.normal,
|
|
310
|
+
geometry.attributes.tangent,
|
|
311
|
+
geometry.attributes.uv,
|
|
312
|
+
geometry.attributes.color,
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
material.materialIndexAttribute.updateFrom( geometry.attributes.materialIndex );
|
|
316
|
+
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// save previously used items
|
|
320
|
+
this._previousScene = scene;
|
|
321
|
+
this.scene = scene;
|
|
322
|
+
this.camera = camera;
|
|
323
|
+
|
|
324
|
+
this.updateCamera();
|
|
325
|
+
this.updateMaterials();
|
|
326
|
+
this.updateEnvironment();
|
|
327
|
+
this.updateLights();
|
|
328
|
+
|
|
329
|
+
return results;
|
|
330
|
+
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
renderSample() {
|
|
334
|
+
|
|
335
|
+
const lowResPathTracer = this._lowResPathTracer;
|
|
336
|
+
const pathTracer = this._pathTracer;
|
|
337
|
+
const renderer = this._renderer;
|
|
338
|
+
const clock = this._clock;
|
|
339
|
+
const quad = this._quad;
|
|
340
|
+
|
|
341
|
+
this._updateScale();
|
|
342
|
+
|
|
343
|
+
if ( this._queueReset ) {
|
|
344
|
+
|
|
345
|
+
pathTracer.reset();
|
|
346
|
+
lowResPathTracer.reset();
|
|
347
|
+
this._queueReset = false;
|
|
348
|
+
|
|
349
|
+
quad.material.opacity = 0;
|
|
350
|
+
clock.start();
|
|
351
|
+
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// render the path tracing sample after enough time has passed
|
|
355
|
+
const delta = clock.getDelta() * 1e3;
|
|
356
|
+
const elapsedTime = clock.getElapsedTime() * 1e3;
|
|
357
|
+
if ( ! this.pausePathTracing && this.enablePathTracing && this.renderDelay <= elapsedTime ) {
|
|
358
|
+
|
|
359
|
+
pathTracer.update();
|
|
360
|
+
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// when alpha is enabled we use a manual blending system rather than
|
|
364
|
+
// rendering with a blend function
|
|
365
|
+
pathTracer.alpha = pathTracer.material.backgroundAlpha !== 1 || ! supportsFloatBlending( renderer );
|
|
366
|
+
lowResPathTracer.alpha = pathTracer.alpha;
|
|
367
|
+
|
|
368
|
+
if ( this.renderToCanvas ) {
|
|
369
|
+
|
|
370
|
+
const renderer = this._renderer;
|
|
371
|
+
const minSamples = this.minSamples;
|
|
372
|
+
|
|
373
|
+
if ( elapsedTime >= this.renderDelay && this.samples >= this.minSamples ) {
|
|
374
|
+
|
|
375
|
+
if ( this.fadeDuration !== 0 ) {
|
|
376
|
+
|
|
377
|
+
quad.material.opacity = Math.min( quad.material.opacity + delta / this.fadeDuration, 1 );
|
|
378
|
+
|
|
379
|
+
} else {
|
|
380
|
+
|
|
381
|
+
quad.material.opacity = 1;
|
|
382
|
+
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// render the fallback if we haven't rendered enough samples, are paused, or are occluded
|
|
388
|
+
if ( ! this.enablePathTracing || this.samples < minSamples || quad.material.opacity < 1 ) {
|
|
389
|
+
|
|
390
|
+
if ( this.dynamicLowRes ) {
|
|
391
|
+
|
|
392
|
+
if ( lowResPathTracer.samples < 1 ) {
|
|
393
|
+
|
|
394
|
+
lowResPathTracer.material = pathTracer.material;
|
|
395
|
+
lowResPathTracer.update();
|
|
396
|
+
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const currentOpacity = quad.material.opacity;
|
|
400
|
+
quad.material.opacity = 1 - quad.material.opacity;
|
|
401
|
+
quad.material.map = lowResPathTracer.target.texture;
|
|
402
|
+
quad.render( renderer );
|
|
403
|
+
quad.material.opacity = currentOpacity;
|
|
404
|
+
|
|
405
|
+
} else if ( this.rasterizeScene ) {
|
|
406
|
+
|
|
407
|
+
this.rasterizeSceneCallback( this.scene, this.camera );
|
|
408
|
+
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
if ( this.enablePathTracing && quad.material.opacity > 0 ) {
|
|
415
|
+
|
|
416
|
+
if ( quad.material.opacity < 1 ) {
|
|
417
|
+
|
|
418
|
+
// use additive blending when the low res texture is rendered so we can fade the
|
|
419
|
+
// background out while the full res fades in
|
|
420
|
+
quad.material.blending = this.dynamicLowRes ? AdditiveBlending : NormalBlending;
|
|
421
|
+
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
quad.material.map = pathTracer.target.texture;
|
|
425
|
+
this.renderToCanvasCallback( pathTracer.target, renderer, quad );
|
|
426
|
+
quad.material.blending = NoBlending;
|
|
427
|
+
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
reset() {
|
|
435
|
+
|
|
436
|
+
this._queueReset = true;
|
|
437
|
+
this._pathTracer.samples = 0;
|
|
438
|
+
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
dispose() {
|
|
442
|
+
|
|
443
|
+
this._renderQuad.dispose();
|
|
444
|
+
this._renderQuad.material.dispose();
|
|
445
|
+
this._pathTracer.dispose();
|
|
446
|
+
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
_updateScale() {
|
|
450
|
+
|
|
451
|
+
// update the path tracer scale if it has changed
|
|
452
|
+
if ( this.synchronizeRenderSize ) {
|
|
453
|
+
|
|
454
|
+
this._renderer.getDrawingBufferSize( _resolution );
|
|
455
|
+
|
|
456
|
+
const w = Math.floor( this.renderScale * _resolution.x );
|
|
457
|
+
const h = Math.floor( this.renderScale * _resolution.y );
|
|
458
|
+
|
|
459
|
+
this._pathTracer.getSize( _resolution );
|
|
460
|
+
if ( _resolution.x !== w || _resolution.y !== h ) {
|
|
461
|
+
|
|
462
|
+
const lowResScale = this.lowResScale;
|
|
463
|
+
this._pathTracer.setSize( w, h );
|
|
464
|
+
this._lowResPathTracer.setSize( Math.floor( w * lowResScale ), Math.floor( h * lowResScale ) );
|
|
465
|
+
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BufferGeometry } from 'three';
|
|
2
|
+
import { MeshDiff } from './MeshDiff.js';
|
|
3
|
+
import { convertToStaticGeometry } from './convertToStaticGeometry.js';
|
|
4
|
+
|
|
5
|
+
export class BakedGeometry extends BufferGeometry {
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
|
|
9
|
+
super();
|
|
10
|
+
this.version = 0;
|
|
11
|
+
this.hash = null;
|
|
12
|
+
this._diff = new MeshDiff();
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
updateFrom( mesh, options ) {
|
|
17
|
+
|
|
18
|
+
const diff = this._diff;
|
|
19
|
+
if ( diff.didChange( mesh ) ) {
|
|
20
|
+
|
|
21
|
+
convertToStaticGeometry( mesh, options, this );
|
|
22
|
+
diff.updateFrom( mesh );
|
|
23
|
+
this.version ++;
|
|
24
|
+
this.hash = `${ this.uuid }_${ this.version }`;
|
|
25
|
+
return true;
|
|
26
|
+
|
|
27
|
+
} else {
|
|
28
|
+
|
|
29
|
+
return false;
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { BufferAttribute } from 'three';
|
|
2
|
+
|
|
3
|
+
// target offset is the number of elements in the target buffer stride to skip before copying the
|
|
4
|
+
// attributes contents in to.
|
|
5
|
+
export function copyAttributeContents( attr, target, targetOffset = 0 ) {
|
|
6
|
+
|
|
7
|
+
if ( attr.isInterleavedBufferAttribute ) {
|
|
8
|
+
|
|
9
|
+
const itemSize = attr.itemSize;
|
|
10
|
+
for ( let i = 0, l = attr.count; i < l; i ++ ) {
|
|
11
|
+
|
|
12
|
+
const io = i + targetOffset;
|
|
13
|
+
target.setX( io, attr.getX( i ) );
|
|
14
|
+
if ( itemSize >= 2 ) target.setY( io, attr.getY( i ) );
|
|
15
|
+
if ( itemSize >= 3 ) target.setZ( io, attr.getZ( i ) );
|
|
16
|
+
if ( itemSize >= 4 ) target.setW( io, attr.getW( i ) );
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
} else {
|
|
21
|
+
|
|
22
|
+
const array = target.array;
|
|
23
|
+
const cons = array.constructor;
|
|
24
|
+
const byteOffset = array.BYTES_PER_ELEMENT * attr.itemSize * targetOffset;
|
|
25
|
+
const temp = new cons( array.buffer, byteOffset, attr.array.length );
|
|
26
|
+
temp.set( attr.array );
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Clones the given attribute with a new compatible buffer attribute but no data
|
|
33
|
+
export function createAttributeClone( attr, countOverride = null ) {
|
|
34
|
+
|
|
35
|
+
const cons = attr.array.constructor;
|
|
36
|
+
const normalized = attr.normalized;
|
|
37
|
+
const itemSize = attr.itemSize;
|
|
38
|
+
const count = countOverride === null ? attr.count : countOverride;
|
|
39
|
+
|
|
40
|
+
return new BufferAttribute( new cons( itemSize * count ), itemSize, normalized );
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Confirms that the two provided attributes are compatible
|
|
45
|
+
export function validateAttributes( attr1, attr2 ) {
|
|
46
|
+
|
|
47
|
+
if ( ! attr1 && ! attr2 ) {
|
|
48
|
+
|
|
49
|
+
return;
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const sameCount = attr1.count === attr2.count;
|
|
54
|
+
const sameNormalized = attr1.normalized === attr2.normalized;
|
|
55
|
+
const sameType = attr1.array.constructor === attr2.array.constructor;
|
|
56
|
+
const sameItemSize = attr1.itemSize === attr2.itemSize;
|
|
57
|
+
|
|
58
|
+
if ( ! sameCount || ! sameNormalized || ! sameType || ! sameItemSize ) {
|
|
59
|
+
|
|
60
|
+
throw new Error();
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BufferAttribute } from 'three';
|
|
2
|
-
|
|
3
|
-
export function
|
|
2
|
+
|
|
3
|
+
export function updateMaterialIndexAttribute( geometry, materials, allMaterials ) {
|
|
4
4
|
|
|
5
5
|
const indexAttr = geometry.index;
|
|
6
6
|
const posAttr = geometry.attributes.position;
|
|
@@ -13,18 +13,28 @@ export function getGroupMaterialIndicesAttribute( geometry, materials, allMateri
|
|
|
13
13
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
let materialIndexAttribute = geometry.getAttribute( 'materialIndex' );
|
|
17
|
+
if ( ! materialIndexAttribute || materialIndexAttribute.count !== vertCount ) {
|
|
18
|
+
|
|
19
|
+
// use an array with the minimum precision required to store all material id references.
|
|
20
|
+
let array;
|
|
21
|
+
if ( allMaterials.length <= 255 ) {
|
|
22
|
+
|
|
23
|
+
array = new Uint8Array( vertCount );
|
|
24
|
+
|
|
25
|
+
} else {
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
array = new Uint16Array( vertCount );
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
}
|
|
23
30
|
|
|
24
|
-
|
|
31
|
+
materialIndexAttribute = new BufferAttribute( array, 1, false );
|
|
32
|
+
geometry.deleteAttribute( 'materialIndex' );
|
|
33
|
+
geometry.setAttribute( 'materialIndex', materialIndexAttribute );
|
|
25
34
|
|
|
26
35
|
}
|
|
27
36
|
|
|
37
|
+
const materialArray = materialIndexAttribute.array;
|
|
28
38
|
for ( let i = 0; i < groups.length; i ++ ) {
|
|
29
39
|
|
|
30
40
|
const group = groups[ i ];
|
|
@@ -50,13 +60,24 @@ export function getGroupMaterialIndicesAttribute( geometry, materials, allMateri
|
|
|
50
60
|
|
|
51
61
|
}
|
|
52
62
|
|
|
53
|
-
return new BufferAttribute( materialArray, 1, false );
|
|
54
|
-
|
|
55
63
|
}
|
|
56
64
|
|
|
57
|
-
export function setCommonAttributes( geometry,
|
|
65
|
+
export function setCommonAttributes( geometry, attributes ) {
|
|
66
|
+
|
|
67
|
+
if ( ! geometry.index ) {
|
|
68
|
+
|
|
69
|
+
// TODO: compute a typed array
|
|
70
|
+
const indexCount = geometry.attributes.position.count;
|
|
71
|
+
const array = new Array( indexCount );
|
|
72
|
+
for ( let i = 0; i < indexCount; i ++ ) {
|
|
73
|
+
|
|
74
|
+
array[ i ] = i;
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
geometry.setIndex( array );
|
|
58
79
|
|
|
59
|
-
|
|
80
|
+
}
|
|
60
81
|
|
|
61
82
|
if ( ! geometry.attributes.normal && ( attributes && attributes.includes( 'normal' ) ) ) {
|
|
62
83
|
|
|
@@ -80,14 +101,8 @@ export function setCommonAttributes( geometry, options ) {
|
|
|
80
101
|
|
|
81
102
|
if ( ! geometry.attributes.tangent && ( attributes && attributes.includes( 'tangent' ) ) ) {
|
|
82
103
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// computeTangents requires an index buffer
|
|
86
|
-
if ( geometry.index === null ) {
|
|
87
|
-
|
|
88
|
-
geometry = mergeVertices( geometry );
|
|
89
|
-
|
|
90
|
-
}
|
|
104
|
+
// compute tangents requires a uv and normal buffer
|
|
105
|
+
if ( geometry.attributes.uv && geometry.attributes.normal ) {
|
|
91
106
|
|
|
92
107
|
geometry.computeTangents();
|
|
93
108
|
|
|
@@ -109,19 +124,4 @@ export function setCommonAttributes( geometry, options ) {
|
|
|
109
124
|
|
|
110
125
|
}
|
|
111
126
|
|
|
112
|
-
if ( ! geometry.index ) {
|
|
113
|
-
|
|
114
|
-
// TODO: compute a typed array
|
|
115
|
-
const indexCount = geometry.attributes.position.count;
|
|
116
|
-
const array = new Array( indexCount );
|
|
117
|
-
for ( let i = 0; i < indexCount; i ++ ) {
|
|
118
|
-
|
|
119
|
-
array[ i ] = i;
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
geometry.setIndex( array );
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
127
|
}
|