three-gpu-pathtracer 0.0.14 → 0.0.16
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 +1004 -981
- package/build/index.module.js +7413 -6902
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +7446 -6933
- 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/detectors/CompatibilityDetector.js +38 -0
- package/src/detectors/MaterialCompileDetector.js +50 -0
- package/src/detectors/PrecisionDetector.js +85 -0
- package/src/detectors/PrecisionMaterial.js +160 -0
- package/src/index.js +40 -36
- package/src/materials/MaterialBase.js +56 -56
- package/src/materials/debug/GraphMaterial.js +243 -243
- package/src/materials/fullscreen/AlphaDisplayMaterial.js +50 -48
- package/src/materials/fullscreen/BlendMaterial.js +67 -67
- package/src/materials/fullscreen/DenoiseMaterial.js +142 -142
- package/src/materials/fullscreen/GradientMapMaterial.js +82 -0
- package/src/materials/pathtracing/LambertPathTracingMaterial.js +296 -296
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +118 -196
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +177 -179
- package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +84 -81
- package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +93 -0
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +323 -317
- package/src/materials/pathtracing/glsl/renderStructs.glsl.js +50 -0
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +52 -54
- package/src/materials/surface/AmbientOcclusionMaterial.js +207 -207
- package/src/materials/surface/FogVolumeMaterial.js +23 -23
- package/src/objects/EquirectCamera.js +13 -13
- package/src/objects/PhysicalCamera.js +42 -28
- package/src/objects/PhysicalSpotLight.js +25 -14
- package/src/objects/ShapedAreaLight.js +22 -12
- package/src/shader/bsdf/bsdfSampling.glsl.js +499 -490
- package/src/shader/bsdf/fog.glsl.js +22 -23
- package/src/shader/bsdf/ggx.glsl.js +102 -102
- package/src/shader/bsdf/iridescence.glsl.js +135 -135
- package/src/shader/bsdf/sheen.glsl.js +98 -98
- package/src/shader/common/arraySamplerTexelFetch.glsl.js +25 -25
- package/src/shader/common/bvhAnyHit.glsl.js +76 -76
- package/src/shader/common/fresnel.glsl.js +98 -98
- package/src/shader/common/intersectShapes.glsl.js +62 -62
- package/src/shader/common/math.glsl.js +81 -81
- package/src/shader/common/utils.glsl.js +116 -116
- package/src/shader/rand/pcg.glsl.js +57 -57
- package/src/shader/rand/sobol.glsl.js +256 -256
- package/src/shader/sampling/equirectSampling.glsl.js +62 -62
- package/src/shader/sampling/lightSampling.glsl.js +223 -223
- package/src/shader/sampling/shapeSampling.glsl.js +86 -86
- package/src/shader/structs/cameraStruct.glsl.js +13 -13
- package/src/shader/structs/equirectStruct.glsl.js +13 -14
- package/src/shader/structs/fogMaterialBvh.glsl.js +62 -62
- package/src/shader/structs/lightsStruct.glsl.js +78 -78
- package/src/shader/structs/materialStruct.glsl.js +207 -207
- 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 +269 -277
- 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 -503
- 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 -9
- package/src/workers/PathTracingSceneWorker.js +42 -42
|
@@ -1,346 +1,346 @@
|
|
|
1
|
-
import { RGBAFormat, FloatType, Color, Vector2, WebGLRenderTarget, NoBlending, NormalBlending, Vector4 } from 'three';
|
|
2
|
-
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
|
|
3
|
-
import { BlendMaterial } from '../materials/fullscreen/BlendMaterial.js';
|
|
4
|
-
import { SobolNumberMapGenerator } from '../utils/SobolNumberMapGenerator.js';
|
|
5
|
-
|
|
6
|
-
const _scissor = new Vector4();
|
|
7
|
-
const _viewport = new Vector4();
|
|
8
|
-
|
|
9
|
-
function* renderTask() {
|
|
10
|
-
|
|
11
|
-
const {
|
|
12
|
-
_renderer,
|
|
13
|
-
_fsQuad,
|
|
14
|
-
_blendQuad,
|
|
15
|
-
_primaryTarget,
|
|
16
|
-
_blendTargets,
|
|
17
|
-
_sobolTarget,
|
|
18
|
-
_subframe,
|
|
19
|
-
alpha,
|
|
20
|
-
camera,
|
|
21
|
-
material,
|
|
22
|
-
} = this;
|
|
23
|
-
const _ogScissor = new Vector4();
|
|
24
|
-
const _ogViewport = new Vector4();
|
|
25
|
-
|
|
26
|
-
const blendMaterial = _blendQuad.material;
|
|
27
|
-
let [ blendTarget1, blendTarget2 ] = _blendTargets;
|
|
28
|
-
|
|
29
|
-
while ( true ) {
|
|
30
|
-
|
|
31
|
-
if ( alpha ) {
|
|
32
|
-
|
|
33
|
-
blendMaterial.opacity = this._opacityFactor / ( this._samples + 1 );
|
|
34
|
-
material.blending = NoBlending;
|
|
35
|
-
material.opacity = 1;
|
|
36
|
-
|
|
37
|
-
} else {
|
|
38
|
-
|
|
39
|
-
material.opacity = this._opacityFactor / ( this._samples + 1 );
|
|
40
|
-
material.blending = NormalBlending;
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const [ subX, subY, subW, subH ] = _subframe;
|
|
45
|
-
|
|
46
|
-
const w = _primaryTarget.width;
|
|
47
|
-
const h = _primaryTarget.height;
|
|
48
|
-
material.resolution.set( w * subW, h * subH );
|
|
49
|
-
material.sobolTexture = _sobolTarget.texture;
|
|
50
|
-
material.seed ++;
|
|
51
|
-
|
|
52
|
-
const tilesX = this.tiles.x || 1;
|
|
53
|
-
const tilesY = this.tiles.y || 1;
|
|
54
|
-
const totalTiles = tilesX * tilesY;
|
|
55
|
-
const dprInv = ( 1 / _renderer.getPixelRatio() );
|
|
56
|
-
|
|
57
|
-
for ( let y = 0; y < tilesY; y ++ ) {
|
|
58
|
-
|
|
59
|
-
for ( let x = 0; x < tilesX; x ++ ) {
|
|
60
|
-
|
|
61
|
-
material.cameraWorldMatrix.copy( camera.matrixWorld );
|
|
62
|
-
material.invProjectionMatrix.copy( camera.projectionMatrixInverse );
|
|
63
|
-
|
|
64
|
-
// Perspective camera (default)
|
|
65
|
-
let cameraType = 0;
|
|
66
|
-
|
|
67
|
-
// An orthographic projection matrix will always have the bottom right element == 1
|
|
68
|
-
// And a perspective projection matrix will always have the bottom right element == 0
|
|
69
|
-
if ( camera.projectionMatrix.elements[ 15 ] > 0 ) {
|
|
70
|
-
|
|
71
|
-
// Orthographic
|
|
72
|
-
cameraType = 1;
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if ( camera.isEquirectCamera ) {
|
|
77
|
-
|
|
78
|
-
// Equirectangular
|
|
79
|
-
cameraType = 2;
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
material.setDefine( 'CAMERA_TYPE', cameraType );
|
|
84
|
-
|
|
85
|
-
// store og state
|
|
86
|
-
const ogRenderTarget = _renderer.getRenderTarget();
|
|
87
|
-
const ogAutoClear = _renderer.autoClear;
|
|
88
|
-
const ogScissorTest = _renderer.getScissorTest();
|
|
89
|
-
_renderer.getScissor( _ogScissor );
|
|
90
|
-
_renderer.getViewport( _ogViewport );
|
|
91
|
-
|
|
92
|
-
let tx = x;
|
|
93
|
-
let ty = y;
|
|
94
|
-
if ( ! this.stableTiles ) {
|
|
95
|
-
|
|
96
|
-
const tileIndex = ( this._currentTile ) % ( tilesX * tilesY );
|
|
97
|
-
tx = tileIndex % tilesX;
|
|
98
|
-
ty = ~ ~ ( tileIndex / tilesX );
|
|
99
|
-
|
|
100
|
-
this._currentTile = tileIndex + 1;
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// three.js renderer takes values relative to the current pixel ratio
|
|
105
|
-
_renderer.setRenderTarget( _primaryTarget );
|
|
106
|
-
_renderer.setScissorTest( true );
|
|
107
|
-
|
|
108
|
-
// set the scissor window for a subtile
|
|
109
|
-
_scissor.x = tx * w / tilesX;
|
|
110
|
-
_scissor.y = ( tilesY - ty - 1 ) * h / tilesY;
|
|
111
|
-
_scissor.z = w / tilesX;
|
|
112
|
-
_scissor.w = h / tilesY;
|
|
113
|
-
|
|
114
|
-
// adjust for the subframe
|
|
115
|
-
_scissor.x = subX * w + subW * _scissor.x;
|
|
116
|
-
_scissor.y = subY * h + subH * _scissor.y;
|
|
117
|
-
_scissor.z = subW * _scissor.z;
|
|
118
|
-
_scissor.w = subH * _scissor.w;
|
|
119
|
-
|
|
120
|
-
// round for floating point cases
|
|
121
|
-
_scissor.x = _scissor.x;
|
|
122
|
-
_scissor.y = _scissor.y;
|
|
123
|
-
_scissor.z = _scissor.z;
|
|
124
|
-
_scissor.w = _scissor.w;
|
|
125
|
-
|
|
126
|
-
// multiply inverse of DPR in because threes multiplies it in
|
|
127
|
-
_scissor.multiplyScalar( dprInv ).ceil();
|
|
128
|
-
|
|
129
|
-
_viewport.x = subX * w;
|
|
130
|
-
_viewport.y = subY * h;
|
|
131
|
-
_viewport.z = subW * w;
|
|
132
|
-
_viewport.w = subH * h;
|
|
133
|
-
_viewport.multiplyScalar( dprInv ).ceil();
|
|
134
|
-
|
|
135
|
-
_renderer.setScissor( _scissor );
|
|
136
|
-
_renderer.setViewport( _viewport );
|
|
137
|
-
|
|
138
|
-
_renderer.autoClear = false;
|
|
139
|
-
_fsQuad.render( _renderer );
|
|
140
|
-
|
|
141
|
-
// reset original renderer state
|
|
142
|
-
_renderer.setViewport( _ogViewport );
|
|
143
|
-
_renderer.setScissor( _ogScissor );
|
|
144
|
-
_renderer.setScissorTest( ogScissorTest );
|
|
145
|
-
_renderer.setRenderTarget( ogRenderTarget );
|
|
146
|
-
_renderer.autoClear = ogAutoClear;
|
|
147
|
-
|
|
148
|
-
// swap and blend alpha targets
|
|
149
|
-
if ( alpha ) {
|
|
150
|
-
|
|
151
|
-
blendMaterial.target1 = blendTarget1.texture;
|
|
152
|
-
blendMaterial.target2 = _primaryTarget.texture;
|
|
153
|
-
|
|
154
|
-
_renderer.setRenderTarget( blendTarget2 );
|
|
155
|
-
_blendQuad.render( _renderer );
|
|
156
|
-
_renderer.setRenderTarget( ogRenderTarget );
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
this._samples += ( 1 / totalTiles );
|
|
161
|
-
|
|
162
|
-
// round the samples value if we've finished the tiles
|
|
163
|
-
if ( x === tilesX - 1 && y === tilesY - 1 ) {
|
|
164
|
-
|
|
165
|
-
this._samples = Math.round( this._samples );
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
yield;
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
[ blendTarget1, blendTarget2 ] = [ blendTarget2, blendTarget1 ];
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const ogClearColor = new Color();
|
|
182
|
-
export class PathTracingRenderer {
|
|
183
|
-
|
|
184
|
-
get material() {
|
|
185
|
-
|
|
186
|
-
return this._fsQuad.material;
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
set material( v ) {
|
|
191
|
-
|
|
192
|
-
this._fsQuad.material = v;
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
get target() {
|
|
197
|
-
|
|
198
|
-
return this._alpha ? this._blendTargets[ 1 ] : this._primaryTarget;
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
set alpha( v ) {
|
|
203
|
-
|
|
204
|
-
if ( this._alpha === v ) {
|
|
205
|
-
|
|
206
|
-
return;
|
|
207
|
-
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if ( ! v ) {
|
|
211
|
-
|
|
212
|
-
this._blendTargets[ 0 ].dispose();
|
|
213
|
-
this._blendTargets[ 1 ].dispose();
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
this._alpha = v;
|
|
218
|
-
this.reset();
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
get alpha() {
|
|
223
|
-
|
|
224
|
-
return this._alpha;
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
get samples() {
|
|
229
|
-
|
|
230
|
-
return this._samples;
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
constructor( renderer ) {
|
|
235
|
-
|
|
236
|
-
this.camera = null;
|
|
237
|
-
this.tiles = new Vector2( 1, 1 );
|
|
238
|
-
|
|
239
|
-
this.stableNoise = false;
|
|
240
|
-
this.stableTiles = true;
|
|
241
|
-
|
|
242
|
-
this._samples = 0;
|
|
243
|
-
this._subframe = new Vector4( 0, 0, 1, 1 );
|
|
244
|
-
this._opacityFactor = 1.0;
|
|
245
|
-
this._renderer = renderer;
|
|
246
|
-
this._alpha = false;
|
|
247
|
-
this._fsQuad = new FullScreenQuad( null );
|
|
248
|
-
this._blendQuad = new FullScreenQuad( new BlendMaterial() );
|
|
249
|
-
this._task = null;
|
|
250
|
-
this._currentTile = 0;
|
|
251
|
-
|
|
252
|
-
this._sobolTarget = new SobolNumberMapGenerator().generate( renderer );
|
|
253
|
-
this._primaryTarget = new WebGLRenderTarget( 1, 1, {
|
|
254
|
-
format: RGBAFormat,
|
|
255
|
-
type: FloatType,
|
|
256
|
-
} );
|
|
257
|
-
this._blendTargets = [
|
|
258
|
-
new WebGLRenderTarget( 1, 1, {
|
|
259
|
-
format: RGBAFormat,
|
|
260
|
-
type: FloatType,
|
|
261
|
-
} ),
|
|
262
|
-
new WebGLRenderTarget( 1, 1, {
|
|
263
|
-
format: RGBAFormat,
|
|
264
|
-
type: FloatType,
|
|
265
|
-
} ),
|
|
266
|
-
];
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
setSize( w, h ) {
|
|
271
|
-
|
|
272
|
-
w = Math.ceil( w );
|
|
273
|
-
h = Math.ceil( h );
|
|
274
|
-
|
|
275
|
-
if ( this._primaryTarget.width === w && this._primaryTarget.height === h ) {
|
|
276
|
-
|
|
277
|
-
return;
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
this._primaryTarget.setSize( w, h );
|
|
282
|
-
this._blendTargets[ 0 ].setSize( w, h );
|
|
283
|
-
this._blendTargets[ 1 ].setSize( w, h );
|
|
284
|
-
this.reset();
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
dispose() {
|
|
289
|
-
|
|
290
|
-
this._primaryTarget.dispose();
|
|
291
|
-
this._blendTargets[ 0 ].dispose();
|
|
292
|
-
this._blendTargets[ 1 ].dispose();
|
|
293
|
-
this._sobolTarget.dispose();
|
|
294
|
-
|
|
295
|
-
this._fsQuad.dispose();
|
|
296
|
-
this._blendQuad.dispose();
|
|
297
|
-
this._task = null;
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
reset() {
|
|
302
|
-
|
|
303
|
-
const { _renderer, _primaryTarget, _blendTargets } = this;
|
|
304
|
-
const ogRenderTarget = _renderer.getRenderTarget();
|
|
305
|
-
const ogClearAlpha = _renderer.getClearAlpha();
|
|
306
|
-
_renderer.getClearColor( ogClearColor );
|
|
307
|
-
|
|
308
|
-
_renderer.setRenderTarget( _primaryTarget );
|
|
309
|
-
_renderer.setClearColor( 0, 0 );
|
|
310
|
-
_renderer.clearColor();
|
|
311
|
-
|
|
312
|
-
_renderer.setRenderTarget( _blendTargets[ 0 ] );
|
|
313
|
-
_renderer.setClearColor( 0, 0 );
|
|
314
|
-
_renderer.clearColor();
|
|
315
|
-
|
|
316
|
-
_renderer.setRenderTarget( _blendTargets[ 1 ] );
|
|
317
|
-
_renderer.setClearColor( 0, 0 );
|
|
318
|
-
_renderer.clearColor();
|
|
319
|
-
|
|
320
|
-
_renderer.setClearColor( ogClearColor, ogClearAlpha );
|
|
321
|
-
_renderer.setRenderTarget( ogRenderTarget );
|
|
322
|
-
|
|
323
|
-
this._samples = 0;
|
|
324
|
-
this._task = null;
|
|
325
|
-
|
|
326
|
-
if ( this.stableNoise ) {
|
|
327
|
-
|
|
328
|
-
this.material.seed = 0;
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
update() {
|
|
335
|
-
|
|
336
|
-
if ( ! this._task ) {
|
|
337
|
-
|
|
338
|
-
this._task = renderTask.call( this );
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
this._task.next();
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
}
|
|
1
|
+
import { RGBAFormat, FloatType, Color, Vector2, WebGLRenderTarget, NoBlending, NormalBlending, Vector4 } from 'three';
|
|
2
|
+
import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
|
|
3
|
+
import { BlendMaterial } from '../materials/fullscreen/BlendMaterial.js';
|
|
4
|
+
import { SobolNumberMapGenerator } from '../utils/SobolNumberMapGenerator.js';
|
|
5
|
+
|
|
6
|
+
const _scissor = new Vector4();
|
|
7
|
+
const _viewport = new Vector4();
|
|
8
|
+
|
|
9
|
+
function* renderTask() {
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
_renderer,
|
|
13
|
+
_fsQuad,
|
|
14
|
+
_blendQuad,
|
|
15
|
+
_primaryTarget,
|
|
16
|
+
_blendTargets,
|
|
17
|
+
_sobolTarget,
|
|
18
|
+
_subframe,
|
|
19
|
+
alpha,
|
|
20
|
+
camera,
|
|
21
|
+
material,
|
|
22
|
+
} = this;
|
|
23
|
+
const _ogScissor = new Vector4();
|
|
24
|
+
const _ogViewport = new Vector4();
|
|
25
|
+
|
|
26
|
+
const blendMaterial = _blendQuad.material;
|
|
27
|
+
let [ blendTarget1, blendTarget2 ] = _blendTargets;
|
|
28
|
+
|
|
29
|
+
while ( true ) {
|
|
30
|
+
|
|
31
|
+
if ( alpha ) {
|
|
32
|
+
|
|
33
|
+
blendMaterial.opacity = this._opacityFactor / ( this._samples + 1 );
|
|
34
|
+
material.blending = NoBlending;
|
|
35
|
+
material.opacity = 1;
|
|
36
|
+
|
|
37
|
+
} else {
|
|
38
|
+
|
|
39
|
+
material.opacity = this._opacityFactor / ( this._samples + 1 );
|
|
40
|
+
material.blending = NormalBlending;
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const [ subX, subY, subW, subH ] = _subframe;
|
|
45
|
+
|
|
46
|
+
const w = _primaryTarget.width;
|
|
47
|
+
const h = _primaryTarget.height;
|
|
48
|
+
material.resolution.set( w * subW, h * subH );
|
|
49
|
+
material.sobolTexture = _sobolTarget.texture;
|
|
50
|
+
material.seed ++;
|
|
51
|
+
|
|
52
|
+
const tilesX = this.tiles.x || 1;
|
|
53
|
+
const tilesY = this.tiles.y || 1;
|
|
54
|
+
const totalTiles = tilesX * tilesY;
|
|
55
|
+
const dprInv = ( 1 / _renderer.getPixelRatio() );
|
|
56
|
+
|
|
57
|
+
for ( let y = 0; y < tilesY; y ++ ) {
|
|
58
|
+
|
|
59
|
+
for ( let x = 0; x < tilesX; x ++ ) {
|
|
60
|
+
|
|
61
|
+
material.cameraWorldMatrix.copy( camera.matrixWorld );
|
|
62
|
+
material.invProjectionMatrix.copy( camera.projectionMatrixInverse );
|
|
63
|
+
|
|
64
|
+
// Perspective camera (default)
|
|
65
|
+
let cameraType = 0;
|
|
66
|
+
|
|
67
|
+
// An orthographic projection matrix will always have the bottom right element == 1
|
|
68
|
+
// And a perspective projection matrix will always have the bottom right element == 0
|
|
69
|
+
if ( camera.projectionMatrix.elements[ 15 ] > 0 ) {
|
|
70
|
+
|
|
71
|
+
// Orthographic
|
|
72
|
+
cameraType = 1;
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if ( camera.isEquirectCamera ) {
|
|
77
|
+
|
|
78
|
+
// Equirectangular
|
|
79
|
+
cameraType = 2;
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
material.setDefine( 'CAMERA_TYPE', cameraType );
|
|
84
|
+
|
|
85
|
+
// store og state
|
|
86
|
+
const ogRenderTarget = _renderer.getRenderTarget();
|
|
87
|
+
const ogAutoClear = _renderer.autoClear;
|
|
88
|
+
const ogScissorTest = _renderer.getScissorTest();
|
|
89
|
+
_renderer.getScissor( _ogScissor );
|
|
90
|
+
_renderer.getViewport( _ogViewport );
|
|
91
|
+
|
|
92
|
+
let tx = x;
|
|
93
|
+
let ty = y;
|
|
94
|
+
if ( ! this.stableTiles ) {
|
|
95
|
+
|
|
96
|
+
const tileIndex = ( this._currentTile ) % ( tilesX * tilesY );
|
|
97
|
+
tx = tileIndex % tilesX;
|
|
98
|
+
ty = ~ ~ ( tileIndex / tilesX );
|
|
99
|
+
|
|
100
|
+
this._currentTile = tileIndex + 1;
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// three.js renderer takes values relative to the current pixel ratio
|
|
105
|
+
_renderer.setRenderTarget( _primaryTarget );
|
|
106
|
+
_renderer.setScissorTest( true );
|
|
107
|
+
|
|
108
|
+
// set the scissor window for a subtile
|
|
109
|
+
_scissor.x = tx * w / tilesX;
|
|
110
|
+
_scissor.y = ( tilesY - ty - 1 ) * h / tilesY;
|
|
111
|
+
_scissor.z = w / tilesX;
|
|
112
|
+
_scissor.w = h / tilesY;
|
|
113
|
+
|
|
114
|
+
// adjust for the subframe
|
|
115
|
+
_scissor.x = subX * w + subW * _scissor.x;
|
|
116
|
+
_scissor.y = subY * h + subH * _scissor.y;
|
|
117
|
+
_scissor.z = subW * _scissor.z;
|
|
118
|
+
_scissor.w = subH * _scissor.w;
|
|
119
|
+
|
|
120
|
+
// round for floating point cases
|
|
121
|
+
_scissor.x = _scissor.x;
|
|
122
|
+
_scissor.y = _scissor.y;
|
|
123
|
+
_scissor.z = _scissor.z;
|
|
124
|
+
_scissor.w = _scissor.w;
|
|
125
|
+
|
|
126
|
+
// multiply inverse of DPR in because threes multiplies it in
|
|
127
|
+
_scissor.multiplyScalar( dprInv ).ceil();
|
|
128
|
+
|
|
129
|
+
_viewport.x = subX * w;
|
|
130
|
+
_viewport.y = subY * h;
|
|
131
|
+
_viewport.z = subW * w;
|
|
132
|
+
_viewport.w = subH * h;
|
|
133
|
+
_viewport.multiplyScalar( dprInv ).ceil();
|
|
134
|
+
|
|
135
|
+
_renderer.setScissor( _scissor );
|
|
136
|
+
_renderer.setViewport( _viewport );
|
|
137
|
+
|
|
138
|
+
_renderer.autoClear = false;
|
|
139
|
+
_fsQuad.render( _renderer );
|
|
140
|
+
|
|
141
|
+
// reset original renderer state
|
|
142
|
+
_renderer.setViewport( _ogViewport );
|
|
143
|
+
_renderer.setScissor( _ogScissor );
|
|
144
|
+
_renderer.setScissorTest( ogScissorTest );
|
|
145
|
+
_renderer.setRenderTarget( ogRenderTarget );
|
|
146
|
+
_renderer.autoClear = ogAutoClear;
|
|
147
|
+
|
|
148
|
+
// swap and blend alpha targets
|
|
149
|
+
if ( alpha ) {
|
|
150
|
+
|
|
151
|
+
blendMaterial.target1 = blendTarget1.texture;
|
|
152
|
+
blendMaterial.target2 = _primaryTarget.texture;
|
|
153
|
+
|
|
154
|
+
_renderer.setRenderTarget( blendTarget2 );
|
|
155
|
+
_blendQuad.render( _renderer );
|
|
156
|
+
_renderer.setRenderTarget( ogRenderTarget );
|
|
157
|
+
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this._samples += ( 1 / totalTiles );
|
|
161
|
+
|
|
162
|
+
// round the samples value if we've finished the tiles
|
|
163
|
+
if ( x === tilesX - 1 && y === tilesY - 1 ) {
|
|
164
|
+
|
|
165
|
+
this._samples = Math.round( this._samples );
|
|
166
|
+
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
yield;
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
[ blendTarget1, blendTarget2 ] = [ blendTarget2, blendTarget1 ];
|
|
176
|
+
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const ogClearColor = new Color();
|
|
182
|
+
export class PathTracingRenderer {
|
|
183
|
+
|
|
184
|
+
get material() {
|
|
185
|
+
|
|
186
|
+
return this._fsQuad.material;
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
set material( v ) {
|
|
191
|
+
|
|
192
|
+
this._fsQuad.material = v;
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
get target() {
|
|
197
|
+
|
|
198
|
+
return this._alpha ? this._blendTargets[ 1 ] : this._primaryTarget;
|
|
199
|
+
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
set alpha( v ) {
|
|
203
|
+
|
|
204
|
+
if ( this._alpha === v ) {
|
|
205
|
+
|
|
206
|
+
return;
|
|
207
|
+
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if ( ! v ) {
|
|
211
|
+
|
|
212
|
+
this._blendTargets[ 0 ].dispose();
|
|
213
|
+
this._blendTargets[ 1 ].dispose();
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
this._alpha = v;
|
|
218
|
+
this.reset();
|
|
219
|
+
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
get alpha() {
|
|
223
|
+
|
|
224
|
+
return this._alpha;
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
get samples() {
|
|
229
|
+
|
|
230
|
+
return this._samples;
|
|
231
|
+
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
constructor( renderer ) {
|
|
235
|
+
|
|
236
|
+
this.camera = null;
|
|
237
|
+
this.tiles = new Vector2( 1, 1 );
|
|
238
|
+
|
|
239
|
+
this.stableNoise = false;
|
|
240
|
+
this.stableTiles = true;
|
|
241
|
+
|
|
242
|
+
this._samples = 0;
|
|
243
|
+
this._subframe = new Vector4( 0, 0, 1, 1 );
|
|
244
|
+
this._opacityFactor = 1.0;
|
|
245
|
+
this._renderer = renderer;
|
|
246
|
+
this._alpha = false;
|
|
247
|
+
this._fsQuad = new FullScreenQuad( null );
|
|
248
|
+
this._blendQuad = new FullScreenQuad( new BlendMaterial() );
|
|
249
|
+
this._task = null;
|
|
250
|
+
this._currentTile = 0;
|
|
251
|
+
|
|
252
|
+
this._sobolTarget = new SobolNumberMapGenerator().generate( renderer );
|
|
253
|
+
this._primaryTarget = new WebGLRenderTarget( 1, 1, {
|
|
254
|
+
format: RGBAFormat,
|
|
255
|
+
type: FloatType,
|
|
256
|
+
} );
|
|
257
|
+
this._blendTargets = [
|
|
258
|
+
new WebGLRenderTarget( 1, 1, {
|
|
259
|
+
format: RGBAFormat,
|
|
260
|
+
type: FloatType,
|
|
261
|
+
} ),
|
|
262
|
+
new WebGLRenderTarget( 1, 1, {
|
|
263
|
+
format: RGBAFormat,
|
|
264
|
+
type: FloatType,
|
|
265
|
+
} ),
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
setSize( w, h ) {
|
|
271
|
+
|
|
272
|
+
w = Math.ceil( w );
|
|
273
|
+
h = Math.ceil( h );
|
|
274
|
+
|
|
275
|
+
if ( this._primaryTarget.width === w && this._primaryTarget.height === h ) {
|
|
276
|
+
|
|
277
|
+
return;
|
|
278
|
+
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
this._primaryTarget.setSize( w, h );
|
|
282
|
+
this._blendTargets[ 0 ].setSize( w, h );
|
|
283
|
+
this._blendTargets[ 1 ].setSize( w, h );
|
|
284
|
+
this.reset();
|
|
285
|
+
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
dispose() {
|
|
289
|
+
|
|
290
|
+
this._primaryTarget.dispose();
|
|
291
|
+
this._blendTargets[ 0 ].dispose();
|
|
292
|
+
this._blendTargets[ 1 ].dispose();
|
|
293
|
+
this._sobolTarget.dispose();
|
|
294
|
+
|
|
295
|
+
this._fsQuad.dispose();
|
|
296
|
+
this._blendQuad.dispose();
|
|
297
|
+
this._task = null;
|
|
298
|
+
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
reset() {
|
|
302
|
+
|
|
303
|
+
const { _renderer, _primaryTarget, _blendTargets } = this;
|
|
304
|
+
const ogRenderTarget = _renderer.getRenderTarget();
|
|
305
|
+
const ogClearAlpha = _renderer.getClearAlpha();
|
|
306
|
+
_renderer.getClearColor( ogClearColor );
|
|
307
|
+
|
|
308
|
+
_renderer.setRenderTarget( _primaryTarget );
|
|
309
|
+
_renderer.setClearColor( 0, 0 );
|
|
310
|
+
_renderer.clearColor();
|
|
311
|
+
|
|
312
|
+
_renderer.setRenderTarget( _blendTargets[ 0 ] );
|
|
313
|
+
_renderer.setClearColor( 0, 0 );
|
|
314
|
+
_renderer.clearColor();
|
|
315
|
+
|
|
316
|
+
_renderer.setRenderTarget( _blendTargets[ 1 ] );
|
|
317
|
+
_renderer.setClearColor( 0, 0 );
|
|
318
|
+
_renderer.clearColor();
|
|
319
|
+
|
|
320
|
+
_renderer.setClearColor( ogClearColor, ogClearAlpha );
|
|
321
|
+
_renderer.setRenderTarget( ogRenderTarget );
|
|
322
|
+
|
|
323
|
+
this._samples = 0;
|
|
324
|
+
this._task = null;
|
|
325
|
+
|
|
326
|
+
if ( this.stableNoise ) {
|
|
327
|
+
|
|
328
|
+
this.material.seed = 0;
|
|
329
|
+
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
update() {
|
|
335
|
+
|
|
336
|
+
if ( ! this._task ) {
|
|
337
|
+
|
|
338
|
+
this._task = renderTask.call( this );
|
|
339
|
+
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
this._task.next();
|
|
343
|
+
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
}
|