three-gpu-pathtracer 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +887 -815
  3. package/build/index.module.js +5796 -5451
  4. package/build/index.module.js.map +1 -1
  5. package/build/index.umd.cjs +5795 -5448
  6. package/build/index.umd.cjs.map +1 -1
  7. package/package.json +69 -68
  8. package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
  9. package/src/core/MaterialReducer.js +256 -256
  10. package/src/core/PathTracingRenderer.js +270 -270
  11. package/src/core/PathTracingSceneGenerator.js +1 -1
  12. package/src/index.js +39 -35
  13. package/src/materials/AlphaDisplayMaterial.js +48 -48
  14. package/src/materials/AmbientOcclusionMaterial.js +197 -197
  15. package/src/materials/BlendMaterial.js +67 -67
  16. package/src/materials/DenoiseMaterial.js +142 -142
  17. package/src/materials/GraphMaterial.js +243 -243
  18. package/src/materials/LambertPathTracingMaterial.js +285 -285
  19. package/src/materials/MaterialBase.js +56 -56
  20. package/src/materials/PhysicalPathTracingMaterial.js +973 -970
  21. package/src/objects/EquirectCamera.js +13 -13
  22. package/src/objects/PhysicalCamera.js +28 -28
  23. package/src/objects/PhysicalSpotLight.js +14 -14
  24. package/src/objects/ShapedAreaLight.js +12 -12
  25. package/src/shader/shaderEnvMapSampling.js +59 -59
  26. package/src/shader/shaderGGXFunctions.js +100 -100
  27. package/src/shader/shaderIridescenceFunctions.js +130 -130
  28. package/src/shader/shaderLayerTexelFetchFunctions.js +25 -0
  29. package/src/shader/shaderLightSampling.js +231 -231
  30. package/src/shader/shaderMaterialSampling.js +504 -542
  31. package/src/shader/shaderSheenFunctions.js +98 -98
  32. package/src/shader/shaderStructs.js +321 -321
  33. package/src/shader/shaderUtils.js +403 -364
  34. package/src/textures/GradientEquirectTexture.js +35 -0
  35. package/src/textures/ProceduralEquirectTexture.js +75 -0
  36. package/src/uniforms/AttributesTextureArray.js +35 -0
  37. package/src/uniforms/EquirectHdrInfoUniform.js +259 -259
  38. package/src/uniforms/FloatAttributeTextureArray.js +169 -0
  39. package/src/uniforms/IESProfilesTexture.js +100 -100
  40. package/src/uniforms/LightsInfoUniformStruct.js +162 -162
  41. package/src/uniforms/MaterialsTexture.js +420 -426
  42. package/src/uniforms/PhysicalCameraUniform.js +36 -36
  43. package/src/uniforms/RenderTarget2DArray.js +97 -93
  44. package/src/uniforms/utils.js +21 -0
  45. package/src/utils/BlurredEnvMapGenerator.js +116 -113
  46. package/src/utils/IESLoader.js +325 -325
  47. package/src/utils/UVUnwrapper.js +101 -101
  48. package/src/workers/PathTracingSceneWorker.js +42 -42
