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,69 +1,69 @@
|
|
|
1
|
-
import { Mesh } from 'three';
|
|
2
|
-
import { SAH, MeshBVH, StaticGeometryGenerator } from 'three-mesh-bvh';
|
|
3
|
-
import { mergeMeshes } from '../utils/GeometryPreparationUtils.js';
|
|
4
|
-
|
|
5
|
-
export class PathTracingSceneGenerator {
|
|
6
|
-
|
|
7
|
-
prepScene( scene ) {
|
|
8
|
-
|
|
9
|
-
scene = Array.isArray( scene ) ? scene : [ scene ];
|
|
10
|
-
|
|
11
|
-
const meshes = [];
|
|
12
|
-
const lights = [];
|
|
13
|
-
|
|
14
|
-
for ( let i = 0, l = scene.length; i < l; i ++ ) {
|
|
15
|
-
|
|
16
|
-
scene[ i ].traverseVisible( c => {
|
|
17
|
-
|
|
18
|
-
if ( c.isSkinnedMesh || c.isMesh && c.morphTargetInfluences ) {
|
|
19
|
-
|
|
20
|
-
const generator = new StaticGeometryGenerator( c );
|
|
21
|
-
generator.attributes = [ 'position', 'color', 'normal', 'tangent', 'uv', 'uv2' ];
|
|
22
|
-
generator.applyWorldTransforms = false;
|
|
23
|
-
const mesh = new Mesh(
|
|
24
|
-
generator.generate(),
|
|
25
|
-
c.material,
|
|
26
|
-
);
|
|
27
|
-
mesh.matrixWorld.copy( c.matrixWorld );
|
|
28
|
-
mesh.matrix.copy( c.matrixWorld );
|
|
29
|
-
mesh.matrix.decompose( mesh.position, mesh.quaternion, mesh.scale );
|
|
30
|
-
meshes.push( mesh );
|
|
31
|
-
|
|
32
|
-
} else if ( c.isMesh ) {
|
|
33
|
-
|
|
34
|
-
meshes.push( c );
|
|
35
|
-
|
|
36
|
-
} else if ( c.isRectAreaLight || c.isSpotLight || c.isDirectionalLight || c.isPointLight ) {
|
|
37
|
-
|
|
38
|
-
lights.push( c );
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
} );
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return {
|
|
47
|
-
...mergeMeshes( meshes, {
|
|
48
|
-
attributes: [ 'position', 'normal', 'tangent', 'uv', 'color' ],
|
|
49
|
-
} ),
|
|
50
|
-
lights,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
generate( scene, options = {} ) {
|
|
56
|
-
|
|
57
|
-
const { materials, textures, geometry, lights } = this.prepScene( scene );
|
|
58
|
-
const bvhOptions = { strategy: SAH, ...options, maxLeafTris: 1 };
|
|
59
|
-
return {
|
|
60
|
-
scene,
|
|
61
|
-
materials,
|
|
62
|
-
textures,
|
|
63
|
-
lights,
|
|
64
|
-
bvh: new MeshBVH( geometry, bvhOptions ),
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
}
|
|
1
|
+
import { Mesh } from 'three';
|
|
2
|
+
import { SAH, MeshBVH, StaticGeometryGenerator } from 'three-mesh-bvh';
|
|
3
|
+
import { mergeMeshes } from '../utils/GeometryPreparationUtils.js';
|
|
4
|
+
|
|
5
|
+
export class PathTracingSceneGenerator {
|
|
6
|
+
|
|
7
|
+
prepScene( scene ) {
|
|
8
|
+
|
|
9
|
+
scene = Array.isArray( scene ) ? scene : [ scene ];
|
|
10
|
+
|
|
11
|
+
const meshes = [];
|
|
12
|
+
const lights = [];
|
|
13
|
+
|
|
14
|
+
for ( let i = 0, l = scene.length; i < l; i ++ ) {
|
|
15
|
+
|
|
16
|
+
scene[ i ].traverseVisible( c => {
|
|
17
|
+
|
|
18
|
+
if ( c.isSkinnedMesh || c.isMesh && c.morphTargetInfluences ) {
|
|
19
|
+
|
|
20
|
+
const generator = new StaticGeometryGenerator( c );
|
|
21
|
+
generator.attributes = [ 'position', 'color', 'normal', 'tangent', 'uv', 'uv2' ];
|
|
22
|
+
generator.applyWorldTransforms = false;
|
|
23
|
+
const mesh = new Mesh(
|
|
24
|
+
generator.generate(),
|
|
25
|
+
c.material,
|
|
26
|
+
);
|
|
27
|
+
mesh.matrixWorld.copy( c.matrixWorld );
|
|
28
|
+
mesh.matrix.copy( c.matrixWorld );
|
|
29
|
+
mesh.matrix.decompose( mesh.position, mesh.quaternion, mesh.scale );
|
|
30
|
+
meshes.push( mesh );
|
|
31
|
+
|
|
32
|
+
} else if ( c.isMesh ) {
|
|
33
|
+
|
|
34
|
+
meshes.push( c );
|
|
35
|
+
|
|
36
|
+
} else if ( c.isRectAreaLight || c.isSpotLight || c.isDirectionalLight || c.isPointLight ) {
|
|
37
|
+
|
|
38
|
+
lights.push( c );
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
} );
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
...mergeMeshes( meshes, {
|
|
48
|
+
attributes: [ 'position', 'normal', 'tangent', 'uv', 'color' ],
|
|
49
|
+
} ),
|
|
50
|
+
lights,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
generate( scene, options = {} ) {
|
|
56
|
+
|
|
57
|
+
const { materials, textures, geometry, lights } = this.prepScene( scene );
|
|
58
|
+
const bvhOptions = { strategy: SAH, ...options, maxLeafTris: 1 };
|
|
59
|
+
return {
|
|
60
|
+
scene,
|
|
61
|
+
materials,
|
|
62
|
+
textures,
|
|
63
|
+
lights,
|
|
64
|
+
bvh: new MeshBVH( geometry, bvhOptions ),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
}
|
|
@@ -1,223 +1,223 @@
|
|
|
1
|
-
import { PerspectiveCamera, Vector3, MathUtils, Vector2, Matrix4, Vector4 } from 'three';
|
|
2
|
-
import { PathTracingRenderer } from './PathTracingRenderer.js';
|
|
3
|
-
|
|
4
|
-
function* _task( cb ) {
|
|
5
|
-
|
|
6
|
-
const {
|
|
7
|
-
viewCount,
|
|
8
|
-
_camera,
|
|
9
|
-
_quiltUtility,
|
|
10
|
-
_subframe,
|
|
11
|
-
} = this;
|
|
12
|
-
|
|
13
|
-
const quiltViewInfo = {
|
|
14
|
-
subframe: _subframe,
|
|
15
|
-
projectionMatrix: _camera.projectionMatrix,
|
|
16
|
-
offsetDirection: new Vector3(),
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
while ( true ) {
|
|
20
|
-
|
|
21
|
-
for ( let i = 0; i < viewCount; i ++ ) {
|
|
22
|
-
|
|
23
|
-
// get the camera info for the current view index
|
|
24
|
-
_quiltUtility.near = this.camera.near;
|
|
25
|
-
_quiltUtility.far = this.camera.far;
|
|
26
|
-
_quiltUtility.getCameraViewInfo( i, quiltViewInfo );
|
|
27
|
-
|
|
28
|
-
// transform offset into world frame from camera frame
|
|
29
|
-
quiltViewInfo.offsetDirection.transformDirection( this.camera.matrixWorld );
|
|
30
|
-
|
|
31
|
-
// adjust the render camera with the view offset
|
|
32
|
-
this.camera.matrixWorld.decompose(
|
|
33
|
-
_camera.position,
|
|
34
|
-
_camera.quaternion,
|
|
35
|
-
_camera.scale,
|
|
36
|
-
);
|
|
37
|
-
_camera.position.addScaledVector( quiltViewInfo.offsetDirection, quiltViewInfo.offset );
|
|
38
|
-
_camera.updateMatrixWorld();
|
|
39
|
-
|
|
40
|
-
// get the inverse projection
|
|
41
|
-
_camera.projectionMatrixInverse
|
|
42
|
-
.copy( _camera.projectionMatrix )
|
|
43
|
-
.invert();
|
|
44
|
-
|
|
45
|
-
this._opacityFactor = Math.floor( this._samples + 1 ) / Math.floor( this._quiltSamples + 1 );
|
|
46
|
-
|
|
47
|
-
do {
|
|
48
|
-
|
|
49
|
-
const ogCamera = this.camera;
|
|
50
|
-
this.camera = _camera;
|
|
51
|
-
cb();
|
|
52
|
-
this.camera = ogCamera;
|
|
53
|
-
yield;
|
|
54
|
-
|
|
55
|
-
} while ( this._samples % 1 !== 0 );
|
|
56
|
-
|
|
57
|
-
this._quiltSamples += 1 / viewCount;
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
this._quiltSamples = Math.round( this._quiltSamples );
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Helper for extracting the camera projection, offset, and quilt subframe needed
|
|
68
|
-
// for rendering a quilt with the provided parameters.
|
|
69
|
-
class QuiltViewUtility {
|
|
70
|
-
|
|
71
|
-
constructor() {
|
|
72
|
-
|
|
73
|
-
this.viewCount = 48;
|
|
74
|
-
this.quiltDimensions = new Vector2( 8, 6 );
|
|
75
|
-
this.viewCone = 35 * MathUtils.DEG2RAD;
|
|
76
|
-
this.viewFoV = 14 * MathUtils.DEG2RAD;
|
|
77
|
-
this.displayDistance = 1;
|
|
78
|
-
this.displayAspect = 0.75;
|
|
79
|
-
this.near = 0.01;
|
|
80
|
-
this.far = 10;
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
getCameraViewInfo( i, target = {} ) {
|
|
85
|
-
|
|
86
|
-
const {
|
|
87
|
-
quiltDimensions,
|
|
88
|
-
viewCone,
|
|
89
|
-
displayDistance,
|
|
90
|
-
viewCount,
|
|
91
|
-
viewFoV,
|
|
92
|
-
displayAspect,
|
|
93
|
-
near,
|
|
94
|
-
far,
|
|
95
|
-
} = this;
|
|
96
|
-
|
|
97
|
-
// initialize defaults
|
|
98
|
-
target.subframe = target.subframe || new Vector4();
|
|
99
|
-
target.offsetDirection = target.offsetDirection || new Vector3();
|
|
100
|
-
target.projectionMatrix = target.projectionMatrix || new Matrix4();
|
|
101
|
-
|
|
102
|
-
// set camera offset
|
|
103
|
-
const halfWidth = Math.tan( 0.5 * viewCone ) * displayDistance;
|
|
104
|
-
const totalWidth = halfWidth * 2.0;
|
|
105
|
-
const stride = totalWidth / ( viewCount - 1 );
|
|
106
|
-
const offset = viewCount === 1 ? 0 : - halfWidth + stride * i;
|
|
107
|
-
target.offsetDirection.set( 1.0, 0, 0 );
|
|
108
|
-
target.offset = offset;
|
|
109
|
-
|
|
110
|
-
// set the projection matrix
|
|
111
|
-
const displayHalfHeight = Math.tan( viewFoV * 0.5 ) * displayDistance;
|
|
112
|
-
const displayHalfWidth = displayAspect * displayHalfHeight;
|
|
113
|
-
const nearScale = near / displayDistance;
|
|
114
|
-
|
|
115
|
-
target.projectionMatrix.makePerspective(
|
|
116
|
-
nearScale * ( - displayHalfWidth - offset ), nearScale * ( displayHalfWidth - offset ),
|
|
117
|
-
nearScale * displayHalfHeight, nearScale * - displayHalfHeight,
|
|
118
|
-
near, far,
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
// set the quilt subframe
|
|
122
|
-
const x = i % quiltDimensions.x;
|
|
123
|
-
const y = Math.floor( i / quiltDimensions.x );
|
|
124
|
-
|
|
125
|
-
const qw = 1 / quiltDimensions.x;
|
|
126
|
-
const qh = 1 / quiltDimensions.y;
|
|
127
|
-
target.subframe.set( x * qw, y * qh, qw, qh );
|
|
128
|
-
|
|
129
|
-
return target;
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
setFromDisplayView( viewerDistance, displayWidth, displayHeight ) {
|
|
134
|
-
|
|
135
|
-
this.displayAspect = displayWidth / displayHeight;
|
|
136
|
-
this.displayDistance = viewerDistance;
|
|
137
|
-
this.viewFoV = 2.0 * Math.atan( 0.5 * displayHeight / viewerDistance );
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export class QuiltPathTracingRenderer extends PathTracingRenderer {
|
|
144
|
-
|
|
145
|
-
get samples() {
|
|
146
|
-
|
|
147
|
-
return this._samples / this.viewCount;
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
constructor( ...args ) {
|
|
152
|
-
|
|
153
|
-
super( ...args );
|
|
154
|
-
|
|
155
|
-
[
|
|
156
|
-
'quiltDimensions',
|
|
157
|
-
'viewCount',
|
|
158
|
-
'viewCone',
|
|
159
|
-
'viewFoV',
|
|
160
|
-
'displayDistance',
|
|
161
|
-
'displayAspect',
|
|
162
|
-
].forEach( member => {
|
|
163
|
-
|
|
164
|
-
Object.defineProperty( this, member, {
|
|
165
|
-
|
|
166
|
-
enumerable: true,
|
|
167
|
-
|
|
168
|
-
set: v => {
|
|
169
|
-
|
|
170
|
-
this._quiltUtility[ member ] = v;
|
|
171
|
-
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
get: () => {
|
|
175
|
-
|
|
176
|
-
return this._quiltUtility[ member ];
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
} );
|
|
181
|
-
|
|
182
|
-
} );
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
this._quiltUtility = new QuiltViewUtility();
|
|
186
|
-
this._quiltSamples = 0;
|
|
187
|
-
this._camera = new PerspectiveCamera();
|
|
188
|
-
this._quiltTask = null;
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
setFromDisplayView( ...args ) {
|
|
193
|
-
|
|
194
|
-
this._quiltUtility.setFromDisplayView( ...args );
|
|
195
|
-
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
update() {
|
|
199
|
-
|
|
200
|
-
this.alpha = false;
|
|
201
|
-
if ( ! this._quiltTask ) {
|
|
202
|
-
|
|
203
|
-
this._quiltTask = _task.call( this, () => {
|
|
204
|
-
|
|
205
|
-
super.update();
|
|
206
|
-
|
|
207
|
-
} );
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
this._quiltTask.next();
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
reset() {
|
|
216
|
-
|
|
217
|
-
super.reset();
|
|
218
|
-
this._quiltTask = null;
|
|
219
|
-
this._quiltSamples = 0;
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
}
|
|
1
|
+
import { PerspectiveCamera, Vector3, MathUtils, Vector2, Matrix4, Vector4 } from 'three';
|
|
2
|
+
import { PathTracingRenderer } from './PathTracingRenderer.js';
|
|
3
|
+
|
|
4
|
+
function* _task( cb ) {
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
viewCount,
|
|
8
|
+
_camera,
|
|
9
|
+
_quiltUtility,
|
|
10
|
+
_subframe,
|
|
11
|
+
} = this;
|
|
12
|
+
|
|
13
|
+
const quiltViewInfo = {
|
|
14
|
+
subframe: _subframe,
|
|
15
|
+
projectionMatrix: _camera.projectionMatrix,
|
|
16
|
+
offsetDirection: new Vector3(),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
while ( true ) {
|
|
20
|
+
|
|
21
|
+
for ( let i = 0; i < viewCount; i ++ ) {
|
|
22
|
+
|
|
23
|
+
// get the camera info for the current view index
|
|
24
|
+
_quiltUtility.near = this.camera.near;
|
|
25
|
+
_quiltUtility.far = this.camera.far;
|
|
26
|
+
_quiltUtility.getCameraViewInfo( i, quiltViewInfo );
|
|
27
|
+
|
|
28
|
+
// transform offset into world frame from camera frame
|
|
29
|
+
quiltViewInfo.offsetDirection.transformDirection( this.camera.matrixWorld );
|
|
30
|
+
|
|
31
|
+
// adjust the render camera with the view offset
|
|
32
|
+
this.camera.matrixWorld.decompose(
|
|
33
|
+
_camera.position,
|
|
34
|
+
_camera.quaternion,
|
|
35
|
+
_camera.scale,
|
|
36
|
+
);
|
|
37
|
+
_camera.position.addScaledVector( quiltViewInfo.offsetDirection, quiltViewInfo.offset );
|
|
38
|
+
_camera.updateMatrixWorld();
|
|
39
|
+
|
|
40
|
+
// get the inverse projection
|
|
41
|
+
_camera.projectionMatrixInverse
|
|
42
|
+
.copy( _camera.projectionMatrix )
|
|
43
|
+
.invert();
|
|
44
|
+
|
|
45
|
+
this._opacityFactor = Math.floor( this._samples + 1 ) / Math.floor( this._quiltSamples + 1 );
|
|
46
|
+
|
|
47
|
+
do {
|
|
48
|
+
|
|
49
|
+
const ogCamera = this.camera;
|
|
50
|
+
this.camera = _camera;
|
|
51
|
+
cb();
|
|
52
|
+
this.camera = ogCamera;
|
|
53
|
+
yield;
|
|
54
|
+
|
|
55
|
+
} while ( this._samples % 1 !== 0 );
|
|
56
|
+
|
|
57
|
+
this._quiltSamples += 1 / viewCount;
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this._quiltSamples = Math.round( this._quiltSamples );
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Helper for extracting the camera projection, offset, and quilt subframe needed
|
|
68
|
+
// for rendering a quilt with the provided parameters.
|
|
69
|
+
class QuiltViewUtility {
|
|
70
|
+
|
|
71
|
+
constructor() {
|
|
72
|
+
|
|
73
|
+
this.viewCount = 48;
|
|
74
|
+
this.quiltDimensions = new Vector2( 8, 6 );
|
|
75
|
+
this.viewCone = 35 * MathUtils.DEG2RAD;
|
|
76
|
+
this.viewFoV = 14 * MathUtils.DEG2RAD;
|
|
77
|
+
this.displayDistance = 1;
|
|
78
|
+
this.displayAspect = 0.75;
|
|
79
|
+
this.near = 0.01;
|
|
80
|
+
this.far = 10;
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getCameraViewInfo( i, target = {} ) {
|
|
85
|
+
|
|
86
|
+
const {
|
|
87
|
+
quiltDimensions,
|
|
88
|
+
viewCone,
|
|
89
|
+
displayDistance,
|
|
90
|
+
viewCount,
|
|
91
|
+
viewFoV,
|
|
92
|
+
displayAspect,
|
|
93
|
+
near,
|
|
94
|
+
far,
|
|
95
|
+
} = this;
|
|
96
|
+
|
|
97
|
+
// initialize defaults
|
|
98
|
+
target.subframe = target.subframe || new Vector4();
|
|
99
|
+
target.offsetDirection = target.offsetDirection || new Vector3();
|
|
100
|
+
target.projectionMatrix = target.projectionMatrix || new Matrix4();
|
|
101
|
+
|
|
102
|
+
// set camera offset
|
|
103
|
+
const halfWidth = Math.tan( 0.5 * viewCone ) * displayDistance;
|
|
104
|
+
const totalWidth = halfWidth * 2.0;
|
|
105
|
+
const stride = totalWidth / ( viewCount - 1 );
|
|
106
|
+
const offset = viewCount === 1 ? 0 : - halfWidth + stride * i;
|
|
107
|
+
target.offsetDirection.set( 1.0, 0, 0 );
|
|
108
|
+
target.offset = offset;
|
|
109
|
+
|
|
110
|
+
// set the projection matrix
|
|
111
|
+
const displayHalfHeight = Math.tan( viewFoV * 0.5 ) * displayDistance;
|
|
112
|
+
const displayHalfWidth = displayAspect * displayHalfHeight;
|
|
113
|
+
const nearScale = near / displayDistance;
|
|
114
|
+
|
|
115
|
+
target.projectionMatrix.makePerspective(
|
|
116
|
+
nearScale * ( - displayHalfWidth - offset ), nearScale * ( displayHalfWidth - offset ),
|
|
117
|
+
nearScale * displayHalfHeight, nearScale * - displayHalfHeight,
|
|
118
|
+
near, far,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// set the quilt subframe
|
|
122
|
+
const x = i % quiltDimensions.x;
|
|
123
|
+
const y = Math.floor( i / quiltDimensions.x );
|
|
124
|
+
|
|
125
|
+
const qw = 1 / quiltDimensions.x;
|
|
126
|
+
const qh = 1 / quiltDimensions.y;
|
|
127
|
+
target.subframe.set( x * qw, y * qh, qw, qh );
|
|
128
|
+
|
|
129
|
+
return target;
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
setFromDisplayView( viewerDistance, displayWidth, displayHeight ) {
|
|
134
|
+
|
|
135
|
+
this.displayAspect = displayWidth / displayHeight;
|
|
136
|
+
this.displayDistance = viewerDistance;
|
|
137
|
+
this.viewFoV = 2.0 * Math.atan( 0.5 * displayHeight / viewerDistance );
|
|
138
|
+
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export class QuiltPathTracingRenderer extends PathTracingRenderer {
|
|
144
|
+
|
|
145
|
+
get samples() {
|
|
146
|
+
|
|
147
|
+
return this._samples / this.viewCount;
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
constructor( ...args ) {
|
|
152
|
+
|
|
153
|
+
super( ...args );
|
|
154
|
+
|
|
155
|
+
[
|
|
156
|
+
'quiltDimensions',
|
|
157
|
+
'viewCount',
|
|
158
|
+
'viewCone',
|
|
159
|
+
'viewFoV',
|
|
160
|
+
'displayDistance',
|
|
161
|
+
'displayAspect',
|
|
162
|
+
].forEach( member => {
|
|
163
|
+
|
|
164
|
+
Object.defineProperty( this, member, {
|
|
165
|
+
|
|
166
|
+
enumerable: true,
|
|
167
|
+
|
|
168
|
+
set: v => {
|
|
169
|
+
|
|
170
|
+
this._quiltUtility[ member ] = v;
|
|
171
|
+
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
get: () => {
|
|
175
|
+
|
|
176
|
+
return this._quiltUtility[ member ];
|
|
177
|
+
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
} );
|
|
181
|
+
|
|
182
|
+
} );
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
this._quiltUtility = new QuiltViewUtility();
|
|
186
|
+
this._quiltSamples = 0;
|
|
187
|
+
this._camera = new PerspectiveCamera();
|
|
188
|
+
this._quiltTask = null;
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
setFromDisplayView( ...args ) {
|
|
193
|
+
|
|
194
|
+
this._quiltUtility.setFromDisplayView( ...args );
|
|
195
|
+
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
update() {
|
|
199
|
+
|
|
200
|
+
this.alpha = false;
|
|
201
|
+
if ( ! this._quiltTask ) {
|
|
202
|
+
|
|
203
|
+
this._quiltTask = _task.call( this, () => {
|
|
204
|
+
|
|
205
|
+
super.update();
|
|
206
|
+
|
|
207
|
+
} );
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this._quiltTask.next();
|
|
212
|
+
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
reset() {
|
|
216
|
+
|
|
217
|
+
super.reset();
|
|
218
|
+
this._quiltTask = null;
|
|
219
|
+
this._quiltSamples = 0;
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PrecisionDetector } from './PrecisionDetector.js';
|
|
2
|
+
import { MaterialCompileDetector } from './MaterialCompileDetector.js';
|
|
3
|
+
export class CompatibilityDetector {
|
|
4
|
+
|
|
5
|
+
constructor( renderer, material ) {
|
|
6
|
+
|
|
7
|
+
this._renderer = renderer;
|
|
8
|
+
this._material = material;
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
detect() {
|
|
13
|
+
|
|
14
|
+
let detector = new PrecisionDetector( this._renderer );
|
|
15
|
+
let result = detector.detect();
|
|
16
|
+
if ( ! result.pass ) {
|
|
17
|
+
|
|
18
|
+
return result;
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
detector = new MaterialCompileDetector( this._renderer );
|
|
23
|
+
result = detector.detect( this._material );
|
|
24
|
+
if ( ! result.pass ) {
|
|
25
|
+
|
|
26
|
+
return result;
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
detail: {},
|
|
32
|
+
pass: true,
|
|
33
|
+
message: '',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Mesh, BoxGeometry, PerspectiveCamera } from 'three';
|
|
2
|
+
|
|
3
|
+
// Returns whether a material can be compiled and run on the current device or not
|
|
4
|
+
export class MaterialCompileDetector {
|
|
5
|
+
|
|
6
|
+
constructor( renderer ) {
|
|
7
|
+
|
|
8
|
+
this._renderer = renderer;
|
|
9
|
+
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
detect( material ) {
|
|
13
|
+
|
|
14
|
+
const renderer = this._renderer;
|
|
15
|
+
const mesh = new Mesh( new BoxGeometry(), material );
|
|
16
|
+
const camera = new PerspectiveCamera();
|
|
17
|
+
const ogShaderErrors = renderer.debug.checkShaderErrors;
|
|
18
|
+
renderer.debug.checkShaderErrors = true;
|
|
19
|
+
|
|
20
|
+
const programs = renderer.info.programs;
|
|
21
|
+
const progLength = programs.length;
|
|
22
|
+
renderer.compile( mesh, camera );
|
|
23
|
+
|
|
24
|
+
renderer.debug.checkShaderErrors = ogShaderErrors;
|
|
25
|
+
mesh.geometry.dispose();
|
|
26
|
+
|
|
27
|
+
if ( programs.length === progLength ) {
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
detail: null,
|
|
31
|
+
pass: true,
|
|
32
|
+
message: 'Cannot determine shader compilation status if material has already been used.',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
} else {
|
|
36
|
+
|
|
37
|
+
const program = programs[ programs.length - 1 ];
|
|
38
|
+
const pass = program.diagnostics ? program.diagnostics.runnable : true;
|
|
39
|
+
const message = pass ? '' : `Cannot render ${ material.type } on this device.`;
|
|
40
|
+
return {
|
|
41
|
+
detail: {},
|
|
42
|
+
pass,
|
|
43
|
+
message,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
}
|