super-three 0.136.1 → 0.137.0

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 (100) hide show
  1. package/README.md +1 -1
  2. package/build/three.cjs +37132 -0
  3. package/build/three.js +71 -53
  4. package/build/three.min.js +2 -2
  5. package/build/three.module.js +80 -47
  6. package/examples/js/animation/MMDAnimationHelper.js +3 -1
  7. package/examples/js/controls/experimental/CameraControls.js +6 -2
  8. package/examples/js/exporters/GLTFExporter.js +82 -39
  9. package/examples/js/geometries/TextGeometry.js +12 -10
  10. package/examples/js/interactive/HTMLMesh.js +14 -2
  11. package/examples/js/loaders/EXRLoader.js +20 -9
  12. package/examples/js/loaders/GLTFLoader.js +1 -1
  13. package/examples/js/loaders/LDrawLoader.js +541 -425
  14. package/examples/js/loaders/MD2Loader.js +5 -5
  15. package/examples/js/loaders/MTLLoader.js +10 -3
  16. package/examples/js/loaders/PCDLoader.js +2 -2
  17. package/examples/js/loaders/STLLoader.js +1 -1
  18. package/examples/js/loaders/SVGLoader.js +3 -2
  19. package/examples/js/modifiers/EdgeSplitModifier.js +0 -6
  20. package/examples/js/modifiers/SimplifyModifier.js +0 -10
  21. package/examples/js/objects/Lensflare.js +2 -2
  22. package/examples/js/postprocessing/OutlinePass.js +1 -5
  23. package/examples/js/renderers/CSS2DRenderer.js +25 -19
  24. package/examples/js/renderers/CSS3DRenderer.js +37 -32
  25. package/examples/js/utils/LDrawUtils.js +182 -0
  26. package/examples/jsm/exporters/GLTFExporter.js +80 -12
  27. package/examples/jsm/geometries/TextGeometry.js +13 -13
  28. package/examples/jsm/interactive/HTMLMesh.js +16 -2
  29. package/examples/jsm/libs/flow.module.js +930 -169
  30. package/examples/jsm/loaders/EXRLoader.js +19 -9
  31. package/examples/jsm/loaders/GLTFLoader.js +1 -1
  32. package/examples/jsm/loaders/LDrawLoader.js +534 -442
  33. package/examples/jsm/loaders/MD2Loader.js +5 -5
  34. package/examples/jsm/loaders/MTLLoader.js +11 -4
  35. package/examples/jsm/loaders/PCDLoader.js +2 -2
  36. package/examples/jsm/loaders/STLLoader.js +1 -1
  37. package/examples/jsm/loaders/SVGLoader.js +3 -1
  38. package/examples/jsm/loaders/VRMLLoader.js +0 -1
  39. package/examples/jsm/modifiers/EdgeSplitModifier.js +0 -6
  40. package/examples/jsm/modifiers/SimplifyModifier.js +0 -10
  41. package/examples/jsm/node-editor/NodeEditor.js +435 -181
  42. package/examples/jsm/node-editor/accessors/NormalEditor.js +8 -8
  43. package/examples/jsm/node-editor/accessors/PositionEditor.js +8 -8
  44. package/examples/jsm/node-editor/accessors/UVEditor.js +6 -7
  45. package/examples/jsm/node-editor/core/BaseNode.js +83 -0
  46. package/examples/jsm/node-editor/display/BlendEditor.js +7 -6
  47. package/examples/jsm/node-editor/examples/animate-uv.json +1 -1
  48. package/examples/jsm/node-editor/examples/fake-top-light.json +1 -1
  49. package/examples/jsm/node-editor/examples/oscillator-color.json +1 -1
  50. package/examples/jsm/node-editor/examples/rim.json +1 -1
  51. package/examples/jsm/node-editor/inputs/ColorEditor.js +14 -10
  52. package/examples/jsm/node-editor/inputs/FloatEditor.js +6 -7
  53. package/examples/jsm/node-editor/inputs/SliderEditor.js +4 -5
  54. package/examples/jsm/node-editor/inputs/Vector2Editor.js +6 -7
  55. package/examples/jsm/node-editor/inputs/Vector3Editor.js +8 -9
  56. package/examples/jsm/node-editor/inputs/Vector4Editor.js +9 -10
  57. package/examples/jsm/node-editor/materials/BasicMaterialEditor.js +87 -0
  58. package/examples/jsm/node-editor/materials/PointsMaterialEditor.js +97 -0
  59. package/examples/jsm/node-editor/materials/StandardMaterialEditor.js +20 -17
  60. package/examples/jsm/node-editor/math/AngleEditor.js +39 -0
  61. package/examples/jsm/node-editor/math/DotEditor.js +6 -7
  62. package/examples/jsm/node-editor/math/InvertEditor.js +4 -3
  63. package/examples/jsm/node-editor/math/LimiterEditor.js +11 -10
  64. package/examples/jsm/node-editor/math/NormalizeEditor.js +6 -5
  65. package/examples/jsm/node-editor/math/OperatorEditor.js +12 -11
  66. package/examples/jsm/node-editor/math/PowerEditor.js +6 -5
  67. package/examples/jsm/node-editor/math/TrigonometryEditor.js +12 -7
  68. package/examples/jsm/node-editor/procedural/CheckerEditor.js +4 -3
  69. package/examples/jsm/node-editor/scene/MeshEditor.js +99 -0
  70. package/examples/jsm/node-editor/scene/Object3DEditor.js +160 -0
  71. package/examples/jsm/node-editor/scene/PointsEditor.js +99 -0
  72. package/examples/jsm/node-editor/utils/JoinEditor.js +58 -0
  73. package/examples/jsm/node-editor/utils/OscillatorEditor.js +7 -6
  74. package/examples/jsm/node-editor/utils/SplitEditor.js +39 -0
  75. package/examples/jsm/node-editor/utils/TimerEditor.js +6 -5
  76. package/examples/jsm/postprocessing/OutlinePass.js +1 -4
  77. package/examples/jsm/renderers/CSS2DRenderer.js +24 -19
  78. package/examples/jsm/renderers/CSS3DRenderer.js +36 -30
  79. package/examples/jsm/renderers/nodes/accessors/UVNode.js +4 -4
  80. package/examples/jsm/renderers/nodes/core/NodeBuilder.js +2 -1
  81. package/examples/jsm/renderers/nodes/utils/SplitNode.js +19 -4
  82. package/examples/jsm/utils/LDrawUtils.js +18 -11
  83. package/package.json +16 -9
  84. package/src/constants.js +1 -3
  85. package/src/core/BufferGeometry.js +2 -2
  86. package/src/geometries/LatheGeometry.js +1 -1
  87. package/src/loaders/FileLoader.js +20 -3
  88. package/src/math/Box3.js +24 -10
  89. package/src/renderers/WebGLRenderTarget.js +4 -1
  90. package/src/renderers/WebGLRenderer.js +3 -3
  91. package/src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl.js +1 -1
  92. package/src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl.js +2 -2
  93. package/src/renderers/webgl/WebGLBackground.js +2 -2
  94. package/src/renderers/webgl/WebGLGeometries.js +2 -2
  95. package/src/renderers/webgl/WebGLPrograms.js +2 -2
  96. package/src/renderers/webgl/WebGLState.js +2 -2
  97. package/src/renderers/webgl/WebGLTextures.js +9 -6
  98. package/src/renderers/webgl/WebGLUtils.js +1 -3
  99. package/src/renderers/webxr/WebXRManager.js +2 -0
  100. package/src/utils.js +15 -1