@@ -0,0 +1,169 @@
1
+ import { DataArrayTexture, FloatType, RGBAFormat } from 'three';
2
+ import { FloatVertexAttributeTexture } from 'three-mesh-bvh';
3
+
4
+ function copyArrayToArray( fromArray, fromStride, toArray, toStride, offset ) {
5
+
6
+ if ( fromStride > toStride ) {
7
+
8
+ throw new Error();
9
+
10
+ }
11
+
12
+ // scale non-float values to their normalized range
13
+ const count = fromArray.length / fromStride;
14
+ const bpe = fromArray.constructor.BYTES_PER_ELEMENT * 8;
15
+ let maxValue = 1.0;
16
+ switch ( fromArray.constructor ) {
17
+
18
+ case Uint8Array:
19
+ case Uint16Array:
20
+ case Uint32Array:
21
+ maxValue = 2 ** bpe - 1;
22
+ break;
23
+
24
+ case Int8Array:
25
+ case Int16Array:
26
+ case Int32Array:
27
+ maxValue = 2 ** ( bpe - 1 ) - 1;
28
+ break;
29
+
30
+ }
31
+
32
+ for ( let i = 0; i < count; i ++ ) {
33
+
34
+ const i4 = 4 * i;
35
+ const is = fromStride * i;
36
+ for ( let j = 0; j < toStride; j ++ ) {
37
+
38
+ toArray[ offset + i4 + j ] = fromStride >= j + 1 ? fromArray[ is + j ] / maxValue : 0;
39
+
40
+ }
41
+
42
+ }
43
+
44
+ }
45
+
46
+ export class FloatAttributeTextureArray extends DataArrayTexture {
47
+
48
+ constructor() {
49
+
50
+ super();
51
+ this._textures = [];
52
+ this.type = FloatType;
53
+ this.format = RGBAFormat;
54
+ this.internalFormat = 'RGBA32F';
55
+
56
+ }
57
+
58
+ updateAttribute( index, attr ) {
59
+
60
+ // update the texture
61
+ const tex = this._textures[ index ];
62
+ tex.updateFrom( attr );
63
+
64
+ // ensure compatibility
65
+ const baseImage = tex.image;
66
+ const image = this.image;
67
+ if ( baseImage.width !== image.width || baseImage.height !== image.height ) {
68
+
69
+ throw new Error( 'FloatAttributeTextureArray: Attribute must be the same dimensions when updating single layer.' );
70
+
71
+ }
72
+
73
+ // update the image
74
+ const { width, height, data } = image;
75
+ const length = width * height * 4;
76
+ const offset = length * index;
77
+ let itemSize = attr.itemSize;
78
+ if ( itemSize === 3 ) {
79
+
80
+ itemSize = 4;
81
+
82
+ }
83
+
84
+ // copy the data
85
+ copyArrayToArray( tex.image.data, itemSize, data, 4, offset );
86
+
87
+ this.dispose();
88
+ this.needsUpdate = true;
89
+
90
+ }
91
+
92
+ setAttributes( attrs ) {
93
+
94
+ // ensure the attribute count
95
+ const itemCount = attrs[ 0 ].count;
96
+ const attrsLength = attrs.length;
97
+ for ( let i = 0, l = attrsLength; i < l; i ++ ) {
98
+
99
+ if ( attrs[ i ].count !== itemCount ) {
100
+
101
+ throw new Error( 'FloatAttributeTextureArray: All attributes must have the same item count.' );
102
+
103
+ }
104
+
105
+ }
106
+
107
+ // initialize all textures
108
+ const textures = this._textures;
109
+ while ( textures.length < attrsLength ) {
110
+
111
+ const tex = new FloatVertexAttributeTexture();
112
+ textures.push( tex );
113
+
114
+ }
115
+
116
+ while ( textures.length > attrsLength ) {
117
+
118
+ textures.pop();
119
+
120
+ }
121
+
122
+ // update all textures
123
+ for ( let i = 0, l = attrsLength; i < l; i ++ ) {
124
+
125
+ textures[ i ].updateFrom( attrs[ i ] );
126
+
127
+ }
128
+
129
+ // determine if we need to create a new array
130
+ const baseTexture = textures[ 0 ];
131
+ const baseImage = baseTexture.image;
132
+ const image = this.image;
133
+
134
+ if ( baseImage.width !== image.width || baseImage.height !== image.height || baseImage.depth !== attrsLength ) {
135
+
136
+ image.width = baseImage.width;
137
+ image.height = baseImage.height;
138
+ image.depth = attrsLength;
139
+ image.data = new Float32Array( image.width * image.height * image.depth * 4 );
140
+
141
+ }
142
+
143
+ // copy the other texture data into the data array texture
144
+ const { data, width, height } = image;
145
+ for ( let i = 0, l = attrsLength; i < l; i ++ ) {
146
+
147
+ const tex = textures[ i ];
148
+ const length = width * height * 4;
149
+ const offset = length * i;
150
+
151
+ let itemSize = attrs[ i ].itemSize;
152
+ if ( itemSize === 3 ) {
153
+
154
+ itemSize = 4;
155
+
156
+ }
157
+
158
+ copyArrayToArray( tex.image.data, itemSize, data, 4, offset );
159
+
160
+ }
161
+
162
+ // reset the texture
163
+ this.dispose();
164
+ this.needsUpdate = true;
165
+
166
+ }
167
+
168
+
169
+ }
@@ -1,100 +1,100 @@
1
- import {
2
- ClampToEdgeWrapping,
3
- Color,
4
- FloatType,
5
- LinearFilter,
6
- MeshBasicMaterial,
7
- NoToneMapping,
8
- RGBAFormat,
9
- WebGLArrayRenderTarget,
10
- } from 'three';
11
- import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
12
- import { IESLoader } from '../utils/IESLoader.js';
13
-
14
- const prevColor = new Color();
15
- export class IESProfilesTexture extends WebGLArrayRenderTarget {
16
-
17
- constructor( ...args ) {
18
-
19
- super( ...args );
20
-
21
- const tex = this.texture;
22
- tex.format = RGBAFormat;
23
- tex.type = FloatType;
24
- tex.minFilter = LinearFilter;
25
- tex.magFilter = LinearFilter;
26
- tex.wrapS = ClampToEdgeWrapping;
27
- tex.wrapT = ClampToEdgeWrapping;
28
- tex.generateMipmaps = false;
29
-
30
- tex.updateFrom = ( ...args ) => {
31
-
32
- this.updateFrom( ...args );
33
-
34
- };
35
-
36
- const fsQuad = new FullScreenQuad( new MeshBasicMaterial() );
37
- this.fsQuad = fsQuad;
38
-
39
- this.iesLoader = new IESLoader();
40
-
41
- }
42
-
43
- async updateFrom( renderer, textures ) {
44
-
45
- // save previous renderer state
46
- const prevRenderTarget = renderer.getRenderTarget();
47
- const prevToneMapping = renderer.toneMapping;
48
- const prevAlpha = renderer.getClearAlpha();
49
- renderer.getClearColor( prevColor );
50
-
51
- // resize the render target and ensure we don't have an empty texture
52
- // render target depth must be >= 1 to avoid unbound texture error on android devices
53
- const depth = textures.length || 1;
54
- this.setSize( 360, 180, depth );
55
- renderer.setClearColor( 0, 0 );
56
- renderer.toneMapping = NoToneMapping;
57
-
58
- // render each texture into each layer of the target
59
- const fsQuad = this.fsQuad;
60
- for ( let i = 0, l = depth; i < l; i ++ ) {
61
-
62
- const texture = textures[ i ];
63
- if ( texture ) {
64
-
65
- // revert to default texture transform before rendering
66
- texture.matrixAutoUpdate = false;
67
- texture.matrix.identity();
68
-
69
- fsQuad.material.map = texture;
70
- fsQuad.material.transparent = true;
71
-
72
- renderer.setRenderTarget( this, i );
73
- fsQuad.render( renderer );
74
-
75
- // restore custom texture transform
76
- texture.updateMatrix();
77
- texture.matrixAutoUpdate = true;
78
-
79
- }
80
-
81
- }
82
-
83
- // reset the renderer
84
- fsQuad.material.map = null;
85
- renderer.setClearColor( prevColor, prevAlpha );
86
- renderer.setRenderTarget( prevRenderTarget );
87
- renderer.toneMapping = prevToneMapping;
88
-
89
- fsQuad.dispose();
90
-
91
- }
92
-
93
- dispose() {
94
-
95
- super.dispose();
96
- this.fsQuad.dispose();
97
-
98
- }
99
-
100
- }
1
+ import {
2
+ ClampToEdgeWrapping,
3
+ Color,
4
+ FloatType,
5
+ LinearFilter,
6
+ MeshBasicMaterial,
7
+ NoToneMapping,
8
+ RGBAFormat,
9
+ WebGLArrayRenderTarget,
10
+ } from 'three';
11
+ import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
12
+ import { IESLoader } from '../utils/IESLoader.js';
13
+
14
+ const prevColor = new Color();
15
+ export class IESProfilesTexture extends WebGLArrayRenderTarget {
16
+
17
+ constructor( ...args ) {
18
+
19
+ super( ...args );
20
+
21
+ const tex = this.texture;
22
+ tex.format = RGBAFormat;
23
+ tex.type = FloatType;
24
+ tex.minFilter = LinearFilter;
25
+ tex.magFilter = LinearFilter;
26
+ tex.wrapS = ClampToEdgeWrapping;
27
+ tex.wrapT = ClampToEdgeWrapping;
28
+ tex.generateMipmaps = false;
29
+
30
+ tex.updateFrom = ( ...args ) => {
31
+
32
+ this.updateFrom( ...args );
33
+
34
+ };
35
+
36
+ const fsQuad = new FullScreenQuad( new MeshBasicMaterial() );
37
+ this.fsQuad = fsQuad;
38
+
39
+ this.iesLoader = new IESLoader();
40
+
41
+ }
42
+
43
+ async updateFrom( renderer, textures ) {
44
+
45
+ // save previous renderer state
46
+ const prevRenderTarget = renderer.getRenderTarget();
47
+ const prevToneMapping = renderer.toneMapping;
48
+ const prevAlpha = renderer.getClearAlpha();
49
+ renderer.getClearColor( prevColor );
50
+
51
+ // resize the render target and ensure we don't have an empty texture
52
+ // render target depth must be >= 1 to avoid unbound texture error on android devices
53
+ const depth = textures.length || 1;
54
+ this.setSize( 360, 180, depth );
55
+ renderer.setClearColor( 0, 0 );
56
+ renderer.toneMapping = NoToneMapping;
57
+
58
+ // render each texture into each layer of the target
59
+ const fsQuad = this.fsQuad;
60
+ for ( let i = 0, l = depth; i < l; i ++ ) {
61
+
62
+ const texture = textures[ i ];
63
+ if ( texture ) {
64
+
65
+ // revert to default texture transform before rendering
66
+ texture.matrixAutoUpdate = false;
67
+ texture.matrix.identity();
68
+
69
+ fsQuad.material.map = texture;
70
+ fsQuad.material.transparent = true;
71
+
72
+ renderer.setRenderTarget( this, i );
73
+ fsQuad.render( renderer );
74
+
75
+ // restore custom texture transform
76
+ texture.updateMatrix();
77
+ texture.matrixAutoUpdate = true;
78
+
79
+ }
80
+
81
+ }
82
+
83
+ // reset the renderer
84
+ fsQuad.material.map = null;
85
+ renderer.setClearColor( prevColor, prevAlpha );
86
+ renderer.setRenderTarget( prevRenderTarget );
87
+ renderer.toneMapping = prevToneMapping;
88
+
89
+ fsQuad.dispose();
90
+
91
+ }
92
+
93
+ dispose() {
94
+
95
+ super.dispose();
96
+ this.fsQuad.dispose();
97
+
98
+ }
99
+
100
+ }
@@ -1,162 +1,162 @@
1
- import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, Vector3, Quaternion, Matrix4 } from 'three';
2
-
3
- const LIGHT_PIXELS = 6;
4
- const RECT_AREA_LIGHT = 0;
5
- const CIRC_AREA_LIGHT = 1;
6
- const SPOT_LIGHT = 2;
7
- export class LightsInfoUniformStruct {
8
-
9
- constructor() {
10
-
11
- const tex = new DataTexture( new Float32Array( 4 ), 1, 1 );
12
- tex.format = RGBAFormat;
13
- tex.type = FloatType;
14
- tex.wrapS = ClampToEdgeWrapping;
15
- tex.wrapT = ClampToEdgeWrapping;
16
- tex.generateMipmaps = false;
17
-
18
- this.tex = tex;
19
- this.count = 0;
20
-
21
- }
22
-
23
- updateFrom( lights, iesTextures = [] ) {
24
-
25
- const tex = this.tex;
26
- const pixelCount = Math.max( lights.length * LIGHT_PIXELS, 1 );
27
- const dimension = Math.ceil( Math.sqrt( pixelCount ) );
28
-
29
- if ( tex.image.width !== dimension ) {
30
-
31
- tex.dispose();
32
-
33
- tex.image.data = new Float32Array( dimension * dimension * 4 );
34
- tex.image.width = dimension;
35
- tex.image.height = dimension;
36
-
37
- }
38
-
39
- const floatArray = tex.image.data;
40
-
41
- const u = new Vector3();
42
- const v = new Vector3();
43
- const m = new Matrix4();
44
- const worldQuaternion = new Quaternion();
45
- const eye = new Vector3();
46
- const target = new Vector3();
47
- const up = new Vector3();
48
-
49
- for ( let i = 0, l = lights.length; i < l; i ++ ) {
50
-
51
- const l = lights[ i ];
52
-
53
- const baseIndex = i * LIGHT_PIXELS * 4;
54
- let index = 0;
55
-
56
- // sample 1
57
- // position
58
- l.getWorldPosition( v );
59
- floatArray[ baseIndex + ( index ++ ) ] = v.x;
60
- floatArray[ baseIndex + ( index ++ ) ] = v.y;
61
- floatArray[ baseIndex + ( index ++ ) ] = v.z;
62
-
63
- // type
64
- let type = RECT_AREA_LIGHT;
65
- if ( l.isRectAreaLight && l.isCircular ) type = CIRC_AREA_LIGHT;
66
- else if ( l.isSpotLight ) type = SPOT_LIGHT;
67
- floatArray[ baseIndex + ( index ++ ) ] = type;
68
-
69
- // sample 2
70
- // color
71
- floatArray[ baseIndex + ( index ++ ) ] = l.color.r;
72
- floatArray[ baseIndex + ( index ++ ) ] = l.color.g;
73
- floatArray[ baseIndex + ( index ++ ) ] = l.color.b;
74
-
75
- // intensity
76
- floatArray[ baseIndex + ( index ++ ) ] = l.intensity;
77
-
78
- l.getWorldQuaternion( worldQuaternion );
79
-
80
- if ( l.isRectAreaLight ) {
81
-
82
- // sample 3
83
- // u vector
84
- u.set( l.width, 0, 0 ).applyQuaternion( worldQuaternion );
85
-
86
- floatArray[ baseIndex + ( index ++ ) ] = u.x;
87
- floatArray[ baseIndex + ( index ++ ) ] = u.y;
88
- floatArray[ baseIndex + ( index ++ ) ] = u.z;
89
- index ++;
90
-
91
- // sample 4
92
- // v vector
93
- v.set( 0, l.height, 0 ).applyQuaternion( worldQuaternion );
94
-
95
- floatArray[ baseIndex + ( index ++ ) ] = v.x;
96
- floatArray[ baseIndex + ( index ++ ) ] = v.y;
97
- floatArray[ baseIndex + ( index ++ ) ] = v.z;
98
-
99
- // area
100
- floatArray[ baseIndex + ( index ++ ) ] = u.cross( v ).length() * ( l.isCircular ? ( Math.PI / 4.0 ) : 1.0 );
101
-
102
- } else if ( l.isSpotLight ) {
103
-
104
- const radius = l.radius;
105
- eye.setFromMatrixPosition( l.matrixWorld );
106
- target.setFromMatrixPosition( l.target.matrixWorld );
107
- m.lookAt( eye, target, up );
108
- worldQuaternion.setFromRotationMatrix( m );
109
-
110
- // sample 3
111
- // u vector
112
- u.set( 1, 0, 0 ).applyQuaternion( worldQuaternion );
113
-
114
- floatArray[ baseIndex + ( index ++ ) ] = u.x;
115
- floatArray[ baseIndex + ( index ++ ) ] = u.y;
116
- floatArray[ baseIndex + ( index ++ ) ] = u.z;
117
- index ++;
118
-
119
- // sample 4
120
- // v vector
121
- v.set( 0, 1, 0 ).applyQuaternion( worldQuaternion );
122
-
123
- floatArray[ baseIndex + ( index ++ ) ] = v.x;
124
- floatArray[ baseIndex + ( index ++ ) ] = v.y;
125
- floatArray[ baseIndex + ( index ++ ) ] = v.z;
126
-
127
- // area
128
- floatArray[ baseIndex + ( index ++ ) ] = Math.PI * radius * radius;
129
-
130
- // sample 5
131
- // radius
132
- floatArray[ baseIndex + ( index ++ ) ] = radius;
133
-
134
- // near
135
- floatArray[ baseIndex + ( index ++ ) ] = l.shadow.camera.near;
136
-
137
- // decay
138
- floatArray[ baseIndex + ( index ++ ) ] = l.decay;
139
-
140
- // distance
141
- floatArray[ baseIndex + ( index ++ ) ] = l.distance;
142
-
143
- // sample 6
144
- // coneCos
145
- floatArray[ baseIndex + ( index ++ ) ] = Math.cos( l.angle );
146
-
147
- // penumbraCos
148
- floatArray[ baseIndex + ( index ++ ) ] = Math.cos( l.angle * ( 1 - l.penumbra ) );
149
-
150
- // iesProfile
151
- floatArray[ baseIndex + ( index ++ ) ] = iesTextures.indexOf( l.iesTexture );
152
-
153
- }
154
-
155
- }
156
-
157
- tex.needsUpdate = true;
158
- this.count = lights.length;
159
-
160
- }
161
-
162
- }
1
+ import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, Vector3, Quaternion, Matrix4 } from 'three';
2
+
3
+ const LIGHT_PIXELS = 6;
4
+ const RECT_AREA_LIGHT = 0;
5
+ const CIRC_AREA_LIGHT = 1;
6
+ const SPOT_LIGHT = 2;
7
+ export class LightsInfoUniformStruct {
8
+
9
+ constructor() {
10
+
11
+ const tex = new DataTexture( new Float32Array( 4 ), 1, 1 );
12
+ tex.format = RGBAFormat;
13
+ tex.type = FloatType;
14
+ tex.wrapS = ClampToEdgeWrapping;
15
+ tex.wrapT = ClampToEdgeWrapping;
16
+ tex.generateMipmaps = false;
17
+
18
+ this.tex = tex;
19
+ this.count = 0;
20
+
21
+ }
22
+
23
+ updateFrom( lights, iesTextures = [] ) {
24
+
25
+ const tex = this.tex;
26
+ const pixelCount = Math.max( lights.length * LIGHT_PIXELS, 1 );
27
+ const dimension = Math.ceil( Math.sqrt( pixelCount ) );
28
+
29
+ if ( tex.image.width !== dimension ) {
30
+
31
+ tex.dispose();
32
+
33
+ tex.image.data = new Float32Array( dimension * dimension * 4 );
34
+ tex.image.width = dimension;
35
+ tex.image.height = dimension;
36
+
37
+ }
38
+
39
+ const floatArray = tex.image.data;
40
+
41
+ const u = new Vector3();
42
+ const v = new Vector3();
43
+ const m = new Matrix4();
44
+ const worldQuaternion = new Quaternion();
45
+ const eye = new Vector3();
46
+ const target = new Vector3();
47
+ const up = new Vector3();
48
+
49
+ for ( let i = 0, l = lights.length; i < l; i ++ ) {
50
+
51
+ const l = lights[ i ];
52
+
53
+ const baseIndex = i * LIGHT_PIXELS * 4;
54
+ let index = 0;
55
+
56
+ // sample 1
57
+ // position
58
+ l.getWorldPosition( v );
59
+ floatArray[ baseIndex + ( index ++ ) ] = v.x;
60
+ floatArray[ baseIndex + ( index ++ ) ] = v.y;
61
+ floatArray[ baseIndex + ( index ++ ) ] = v.z;
62
+
63
+ // type
64
+ let type = RECT_AREA_LIGHT;
65
+ if ( l.isRectAreaLight && l.isCircular ) type = CIRC_AREA_LIGHT;
66
+ else if ( l.isSpotLight ) type = SPOT_LIGHT;
67
+ floatArray[ baseIndex + ( index ++ ) ] = type;
68
+
69
+ // sample 2
70
+ // color
71
+ floatArray[ baseIndex + ( index ++ ) ] = l.color.r;
72
+ floatArray[ baseIndex + ( index ++ ) ] = l.color.g;
73
+ floatArray[ baseIndex + ( index ++ ) ] = l.color.b;
74
+
75
+ // intensity
76
+ floatArray[ baseIndex + ( index ++ ) ] = l.intensity;
77
+
78
+ l.getWorldQuaternion( worldQuaternion );
79
+
80
+ if ( l.isRectAreaLight ) {
81
+
82
+ // sample 3
83
+ // u vector
84
+ u.set( l.width, 0, 0 ).applyQuaternion( worldQuaternion );
85
+
86
+ floatArray[ baseIndex + ( index ++ ) ] = u.x;
87
+ floatArray[ baseIndex + ( index ++ ) ] = u.y;
88
+ floatArray[ baseIndex + ( index ++ ) ] = u.z;
89
+ index ++;
90
+
91
+ // sample 4
92
+ // v vector
93
+ v.set( 0, l.height, 0 ).applyQuaternion( worldQuaternion );
94
+
95
+ floatArray[ baseIndex + ( index ++ ) ] = v.x;
96
+ floatArray[ baseIndex + ( index ++ ) ] = v.y;
97
+ floatArray[ baseIndex + ( index ++ ) ] = v.z;
98
+
99
+ // area
100
+ floatArray[ baseIndex + ( index ++ ) ] = u.cross( v ).length() * ( l.isCircular ? ( Math.PI / 4.0 ) : 1.0 );
101
+
102
+ } else if ( l.isSpotLight ) {
103
+
104
+ const radius = l.radius;
105
+ eye.setFromMatrixPosition( l.matrixWorld );
106
+ target.setFromMatrixPosition( l.target.matrixWorld );
107
+ m.lookAt( eye, target, up );
108
+ worldQuaternion.setFromRotationMatrix( m );
109
+
110
+ // sample 3
111
+ // u vector
112
+ u.set( 1, 0, 0 ).applyQuaternion( worldQuaternion );
113
+
114
+ floatArray[ baseIndex + ( index ++ ) ] = u.x;
115
+ floatArray[ baseIndex + ( index ++ ) ] = u.y;
116
+ floatArray[ baseIndex + ( index ++ ) ] = u.z;
117
+ index ++;
118
+
119
+ // sample 4
120
+ // v vector
121
+ v.set( 0, 1, 0 ).applyQuaternion( worldQuaternion );
122
+
123
+ floatArray[ baseIndex + ( index ++ ) ] = v.x;
124
+ floatArray[ baseIndex + ( index ++ ) ] = v.y;
125
+ floatArray[ baseIndex + ( index ++ ) ] = v.z;
126
+
127
+ // area
128
+ floatArray[ baseIndex + ( index ++ ) ] = Math.PI * radius * radius;
129
+
130
+ // sample 5
131
+ // radius
132
+ floatArray[ baseIndex + ( index ++ ) ] = radius;
133
+
134
+ // near
135
+ floatArray[ baseIndex + ( index ++ ) ] = l.shadow.camera.near;
136
+
137
+ // decay
138
+ floatArray[ baseIndex + ( index ++ ) ] = l.decay;
139
+
140
+ // distance
141
+ floatArray[ baseIndex + ( index ++ ) ] = l.distance;
142
+
143
+ // sample 6
144
+ // coneCos
145
+ floatArray[ baseIndex + ( index ++ ) ] = Math.cos( l.angle );
146
+
147
+ // penumbraCos
148
+ floatArray[ baseIndex + ( index ++ ) ] = Math.cos( l.angle * ( 1 - l.penumbra ) );
149
+
150
+ // iesProfile
151
+ floatArray[ baseIndex + ( index ++ ) ] = iesTextures.indexOf( l.iesTexture );
152
+
153
+ }
154
+
155
+ }
156
+
157
+ tex.needsUpdate = true;
158
+ this.count = lights.length;
159
+
160
+ }
161
+
162
+ }