three-gpu-pathtracer 0.0.3 → 0.0.4

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.
@@ -1,173 +1,251 @@
1
- import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, FrontSide, BackSide, DoubleSide } from 'three';
2
-
3
- const MATERIAL_PIXELS = 6;
4
- const MATERIAL_STRIDE = 6 * 4;
5
-
6
- export class MaterialsTexture extends DataTexture {
7
-
8
- constructor() {
9
-
10
- super( new Float32Array( 4 ), 1, 1 );
11
-
12
- this.format = RGBAFormat;
13
- this.type = FloatType;
14
- this.wrapS = ClampToEdgeWrapping;
15
- this.wrapT = ClampToEdgeWrapping;
16
- this.generateMipmaps = false;
17
-
18
- }
19
-
20
- setSide( materialIndex, side ) {
21
-
22
- const array = this.image.data;
23
- const index = materialIndex * MATERIAL_STRIDE + 5 * 4 + 2;
24
- switch ( side ) {
25
-
26
- case FrontSide:
27
- array[ index ] = 1;
28
- break;
29
- case BackSide:
30
- array[ index ] = - 1;
31
- break;
32
- case DoubleSide:
33
- array[ index ] = 0;
34
- break;
35
-
36
- }
37
-
38
- }
39
-
40
- getSide( materialIndex ) {
41
-
42
- const array = this.image.data;
43
- const index = materialIndex * MATERIAL_STRIDE + 5 * 4 + 2;
44
- switch ( array[ index ] ) {
45
-
46
- case 0:
47
- return DoubleSide;
48
- case 1:
49
- return FrontSide;
50
- case - 1:
51
- return BackSide;
52
-
53
- }
54
-
55
- return 0;
56
-
57
- }
58
-
59
- setMatte( materialIndex, matte ) {
60
-
61
- const array = this.image.data;
62
- const index = materialIndex * MATERIAL_STRIDE + 5 * 4 + 3;
63
- array[ index ] = matte ? 1 : 0;
64
-
65
- }
66
-
67
- getMatte( materialIndex ) {
68
-
69
- const array = this.image.data;
70
- const index = materialIndex * MATERIAL_STRIDE + 5 * 4 + 3;
71
- return Boolean( array[ index ] );
72
-
73
- }
74
-
75
- updateFrom( materials, textures ) {
76
-
77
- function getTexture( material, key, def = - 1 ) {
78
-
79
- return key in material ? textures.indexOf( material[ key ] ) : def;
80
-
81
- }
82
-
83
- function getField( material, key, def ) {
84
-
85
- return key in material ? material[ key ] : def;
86
-
87
- }
88
-
89
- let index = 0;
90
- const pixelCount = materials.length * MATERIAL_PIXELS;
91
- const dimension = Math.ceil( Math.sqrt( pixelCount ) );
92
-
93
- if ( this.image.width !== dimension ) {
94
-
95
- this.dispose();
96
-
97
- this.image.data = new Float32Array( dimension * dimension * 4 );
98
- this.image.width = dimension;
99
- this.image.height = dimension;
100
-
101
- }
102
-
103
- const floatArray = this.image.data;
104
- const intArray = new Int32Array( floatArray.buffer );
105
-
106
- for ( let i = 0, l = materials.length; i < l; i ++ ) {
107
-
108
- const m = materials[ i ];
109
-
110
- // color
111
- floatArray[ index ++ ] = m.color.r;
112
- floatArray[ index ++ ] = m.color.g;
113
- floatArray[ index ++ ] = m.color.b;
114
- intArray[ index ++ ] = getTexture( m, 'map' );
115
-
116
- // metalness & roughness
117
- floatArray[ index ++ ] = getField( m, 'metalness', 0.0 );
118
- intArray[ index ++ ] = textures.indexOf( m.metalnessMap );
119
- floatArray[ index ++ ] = getField( m, 'roughness', 0.0 );
120
- intArray[ index ++ ] = textures.indexOf( m.roughnessMap );
121
-
122
- // transmission & emissiveIntensity
123
- floatArray[ index ++ ] = getField( m, 'ior', 1.0 );
124
- floatArray[ index ++ ] = getField( m, 'transmission', 0.0 );
125
- intArray[ index ++ ] = getTexture( m, 'transmissionMap' );
126
- floatArray[ index ++ ] = getField( m, 'emissiveIntensity', 0.0 );
127
-
128
- // emission
129
- if ( 'emissive' in m ) {
130
-
131
- floatArray[ index ++ ] = m.emissive.r;
132
- floatArray[ index ++ ] = m.emissive.g;
133
- floatArray[ index ++ ] = m.emissive.b;
134
-
135
- } else {
136
-
137
- floatArray[ index ++ ] = 0.0;
138
- floatArray[ index ++ ] = 0.0;
139
- floatArray[ index ++ ] = 0.0;
140
-
141
- }
142
-
143
- intArray[ index ++ ] = getTexture( m, 'emissiveMap' );
144
-
145
- // normals
146
- intArray[ index ++ ] = getTexture( m, 'normalMap' );
147
- if ( 'normalScale' in m ) {
148
-
149
- floatArray[ index ++ ] = m.normalScale.x;
150
- floatArray[ index ++ ] = m.normalScale.y;
151
-
152
- } else {
153
-
154
- floatArray[ index ++ ] = 1;
155
- floatArray[ index ++ ] = 1;
156
-
157
- }
158
-
159
- index ++;
160
-
161
- // side & matte
162
- floatArray[ index ++ ] = m.opacity;
163
- floatArray[ index ++ ] = m.alphaTest;
164
- index ++; // side
165
- index ++; // matte
166
-
167
- }
168
-
169
- this.needsUpdate = true;
170
-
171
- }
172
-
173
- }
1
+ import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, FrontSide, BackSide, DoubleSide } from 'three';
2
+
3
+ const MATERIAL_PIXELS = 19;
4
+ const MATERIAL_STRIDE = MATERIAL_PIXELS * 4;
5
+
6
+ export class MaterialsTexture extends DataTexture {
7
+
8
+ constructor() {
9
+
10
+ super( new Float32Array( 4 ), 1, 1 );
11
+
12
+ this.format = RGBAFormat;
13
+ this.type = FloatType;
14
+ this.wrapS = ClampToEdgeWrapping;
15
+ this.wrapT = ClampToEdgeWrapping;
16
+ this.generateMipmaps = false;
17
+
18
+ }
19
+
20
+ setCastShadow( materialIndex, cast ) {
21
+
22
+ // invert the shadow value so we default to "true" when initializing a material
23
+ const array = this.image.data;
24
+ const index = materialIndex * MATERIAL_STRIDE + 6 * 4 + 0;
25
+ array[ index ] = ! cast ? 1 : 0;
26
+
27
+ }
28
+
29
+ getCastShadow( materialIndex ) {
30
+
31
+ const array = this.image.data;
32
+ const index = materialIndex * MATERIAL_STRIDE + 6 * 4 + 0;
33
+ return ! Boolean( array[ index ] );
34
+
35
+ }
36
+
37
+ setSide( materialIndex, side ) {
38
+
39
+ const array = this.image.data;
40
+ const index = materialIndex * MATERIAL_STRIDE + 5 * 4 + 2;
41
+ switch ( side ) {
42
+
43
+ case FrontSide:
44
+ array[ index ] = 1;
45
+ break;
46
+ case BackSide:
47
+ array[ index ] = - 1;
48
+ break;
49
+ case DoubleSide:
50
+ array[ index ] = 0;
51
+ break;
52
+
53
+ }
54
+
55
+ }
56
+
57
+ getSide( materialIndex ) {
58
+
59
+ const array = this.image.data;
60
+ const index = materialIndex * MATERIAL_STRIDE + 5 * 4 + 2;
61
+ switch ( array[ index ] ) {
62
+
63
+ case 0:
64
+ return DoubleSide;
65
+ case 1:
66
+ return FrontSide;
67
+ case - 1:
68
+ return BackSide;
69
+
70
+ }
71
+
72
+ return 0;
73
+
74
+ }
75
+
76
+ setMatte( materialIndex, matte ) {
77
+
78
+ const array = this.image.data;
79
+ const index = materialIndex * MATERIAL_STRIDE + 5 * 4 + 3;
80
+ array[ index ] = matte ? 1 : 0;
81
+
82
+ }
83
+
84
+ getMatte( materialIndex ) {
85
+
86
+ const array = this.image.data;
87
+ const index = materialIndex * MATERIAL_STRIDE + 5 * 4 + 3;
88
+ return Boolean( array[ index ] );
89
+
90
+ }
91
+
92
+ updateFrom( materials, textures ) {
93
+
94
+ function getTexture( material, key, def = - 1 ) {
95
+
96
+ return key in material ? textures.indexOf( material[ key ] ) : def;
97
+
98
+ }
99
+
100
+ function getField( material, key, def ) {
101
+
102
+ return key in material ? material[ key ] : def;
103
+
104
+ }
105
+
106
+ /**
107
+ *
108
+ * @param {Object} material
109
+ * @param {string} textureKey
110
+ * @param {Float32Array} array
111
+ * @param {number} offset
112
+ * @returns {8} number of floats occupied by texture transform matrix
113
+ */
114
+ function writeTextureMatrixToArray( material, textureKey, array, offset ) {
115
+
116
+ // check if texture exists
117
+ if ( material[ textureKey ] && material[ textureKey ].isTexture ) {
118
+
119
+ const elements = material[ textureKey ].matrix.elements;
120
+
121
+ let i = 0;
122
+
123
+ // first row
124
+ array[ offset + i ++ ] = elements[ 0 ];
125
+ array[ offset + i ++ ] = elements[ 3 ];
126
+ array[ offset + i ++ ] = elements[ 6 ];
127
+ i ++;
128
+
129
+ // second row
130
+ array[ offset + i ++ ] = elements[ 1 ];
131
+ array[ offset + i ++ ] = elements[ 4 ];
132
+ array[ offset + i ++ ] = elements[ 7 ];
133
+ i ++;
134
+
135
+ }
136
+
137
+ return 8;
138
+
139
+ }
140
+
141
+ let index = 0;
142
+ const pixelCount = materials.length * MATERIAL_PIXELS;
143
+ const dimension = Math.ceil( Math.sqrt( pixelCount ) );
144
+
145
+ if ( this.image.width !== dimension ) {
146
+
147
+ this.dispose();
148
+
149
+ this.image.data = new Float32Array( dimension * dimension * 4 );
150
+ this.image.width = dimension;
151
+ this.image.height = dimension;
152
+
153
+ }
154
+
155
+ const floatArray = this.image.data;
156
+
157
+ // on some devices (Google Pixel 6) the "floatBitsToInt" function does not work correctly so we
158
+ // can't encode texture ids that way.
159
+ // const intArray = new Int32Array( floatArray.buffer );
160
+
161
+ for ( let i = 0, l = materials.length; i < l; i ++ ) {
162
+
163
+ const m = materials[ i ];
164
+
165
+ // color
166
+ floatArray[ index ++ ] = m.color.r;
167
+ floatArray[ index ++ ] = m.color.g;
168
+ floatArray[ index ++ ] = m.color.b;
169
+ floatArray[ index ++ ] = getTexture( m, 'map' );
170
+
171
+ // metalness & roughness
172
+ floatArray[ index ++ ] = getField( m, 'metalness', 0.0 );
173
+ floatArray[ index ++ ] = textures.indexOf( m.metalnessMap );
174
+ floatArray[ index ++ ] = getField( m, 'roughness', 0.0 );
175
+ floatArray[ index ++ ] = textures.indexOf( m.roughnessMap );
176
+
177
+ // transmission & emissiveIntensity
178
+ floatArray[ index ++ ] = getField( m, 'ior', 1.0 );
179
+ floatArray[ index ++ ] = getField( m, 'transmission', 0.0 );
180
+ floatArray[ index ++ ] = getTexture( m, 'transmissionMap' );
181
+ floatArray[ index ++ ] = getField( m, 'emissiveIntensity', 0.0 );
182
+
183
+ // emission
184
+ if ( 'emissive' in m ) {
185
+
186
+ floatArray[ index ++ ] = m.emissive.r;
187
+ floatArray[ index ++ ] = m.emissive.g;
188
+ floatArray[ index ++ ] = m.emissive.b;
189
+
190
+ } else {
191
+
192
+ floatArray[ index ++ ] = 0.0;
193
+ floatArray[ index ++ ] = 0.0;
194
+ floatArray[ index ++ ] = 0.0;
195
+
196
+ }
197
+
198
+ floatArray[ index ++ ] = getTexture( m, 'emissiveMap' );
199
+
200
+ // normals
201
+ floatArray[ index ++ ] = getTexture( m, 'normalMap' );
202
+ if ( 'normalScale' in m ) {
203
+
204
+ floatArray[ index ++ ] = m.normalScale.x;
205
+ floatArray[ index ++ ] = m.normalScale.y;
206
+
207
+ } else {
208
+
209
+ floatArray[ index ++ ] = 1;
210
+ floatArray[ index ++ ] = 1;
211
+
212
+ }
213
+
214
+ floatArray[ index ++ ] = getTexture( m, 'alphaMap' );
215
+
216
+ // side & matte
217
+ floatArray[ index ++ ] = m.opacity;
218
+ floatArray[ index ++ ] = m.alphaTest;
219
+ index ++; // side
220
+ index ++; // matte
221
+
222
+ index ++; // shadow
223
+ index ++;
224
+ index ++;
225
+ index ++;
226
+
227
+ // map transform
228
+ index += writeTextureMatrixToArray( m, 'map', floatArray, index );
229
+
230
+ // metalnessMap transform
231
+ index += writeTextureMatrixToArray( m, 'metalnessMap', floatArray, index );
232
+
233
+ // roughnessMap transform
234
+ index += writeTextureMatrixToArray( m, 'roughnessMap', floatArray, index );
235
+
236
+ // transmissionMap transform
237
+ index += writeTextureMatrixToArray( m, 'transmissionMap', floatArray, index );
238
+
239
+ // emissiveMap transform
240
+ index += writeTextureMatrixToArray( m, 'emissiveMap', floatArray, index );
241
+
242
+ // normalMap transform
243
+ index += writeTextureMatrixToArray( m, 'normalMap', floatArray, index );
244
+
245
+ }
246
+
247
+ this.needsUpdate = true;
248
+
249
+ }
250
+
251
+ }
@@ -1,36 +1,36 @@
1
- import { PhysicalCamera } from '../core/PhysicalCamera.js';
2
- export class PhysicalCameraUniform {
3
-
4
- constructor() {
5
-
6
- this.bokehSize = 0;
7
- this.apertureBlades = 0;
8
- this.apertureRotation = 0;
9
- this.focusDistance = 10;
10
- this.anamorphicRatio = 1;
11
-
12
- }
13
-
14
- updateFrom( camera ) {
15
-
16
- if ( camera instanceof PhysicalCamera ) {
17
-
18
- this.bokehSize = camera.bokehSize;
19
- this.apertureBlades = camera.apertureBlades;
20
- this.apertureRotation = camera.apertureRotation;
21
- this.focusDistance = camera.focusDistance;
22
- this.anamorphicRatio = camera.anamorphicRatio;
23
-
24
- } else {
25
-
26
- this.bokehSize = 0;
27
- this.apertureRotation = 0;
28
- this.apertureBlades = 0;
29
- this.focusDistance = 10;
30
- this.anamorphicRatio = 1;
31
-
32
- }
33
-
34
- }
35
-
36
- }
1
+ import { PhysicalCamera } from '../core/PhysicalCamera.js';
2
+ export class PhysicalCameraUniform {
3
+
4
+ constructor() {
5
+
6
+ this.bokehSize = 0;
7
+ this.apertureBlades = 0;
8
+ this.apertureRotation = 0;
9
+ this.focusDistance = 10;
10
+ this.anamorphicRatio = 1;
11
+
12
+ }
13
+
14
+ updateFrom( camera ) {
15
+
16
+ if ( camera instanceof PhysicalCamera ) {
17
+
18
+ this.bokehSize = camera.bokehSize;
19
+ this.apertureBlades = camera.apertureBlades;
20
+ this.apertureRotation = camera.apertureRotation;
21
+ this.focusDistance = camera.focusDistance;
22
+ this.anamorphicRatio = camera.anamorphicRatio;
23
+
24
+ } else {
25
+
26
+ this.bokehSize = 0;
27
+ this.apertureRotation = 0;
28
+ this.apertureBlades = 0;
29
+ this.focusDistance = 10;
30
+ this.anamorphicRatio = 1;
31
+
32
+ }
33
+
34
+ }
35
+
36
+ }
@@ -44,6 +44,7 @@ export class RenderTarget2DArray extends WebGLArrayRenderTarget {
44
44
  renderer.getClearColor( prevColor );
45
45
 
46
46
  // resize the render target and ensure we don't have an empty texture
47
+ // render target depth must be >= 1 to avoid unbound texture error on android devices
47
48
  const depth = textures.length || 1;
48
49
  this.setSize( width, height, depth );
49
50
  renderer.setClearColor( 0, 0 );
@@ -54,11 +55,23 @@ export class RenderTarget2DArray extends WebGLArrayRenderTarget {
54
55
  for ( let i = 0, l = depth; i < l; i ++ ) {
55
56
 
56
57
  const texture = textures[ i ];
57
- fsQuad.material.map = texture;
58
- fsQuad.material.transparent = true;
58
+ if ( texture ) {
59
59
 
60
- renderer.setRenderTarget( this, i );
61
- fsQuad.render( renderer );
60
+ // revert to default texture transform before rendering
61
+ texture.matrixAutoUpdate = false;
62
+ texture.matrix.identity();
63
+
64
+ fsQuad.material.map = texture;
65
+ fsQuad.material.transparent = true;
66
+
67
+ renderer.setRenderTarget( this, i );
68
+ fsQuad.render( renderer );
69
+
70
+ // restore custom texture transform
71
+ texture.updateMatrix();
72
+ texture.matrixAutoUpdate = true;
73
+
74
+ }
62
75
 
63
76
  }
64
77