@@ -114,7 +114,7 @@
114
114
 
115
115
  for ( let j = 0; j < 16; j ++ ) {
116
116
 
117
- const character = data.getUint8( offset + j, true );
117
+ const character = data.getUint8( offset + j );
118
118
  if ( character === 0 ) break;
119
119
  string[ j ] = character;
120
120
 
@@ -129,11 +129,11 @@
129
129
 
130
130
  for ( let j = 0; j < header.num_vertices; j ++ ) {
131
131
 
132
- let x = data.getUint8( offset ++, true );
133
- let y = data.getUint8( offset ++, true );
134
- let z = data.getUint8( offset ++, true );
132
+ let x = data.getUint8( offset ++ );
133
+ let y = data.getUint8( offset ++ );
134
+ let z = data.getUint8( offset ++ );
135
135
 
136
- const n = _normalData[ data.getUint8( offset ++, true ) ];
136
+ const n = _normalData[ data.getUint8( offset ++ ) ];
137
137
 
138
138
  x = x * scale.x + translation.x;
139
139
  y = y * scale.y + translation.y;
@@ -327,6 +327,13 @@
327
327
  map.offset.copy( texParams.offset );
328
328
  map.wrapS = scope.wrap;
329
329
  map.wrapT = scope.wrap;
330
+
331
+ if ( mapType === 'map' || mapType === 'emissiveMap' ) {
332
+
333
+ map.encoding = THREE.sRGBEncoding;
334
+
335
+ }
336
+
330
337
  params[ mapType ] = map;
331
338
 
332
339
  }
@@ -342,17 +349,17 @@
342
349
  // Ns is material specular exponent
343
350
  case 'kd':
344
351
  // Diffuse color (color under white light) using RGB values
345
- params.color = new THREE.Color().fromArray( value );
352
+ params.color = new THREE.Color().fromArray( value ).convertSRGBToLinear();
346
353
  break;
347
354
 
348
355
  case 'ks':
349
356
  // Specular color (color when light is reflected from shiny surface) using RGB values
350
- params.specular = new THREE.Color().fromArray( value );
357
+ params.specular = new THREE.Color().fromArray( value ).convertSRGBToLinear();
351
358
  break;
352
359
 
353
360
  case 'ke':
354
361
  // Emissive using RGB values
355
- params.emissive = new THREE.Color().fromArray( value );
362
+ params.emissive = new THREE.Color().fromArray( value ).convertSRGBToLinear();
356
363
  break;
357
364
 
358
365
  case 'map_kd':
@@ -262,9 +262,9 @@
262
262
 
263
263
  if ( offset.rgb !== undefined ) {
264
264
 
265
- color.push( dataview.getUint8( PCDheader.points * offset.rgb + PCDheader.size[ 3 ] * i + 0 ) / 255.0 );
266
- color.push( dataview.getUint8( PCDheader.points * offset.rgb + PCDheader.size[ 3 ] * i + 1 ) / 255.0 );
267
265
  color.push( dataview.getUint8( PCDheader.points * offset.rgb + PCDheader.size[ 3 ] * i + 2 ) / 255.0 );
266
+ color.push( dataview.getUint8( PCDheader.points * offset.rgb + PCDheader.size[ 3 ] * i + 1 ) / 255.0 );
267
+ color.push( dataview.getUint8( PCDheader.points * offset.rgb + PCDheader.size[ 3 ] * i + 0 ) / 255.0 );
268
268
 
269
269
  }
270
270
 
@@ -134,7 +134,7 @@
134
134
  // Check if each byte in query matches the corresponding byte from the current offset
135
135
  for ( let i = 0, il = query.length; i < il; i ++ ) {
136
136
 
137
- if ( query[ i ] !== reader.getUint8( offset + i, false ) ) return false;
137
+ if ( query[ i ] !== reader.getUint8( offset + i ) ) return false;
138
138
 
139
139
  }
140
140
 
@@ -110,7 +110,8 @@
110
110
 
111
111
  case 'use':
112
112
  style = parseStyle( node, style );
113
- const usedNodeId = node.href.baseVal.substring( 1 );
113
+ const href = node.getAttributeNS( 'http://www.w3.org/1999/xlink', 'href' ) || '';
114
+ const usedNodeId = href.substring( 1 );
114
115
  const usedNode = node.viewportElement.getElementById( usedNodeId );
115
116
 
116
117
  if ( usedNode ) {
@@ -561,7 +562,7 @@
561
562
  for ( let j = 0; j < selectorList.length; j ++ ) {
562
563
 
563
564
  // Remove empty rules
564
- const definitions = Object.fromEntries( Object.entries( stylesheet.style ).filter( ( [ _, v ] ) => v !== '' ) );
565
+ const definitions = Object.fromEntries( Object.entries( stylesheet.style ).filter( ( [ , v ] ) => v !== '' ) );
565
566
  stylesheets[ selectorList[ j ] ] = Object.assign( stylesheets[ selectorList[ j ] ] || {}, definitions );
566
567
 
567
568
  }
@@ -166,12 +166,6 @@
166
166
 
167
167
  if ( geometry.index == null ) {
168
168
 
169
- if ( THREE.BufferGeometryUtils === undefined ) {
170
-
171
- throw new Error( 'THREE.EdgeSplitModifier relies on THREE.BufferGeometryUtils' );
172
-
173
- }
174
-
175
169
  geometry = THREE.BufferGeometryUtils.mergeVertices( geometry );
176
170
 
177
171
  }
@@ -13,16 +13,6 @@
13
13
 
14
14
  class SimplifyModifier {
15
15
 
16
- constructor() {
17
-
18
- if ( THREE.BufferGeometryUtils === undefined ) {
19
-
20
- throw new Error( 'THREE.SimplifyModifier relies on THREE.BufferGeometryUtils' );
21
-
22
- }
23
-
24
- }
25
-
26
16
  modify( geometry, count ) {
27
17
 
28
18
  if ( geometry.isGeometry === true ) {
@@ -15,8 +15,8 @@
15
15
  const positionScreen = new THREE.Vector3();
16
16
  const positionView = new THREE.Vector3(); // textures
17
17
 
18
- const tempMap = new THREE.FramebufferTexture( 16, 16, THREE.RGBFormat );
19
- const occlusionMap = new THREE.FramebufferTexture( 16, 16, THREE.RGBFormat ); // material
18
+ const tempMap = new THREE.FramebufferTexture( 16, 16, THREE.RGBAFormat );
19
+ const occlusionMap = new THREE.FramebufferTexture( 16, 16, THREE.RGBAFormat ); // material
20
20
 
21
21
  const geometry = Lensflare.Geometry;
22
22
  const material1a = new THREE.RawShaderMaterial( {
@@ -25,10 +25,6 @@
25
25
  };
26
26
  const resx = Math.round( this.resolution.x / this.downSampleRatio );
27
27
  const resy = Math.round( this.resolution.y / this.downSampleRatio );
28
- this.maskBufferMaterial = new THREE.MeshBasicMaterial( {
29
- color: 0xffffff
30
- } );
31
- this.maskBufferMaterial.side = THREE.DoubleSide;
32
28
  this.renderTargetMaskBuffer = new THREE.WebGLRenderTarget( this.resolution.x, this.resolution.y, pars );
33
29
  this.renderTargetMaskBuffer.texture.name = 'OutlinePass.mask';
34
30
  this.renderTargetMaskBuffer.texture.generateMipmaps = false;
@@ -93,7 +89,7 @@
93
89
 
94
90
  function replaceDepthToViewZ( string, camera ) {
95
91
 
96
- var type = camera.isPerspectiveCamera ? 'perspective' : 'orthographic';
92
+ const type = camera.isPerspectiveCamera ? 'perspective' : 'orthographic';
97
93
  return string.replace( /DEPTH_TO_VIEW_Z/g, type + 'DepthToViewZ' );
98
94
 
99
95
  }
@@ -102,38 +102,44 @@
102
102
 
103
103
  if ( object.isCSS2DObject ) {
104
104
 
105
- object.onBeforeRender( _this, scene, camera );
105
+ const visible = object.visible && _vector.z >= - 1 && _vector.z <= 1 && object.layers.test( camera.layers );
106
+ object.element.style.display = visible ? '' : 'none';
106
107
 
107
- _vector.setFromMatrixPosition( object.matrixWorld );
108
+ if ( visible ) {
108
109
 
109
- _vector.applyMatrix4( _viewProjectionMatrix );
110
+ object.onBeforeRender( _this, scene, camera );
110
111
 
111
- const element = object.element;
112
+ _vector.setFromMatrixPosition( object.matrixWorld );
112
113
 
113
- if ( /apple/i.test( navigator.vendor ) ) {
114
+ _vector.applyMatrix4( _viewProjectionMatrix );
114
115
 
115
- // https://github.com/mrdoob/three.js/issues/21415
116
- element.style.transform = 'translate(-50%,-50%) translate(' + Math.round( _vector.x * _widthHalf + _widthHalf ) + 'px,' + Math.round( - _vector.y * _heightHalf + _heightHalf ) + 'px)';
116
+ const element = object.element;
117
117
 
118
- } else {
118
+ if ( /apple/i.test( navigator.vendor ) ) {
119
119
 
120
- element.style.transform = 'translate(-50%,-50%) translate(' + ( _vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - _vector.y * _heightHalf + _heightHalf ) + 'px)';
120
+ // https://github.com/mrdoob/three.js/issues/21415
121
+ element.style.transform = 'translate(-50%,-50%) translate(' + Math.round( _vector.x * _widthHalf + _widthHalf ) + 'px,' + Math.round( - _vector.y * _heightHalf + _heightHalf ) + 'px)';
121
122
 
122
- }
123
+ } else {
123
124
 
124
- element.style.display = object.visible && _vector.z >= - 1 && _vector.z <= 1 ? '' : 'none';
125
- const objectData = {
126
- distanceToCameraSquared: getDistanceToSquared( camera, object )
127
- };
128
- cache.objects.set( object, objectData );
125
+ element.style.transform = 'translate(-50%,-50%) translate(' + ( _vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - _vector.y * _heightHalf + _heightHalf ) + 'px)';
129
126
 
130
- if ( element.parentNode !== domElement ) {
127
+ }
131
128
 
132
- domElement.appendChild( element );
129
+ const objectData = {
130
+ distanceToCameraSquared: getDistanceToSquared( camera, object )
131
+ };
132
+ cache.objects.set( object, objectData );
133
133
 
134
- }
134
+ if ( element.parentNode !== domElement ) {
135
+
136
+ domElement.appendChild( element );
135
137
 
136
- object.onAfterRender( _this, scene, camera );
138
+ }
139
+
140
+ object.onAfterRender( _this, scene, camera );
141
+
142
+ }
137
143
 
138
144
  }
139
145
 
@@ -181,57 +181,62 @@
181
181
 
182
182
  if ( object.isCSS3DObject ) {
183
183
 
184
- object.onBeforeRender( _this, scene, camera );
185
- let style;
184
+ const visible = object.visible && object.layers.test( camera.layers );
185
+ object.element.style.display = visible ? '' : 'none'; // only getObjectCSSMatrix when object.visible
186
186
 
187
- if ( object.isCSS3DSprite ) {
187
+ if ( visible ) {
188
188
 
189
- // http://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/
190
- _matrix.copy( camera.matrixWorldInverse );
189
+ object.onBeforeRender( _this, scene, camera );
190
+ let style;
191
191
 
192
- _matrix.transpose();
192
+ if ( object.isCSS3DSprite ) {
193
193
 
194
- if ( object.rotation2D !== 0 ) _matrix.multiply( _matrix2.makeRotationZ( object.rotation2D ) );
195
- object.matrixWorld.decompose( _position, _quaternion, _scale );
194
+ // http://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/
195
+ _matrix.copy( camera.matrixWorldInverse );
196
196
 
197
- _matrix.setPosition( _position );
197
+ _matrix.transpose();
198
198
 
199
- _matrix.scale( _scale );
199
+ if ( object.rotation2D !== 0 ) _matrix.multiply( _matrix2.makeRotationZ( object.rotation2D ) );
200
+ object.matrixWorld.decompose( _position, _quaternion, _scale );
200
201
 
201
- _matrix.elements[ 3 ] = 0;
202
- _matrix.elements[ 7 ] = 0;
203
- _matrix.elements[ 11 ] = 0;
204
- _matrix.elements[ 15 ] = 1;
205
- style = getObjectCSSMatrix( _matrix );
202
+ _matrix.setPosition( _position );
206
203
 
207
- } else {
204
+ _matrix.scale( _scale );
208
205
 
209
- style = getObjectCSSMatrix( object.matrixWorld );
206
+ _matrix.elements[ 3 ] = 0;
207
+ _matrix.elements[ 7 ] = 0;
208
+ _matrix.elements[ 11 ] = 0;
209
+ _matrix.elements[ 15 ] = 1;
210
+ style = getObjectCSSMatrix( _matrix );
210
211
 
211
- }
212
+ } else {
212
213
 
213
- const element = object.element;
214
- const cachedObject = cache.objects.get( object );
214
+ style = getObjectCSSMatrix( object.matrixWorld );
215
215
 
216
- if ( cachedObject === undefined || cachedObject.style !== style ) {
216
+ }
217
217
 
218
- element.style.transform = style;
219
- const objectData = {
220
- style: style
221
- };
222
- cache.objects.set( object, objectData );
218
+ const element = object.element;
219
+ const cachedObject = cache.objects.get( object );
223
220
 
224
- }
221
+ if ( cachedObject === undefined || cachedObject.style !== style ) {
225
222
 
226
- element.style.display = object.visible ? '' : 'none';
223
+ element.style.transform = style;
224
+ const objectData = {
225
+ style: style
226
+ };
227
+ cache.objects.set( object, objectData );
227
228
 
228
- if ( element.parentNode !== cameraElement ) {
229
+ }
229
230
 
230
- cameraElement.appendChild( element );
231
+ if ( element.parentNode !== cameraElement ) {
231
232
 
232
- }
233
+ cameraElement.appendChild( element );
233
234
 
234
- object.onAfterRender( _this, scene, camera );
235
+ }
236
+
237
+ object.onAfterRender( _this, scene, camera );
238
+
239
+ }
235
240
 
236
241
  }
237
242
 
@@ -0,0 +1,182 @@
1
+ ( function () {
2
+
3
+ class LDrawUtils {
4
+
5
+ static mergeObject( object ) {
6
+
7
+ // Merges geometries in object by materials and returns new object. Use on not indexed geometries.
8
+ // The object buffers reference the old object ones.
9
+ // Special treatment is done to the conditional lines generated by LDrawLoader.
10
+ function extractGroup( geometry, group, elementSize, isConditionalLine ) {
11
+
12
+ // Extracts a group from a geometry as a new geometry (with attribute buffers referencing original buffers)
13
+ const newGeometry = new THREE.BufferGeometry();
14
+ const originalPositions = geometry.getAttribute( 'position' ).array;
15
+ const originalNormals = elementSize === 3 ? geometry.getAttribute( 'normal' ).array : null;
16
+ const numVertsGroup = Math.min( group.count, Math.floor( originalPositions.length / 3 ) - group.start );
17
+ const vertStart = group.start * 3;
18
+ const vertEnd = ( group.start + numVertsGroup ) * 3;
19
+ const positions = originalPositions.subarray( vertStart, vertEnd );
20
+ const normals = originalNormals !== null ? originalNormals.subarray( vertStart, vertEnd ) : null;
21
+ newGeometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
22
+ if ( normals !== null ) newGeometry.setAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
23
+
24
+ if ( isConditionalLine ) {
25
+
26
+ const controlArray0 = geometry.getAttribute( 'control0' ).array.subarray( vertStart, vertEnd );
27
+ const controlArray1 = geometry.getAttribute( 'control1' ).array.subarray( vertStart, vertEnd );
28
+ const directionArray = geometry.getAttribute( 'direction' ).array.subarray( vertStart, vertEnd );
29
+ newGeometry.setAttribute( 'control0', new THREE.BufferAttribute( controlArray0, 3, false ) );
30
+ newGeometry.setAttribute( 'control1', new THREE.BufferAttribute( controlArray1, 3, false ) );
31
+ newGeometry.setAttribute( 'direction', new THREE.BufferAttribute( directionArray, 3, false ) );
32
+
33
+ }
34
+
35
+ return newGeometry;
36
+
37
+ }
38
+
39
+ function addGeometry( mat, geometry, geometries ) {
40
+
41
+ const geoms = geometries[ mat.uuid ];
42
+
43
+ if ( ! geoms ) {
44
+
45
+ geometries[ mat.uuid ] = {
46
+ mat: mat,
47
+ arr: [ geometry ]
48
+ };
49
+
50
+ } else {
51
+
52
+ geoms.arr.push( geometry );
53
+
54
+ }
55
+
56
+ }
57
+
58
+ function permuteAttribute( attribute, elemSize ) {
59
+
60
+ // Permutes first two vertices of each attribute element
61
+ if ( ! attribute ) return;
62
+ const verts = attribute.array;
63
+ const numVerts = Math.floor( verts.length / 3 );
64
+ let offset = 0;
65
+
66
+ for ( let i = 0; i < numVerts; i ++ ) {
67
+
68
+ const x = verts[ offset ];
69
+ const y = verts[ offset + 1 ];
70
+ const z = verts[ offset + 2 ];
71
+ verts[ offset ] = verts[ offset + 3 ];
72
+ verts[ offset + 1 ] = verts[ offset + 4 ];
73
+ verts[ offset + 2 ] = verts[ offset + 5 ];
74
+ verts[ offset + 3 ] = x;
75
+ verts[ offset + 4 ] = y;
76
+ verts[ offset + 5 ] = z;
77
+ offset += elemSize * 3;
78
+
79
+ }
80
+
81
+ } // Traverse the object hierarchy collecting geometries and transforming them to world space
82
+
83
+
84
+ const meshGeometries = {};
85
+ const linesGeometries = {};
86
+ const condLinesGeometries = {};
87
+ object.updateMatrixWorld( true );
88
+ const normalMatrix = new THREE.Matrix3();
89
+ object.traverse( c => {
90
+
91
+ if ( c.isMesh | c.isLineSegments ) {
92
+
93
+ const elemSize = c.isMesh ? 3 : 2;
94
+ const geometry = c.geometry.clone();
95
+ const matrixIsInverted = c.matrixWorld.determinant() < 0;
96
+
97
+ if ( matrixIsInverted ) {
98
+
99
+ permuteAttribute( geometry.attributes.position, elemSize );
100
+ permuteAttribute( geometry.attributes.normal, elemSize );
101
+
102
+ }
103
+
104
+ geometry.applyMatrix4( c.matrixWorld );
105
+
106
+ if ( c.isConditionalLine ) {
107
+
108
+ geometry.attributes.control0.applyMatrix4( c.matrixWorld );
109
+ geometry.attributes.control1.applyMatrix4( c.matrixWorld );
110
+ normalMatrix.getNormalMatrix( c.matrixWorld );
111
+ geometry.attributes.direction.applyNormalMatrix( normalMatrix );
112
+
113
+ }
114
+
115
+ const geometries = c.isMesh ? meshGeometries : c.isConditionalLine ? condLinesGeometries : linesGeometries;
116
+
117
+ if ( Array.isArray( c.material ) ) {
118
+
119
+ for ( const groupIndex in geometry.groups ) {
120
+
121
+ const group = geometry.groups[ groupIndex ];
122
+ const mat = c.material[ group.materialIndex ];
123
+ const newGeometry = extractGroup( geometry, group, elemSize, c.isConditionalLine );
124
+ addGeometry( mat, newGeometry, geometries );
125
+
126
+ }
127
+
128
+ } else {
129
+
130
+ addGeometry( c.material, geometry, geometries );
131
+
132
+ }
133
+
134
+ }
135
+
136
+ } ); // Create object with merged geometries
137
+
138
+ const mergedObject = new THREE.Group();
139
+ const meshMaterialsIds = Object.keys( meshGeometries );
140
+
141
+ for ( const i in meshMaterialsIds ) {
142
+
143
+ const meshGeometry = meshGeometries[ meshMaterialsIds[ i ] ];
144
+ const mergedGeometry = THREE.mergeBufferGeometries( meshGeometry.arr );
145
+ mergedObject.add( new THREE.Mesh( mergedGeometry, meshGeometry.mat ) );
146
+
147
+ }
148
+
149
+ const linesMaterialsIds = Object.keys( linesGeometries );
150
+
151
+ for ( const i in linesMaterialsIds ) {
152
+
153
+ const lineGeometry = linesGeometries[ linesMaterialsIds[ i ] ];
154
+ const mergedGeometry = THREE.mergeBufferGeometries( lineGeometry.arr );
155
+ mergedObject.add( new THREE.LineSegments( mergedGeometry, lineGeometry.mat ) );
156
+
157
+ }
158
+
159
+ const condLinesMaterialsIds = Object.keys( condLinesGeometries );
160
+
161
+ for ( const i in condLinesMaterialsIds ) {
162
+
163
+ const condLineGeometry = condLinesGeometries[ condLinesMaterialsIds[ i ] ];
164
+ const mergedGeometry = THREE.mergeBufferGeometries( condLineGeometry.arr );
165
+ const condLines = new THREE.LineSegments( mergedGeometry, condLineGeometry.mat );
166
+ condLines.isConditionalLine = true;
167
+ mergedObject.add( condLines );
168
+
169
+ }
170
+
171
+ mergedObject.userData.constructionStep = 0;
172
+ mergedObject.userData.numConstructionSteps = 1;
173
+ return mergedObject;
174
+
175
+ }
176
+
177
+ }
178
+
179
+ THREE.LDrawUtils = {};
180
+ THREE.LDrawUtils.LDrawUtils = LDrawUtils;
181
+
182
+ } )();
@@ -17,6 +17,7 @@ import {
17
17
  RGBAFormat,
18
18
  RepeatWrapping,
19
19
  Scene,
20
+ Texture,
20
21
  Vector3
21
22
  } from 'three';
22
23
 
@@ -688,6 +689,79 @@ class GLTFWriter {
688
689
 
689
690
  }
690
691
 
692
+ buildORMTexture( material ) {
693
+
694
+ const occlusion = material.aoMap?.image;
695
+ const roughness = material.roughnessMap?.image;
696
+ const metalness = material.metalnessMap?.image;
697
+
698
+ if ( occlusion === roughness && roughness === metalness ) return occlusion;
699
+
700
+ if ( occlusion || roughness || metalness ) {
701
+
702
+ const width = Math.max( occlusion?.width || 0, roughness?.width || 0, metalness?.width || 0 );
703
+ const height = Math.max( occlusion?.height || 0, roughness?.height || 0, metalness?.height || 0 );
704
+
705
+ const canvas = document.createElement( 'canvas' );
706
+ canvas.width = width;
707
+ canvas.height = height;
708
+
709
+ const context = canvas.getContext( '2d' );
710
+ context.fillStyle = '#ffffff';
711
+ context.fillRect( 0, 0, width, height );
712
+
713
+ const composite = context.getImageData( 0, 0, width, height );
714
+
715
+ if ( occlusion ) {
716
+
717
+ context.drawImage( occlusion, 0, 0, width, height );
718
+
719
+ const data = context.getImageData( 0, 0, width, height ).data;
720
+
721
+ for ( let i = 0; i < data.length; i += 4 ) {
722
+
723
+ composite.data[ i ] = data[ i ];
724
+
725
+ }
726
+
727
+ }
728
+
729
+ if ( roughness ) {
730
+
731
+ context.drawImage( roughness, 0, 0, width, height );
732
+
733
+ const data = context.getImageData( 0, 0, width, height ).data;
734
+
735
+ for ( let i = 1; i < data.length; i += 4 ) {
736
+
737
+ composite.data[ i ] = data[ i ];
738
+
739
+ }
740
+
741
+ }
742
+
743
+ if ( metalness ) {
744
+
745
+ context.drawImage( metalness, 0, 0, width, height );
746
+
747
+ const data = context.getImageData( 0, 0, width, height ).data;
748
+
749
+ for ( let i = 2; i < data.length; i += 4 ) {
750
+
751
+ composite.data[ i ] = data[ i ];
752
+
753
+ }
754
+
755
+ }
756
+
757
+ context.putImageData( composite, 0, 0 );
758
+
759
+ return new Texture( canvas );
760
+
761
+ }
762
+
763
+ }
764
+
691
765
  /**
692
766
  * Process a buffer to append to the default one.
693
767
  * @param {ArrayBuffer} buffer
@@ -1178,20 +1252,14 @@ class GLTFWriter {
1178
1252
 
1179
1253
  }
1180
1254
 
1255
+ const ormTexture = this.buildORMTexture( material );
1256
+
1181
1257
  // pbrMetallicRoughness.metallicRoughnessTexture
1182
1258
  if ( material.metalnessMap || material.roughnessMap ) {
1183
1259
 
1184
- if ( material.metalnessMap === material.roughnessMap ) {
1185
-
1186
- const metalRoughMapDef = { index: this.processTexture( material.metalnessMap ) };
1187
- this.applyTextureTransform( metalRoughMapDef, material.metalnessMap );
1188
- materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
1189
-
1190
- } else {
1191
-
1192
- console.warn( 'THREE.GLTFExporter: Ignoring metalnessMap and roughnessMap because they are not the same Texture.' );
1193
-
1194
- }
1260
+ const metalRoughMapDef = { index: this.processTexture( ormTexture ) };
1261
+ this.applyTextureTransform( metalRoughMapDef, material.metalnessMap || material.roughnessMap );
1262
+ materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef;
1195
1263
 
1196
1264
  }
1197
1265
 
@@ -1257,7 +1325,7 @@ class GLTFWriter {
1257
1325
  if ( material.aoMap ) {
1258
1326
 
1259
1327
  const occlusionMapDef = {
1260
- index: this.processTexture( material.aoMap ),
1328
+ index: this.processTexture( ormTexture ),
1261
1329
  texCoord: 1
1262
1330
  };
1263
1331
 
@@ -16,7 +16,6 @@
16
16
  */
17
17
 
18
18
  import {
19
- BufferGeometry,
20
19
  ExtrudeGeometry
21
20
  } from 'three';
22
21
 
@@ -26,26 +25,27 @@ class TextGeometry extends ExtrudeGeometry {
26
25
 
27
26
  const font = parameters.font;
28
27
 
29
- if ( ! ( font && font.isFont ) ) {
28
+ if ( font === undefined ) {
30
29
 
31
- console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
32
- return new BufferGeometry();
30
+ super(); // generate default extrude geometry
33
31
 
34
- }
32
+ } else {
33
+
34
+ const shapes = font.generateShapes( text, parameters.size );
35
35
 
36
- const shapes = font.generateShapes( text, parameters.size );
36
+ // translate parameters to ExtrudeGeometry API
37
37
 
38
- // translate parameters to ExtrudeGeometry API
38
+ parameters.depth = parameters.height !== undefined ? parameters.height : 50;
39
39
 
40
- parameters.depth = parameters.height !== undefined ? parameters.height : 50;
40
+ // defaults
41
41
 
42
- // defaults
42
+ if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
43
+ if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
44
+ if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
43
45
 
44
- if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
45
- if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
46
- if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
46
+ super( shapes, parameters );
47
47
 
48
- super( shapes, parameters );
48
+ }
49
49
 
50
50
  this.type = 'TextGeometry';
51
51