@needle-tools/engine 3.7.7-beta → 3.9.0-alpha

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 (116) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/needle-engine.js +473 -87019
  3. package/dist/needle-engine.light.js +473 -84478
  4. package/dist/needle-engine.light.min.js +1 -5805
  5. package/dist/needle-engine.light.umd.cjs +1 -5805
  6. package/dist/needle-engine.min.js +1 -5818
  7. package/dist/needle-engine.umd.cjs +1 -5818
  8. package/lib/engine/codegen/register_types.js +2 -0
  9. package/lib/engine/codegen/register_types.js.map +1 -1
  10. package/lib/engine/debug/debug.d.ts +1 -1
  11. package/lib/engine/engine_context.d.ts +3 -1
  12. package/lib/engine/engine_context.js +18 -13
  13. package/lib/engine/engine_context.js.map +1 -1
  14. package/lib/engine/engine_element.js +15 -8
  15. package/lib/engine/engine_element.js.map +1 -1
  16. package/lib/engine/engine_element_overlay.d.ts +2 -1
  17. package/lib/engine/engine_element_overlay.js +38 -55
  18. package/lib/engine/engine_element_overlay.js.map +1 -1
  19. package/lib/engine/engine_lightdata.js +6 -7
  20. package/lib/engine/engine_lightdata.js.map +1 -1
  21. package/lib/engine/engine_networking_utils.d.ts +1 -1
  22. package/lib/engine/engine_networking_utils.js.map +1 -1
  23. package/lib/engine/engine_scenelighting.js +5 -5
  24. package/lib/engine/engine_scenelighting.js.map +1 -1
  25. package/lib/engine/extensions/NEEDLE_lightmaps.js +3 -3
  26. package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
  27. package/lib/engine/extensions/NEEDLE_render_objects.js +1 -1
  28. package/lib/engine/extensions/NEEDLE_render_objects.js.map +1 -1
  29. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +4 -1
  30. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  31. package/lib/engine/extensions/extensions.d.ts +1 -1
  32. package/lib/engine/extensions/extensions.js +17 -3
  33. package/lib/engine/extensions/extensions.js.map +1 -1
  34. package/lib/engine-components/Camera.js +3 -3
  35. package/lib/engine-components/Camera.js.map +1 -1
  36. package/lib/engine-components/GroundProjection.js +1 -1
  37. package/lib/engine-components/GroundProjection.js.map +1 -1
  38. package/lib/engine-components/Light.js +58 -50
  39. package/lib/engine-components/Light.js.map +1 -1
  40. package/lib/engine-components/Networking.d.ts +1 -1
  41. package/lib/engine-components/OrbitControls.js +4 -3
  42. package/lib/engine-components/OrbitControls.js.map +1 -1
  43. package/lib/engine-components/ParticleSystem.d.ts +2 -1
  44. package/lib/engine-components/ParticleSystem.js +11 -1
  45. package/lib/engine-components/ParticleSystem.js.map +1 -1
  46. package/lib/engine-components/ReflectionProbe.js +3 -3
  47. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  48. package/lib/engine-components/Renderer.d.ts +1 -1
  49. package/lib/engine-components/Renderer.js +16 -13
  50. package/lib/engine-components/Renderer.js.map +1 -1
  51. package/lib/engine-components/RendererLightmap.d.ts +5 -8
  52. package/lib/engine-components/RendererLightmap.js +50 -39
  53. package/lib/engine-components/RendererLightmap.js.map +1 -1
  54. package/lib/engine-components/codegen/components.d.ts +1 -0
  55. package/lib/engine-components/codegen/components.js +1 -0
  56. package/lib/engine-components/codegen/components.js.map +1 -1
  57. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +1 -1
  58. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +34 -30
  59. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
  60. package/lib/engine-components/export/usdz/USDZExporter.js +2 -0
  61. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  62. package/lib/engine-components/export/usdz/extensions/USDZText.d.ts +2 -1
  63. package/lib/engine-components/export/usdz/extensions/USDZText.js +40 -3
  64. package/lib/engine-components/export/usdz/extensions/USDZText.js.map +1 -1
  65. package/lib/engine-components/export/usdz/extensions/USDZUI.d.ts +8 -0
  66. package/lib/engine-components/export/usdz/extensions/USDZUI.js +101 -0
  67. package/lib/engine-components/export/usdz/extensions/USDZUI.js.map +1 -0
  68. package/lib/engine-components/ui/BaseUIComponent.js +4 -0
  69. package/lib/engine-components/ui/BaseUIComponent.js.map +1 -1
  70. package/lib/engine-components/ui/Button.d.ts +1 -1
  71. package/lib/engine-components/ui/Button.js +4 -1
  72. package/lib/engine-components/ui/Button.js.map +1 -1
  73. package/lib/engine-components/ui/Canvas.js +9 -1
  74. package/lib/engine-components/ui/Canvas.js.map +1 -1
  75. package/lib/engine-components/ui/EventSystem.js +2 -0
  76. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  77. package/lib/engine-components/ui/Graphic.js +3 -3
  78. package/lib/engine-components/ui/Graphic.js.map +1 -1
  79. package/lib/engine-components/webxr/WebARCameraBackground.d.ts +1 -1
  80. package/lib/engine-components/webxr/WebARCameraBackground.js +2 -2
  81. package/lib/engine-components/webxr/WebARCameraBackground.js.map +1 -1
  82. package/lib/engine-components/webxr/WebXR.js +7 -6
  83. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  84. package/lib/engine-components/webxr/WebXRPlaneTracking.d.ts +1 -1
  85. package/package.json +5 -5
  86. package/src/engine/codegen/register_types.js +2 -0
  87. package/src/engine/engine_context.ts +21 -14
  88. package/src/engine/engine_element.ts +15 -8
  89. package/src/engine/engine_element_overlay.ts +41 -52
  90. package/src/engine/engine_lightdata.ts +6 -8
  91. package/src/engine/engine_networking_utils.ts +1 -1
  92. package/src/engine/engine_scenelighting.ts +5 -5
  93. package/src/engine/extensions/NEEDLE_lightmaps.ts +3 -3
  94. package/src/engine/extensions/NEEDLE_render_objects.ts +10 -8
  95. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +5 -1
  96. package/src/engine/extensions/extensions.ts +19 -4
  97. package/src/engine-components/Camera.ts +3 -3
  98. package/src/engine-components/GroundProjection.ts +1 -1
  99. package/src/engine-components/Light.ts +62 -57
  100. package/src/engine-components/OrbitControls.ts +4 -3
  101. package/src/engine-components/ParticleSystem.ts +14 -0
  102. package/src/engine-components/ReflectionProbe.ts +3 -3
  103. package/src/engine-components/Renderer.ts +21 -17
  104. package/src/engine-components/RendererLightmap.ts +55 -49
  105. package/src/engine-components/codegen/components.ts +1 -0
  106. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +43 -37
  107. package/src/engine-components/export/usdz/USDZExporter.ts +2 -0
  108. package/src/engine-components/export/usdz/extensions/USDZText.ts +41 -1
  109. package/src/engine-components/export/usdz/extensions/USDZUI.ts +120 -0
  110. package/src/engine-components/ui/BaseUIComponent.ts +5 -0
  111. package/src/engine-components/ui/Button.ts +3 -1
  112. package/src/engine-components/ui/Canvas.ts +7 -1
  113. package/src/engine-components/ui/EventSystem.ts +3 -1
  114. package/src/engine-components/ui/Graphic.ts +3 -3
  115. package/src/engine-components/webxr/WebARCameraBackground.ts +3 -3
  116. package/src/engine-components/webxr/WebXR.ts +7 -7
@@ -1,7 +1,9 @@
1
1
  import { Behaviour, GameObject } from "./Component";
2
- import * as THREE from "three";
3
- import { Texture } from "three";
2
+ import { Material, Mesh, Shader, ShaderMaterial, Texture, Vector4 } from "three";
4
3
  import { Context, OnRenderCallback } from "../engine/engine_setup";
4
+ import { getParam } from "../engine/engine_utils";
5
+
6
+ const debug = getParam("debuglightmaps");
5
7
 
6
8
  // this component is automatically added by the Renderer if the object has lightmap uvs AND we have a lightmap
7
9
  // for multimaterial objects GLTF exports a "Group" with the renderer component
@@ -19,20 +21,20 @@ export class RendererLightmap {
19
21
  }
20
22
 
21
23
  lightmapIndex: number = -1;
22
- lightmapScaleOffset: THREE.Vector4 = new THREE.Vector4(1, 1, 0, 0);
24
+ lightmapScaleOffset: THREE.Vector4 = new Vector4(1, 1, 0, 0);
23
25
 
24
26
  private context: Context;
25
- private gameObject: GameObject;
26
- private lightmapTexture: THREE.Texture | null = null;
27
- private lightmapScaleOffsetUniform = { value: new THREE.Vector4(1, 1, 0, 0) };
28
- private lightmapUniform: { value: THREE.Texture | null } = { value: null };
27
+ private gameObject: Mesh;
28
+ private lightmapTexture: Texture | null = null;
29
+ private lightmapScaleOffsetUniform = { value: new Vector4(1, 1, 0, 0) };
30
+ private lightmapUniform: { value: Texture | null } = { value: null };
29
31
 
30
- constructor(gameObject: GameObject, context: Context) {
32
+ constructor(gameObject: Mesh, context: Context) {
31
33
  this.gameObject = gameObject;
32
34
  this.context = context;
33
35
  }
34
36
 
35
- init(lightmapIndex: number, lightmapScaleOffset: THREE.Vector4, lightmapTexture: THREE.Texture, debug: boolean = false) {
37
+ init(lightmapIndex: number, lightmapScaleOffset: Vector4, lightmapTexture: Texture) {
36
38
  console.assert(this.gameObject !== undefined && this.gameObject !== null, "Missing gameobject", this);
37
39
 
38
40
  this.lightmapIndex = lightmapIndex;
@@ -40,24 +42,25 @@ export class RendererLightmap {
40
42
  this.lightmapScaleOffset = lightmapScaleOffset;
41
43
  this.lightmapTexture = lightmapTexture;
42
44
 
43
- const debugLightmaps = debug;
44
- if (debugLightmaps) this.setLightmapDebugMaterial();
45
+ if (debug) this.setLightmapDebugMaterial();
45
46
  this.applyLightmap();
46
47
  }
47
48
 
48
- bindOnBeforeRender() {
49
- this.context.removeBeforeRenderListener(this.gameObject, this.onBeforeRenderThreeComplete);
50
- this.context.addBeforeRenderListener(this.gameObject, this.onBeforeRenderThreeComplete);
49
+ updateLightmapUniforms(material: Material) {
50
+ const uniforms = material["uniforms"];
51
+ if (uniforms && uniforms.lightmap) {
52
+ this.lightmapScaleOffsetUniform.value = this.lightmapScaleOffset;
53
+ this.lightmapUniform.value = this.lightmapTexture;
54
+ uniforms.lightmap = this.lightmapUniform;
55
+ uniforms.lightmapScaleOffset = this.lightmapScaleOffsetUniform;
56
+ }
51
57
  }
52
58
 
53
- private onBeforeRenderThreeComplete = (_renderer, _scene, _camera, _geometry, material, _group) => {
54
- this.onBeforeRenderThree(material);
55
- }
56
59
 
57
60
  private applyLightmap() {
58
-
59
61
  if (this.gameObject.type === "Object3D") {
60
- // console.warn("Can not add lightmap. Is this object missing a renderer?");
62
+ if (debug)
63
+ console.warn("Can not add lightmap. Is this object missing a renderer?", this.gameObject.name);
61
64
  return;
62
65
  }
63
66
 
@@ -68,23 +71,28 @@ export class RendererLightmap {
68
71
 
69
72
  console.assert(this.gameObject.type === "Mesh", "Lightmap only works on meshes", this);
70
73
 
71
- const mesh = this.gameObject as unknown as THREE.Mesh;
72
- // TODO: ensure uv2 exists
73
- if (!mesh.geometry.getAttribute("uv2"))
74
- mesh.geometry.setAttribute("uv2", mesh.geometry.getAttribute("uv"));
75
-
76
- const mat = this.gameObject["material"].clone();
77
- this.gameObject["material"] = mat;
78
-
79
- this.gameObject["material"].onBeforeCompile = (shader, _) => {
80
- shader.uniforms.lightmap = this.lightmapUniform;
81
- shader.uniforms.lightmapScaleOffset = this.lightmapScaleOffsetUniform;
82
- };
83
-
74
+ const mesh = this.gameObject as unknown as Mesh;
75
+ if (!mesh.geometry.getAttribute("uv1"))
76
+ mesh.geometry.setAttribute("uv1", mesh.geometry.getAttribute("uv"));
77
+
78
+ if (Array.isArray(this.gameObject.material)) {
79
+ const mats: Material[] = this.gameObject.material;
80
+ for (let i = 0; i < mats.length; i++) {
81
+ const mat = mats[i];
82
+ const cloned = mat.clone();
83
+ mats[i] = cloned;
84
+ cloned.onBeforeCompile = this.onBeforeCompile;
85
+ }
86
+ }
87
+ else {
88
+ const mat: Material = this.gameObject.material.clone();
89
+ this.gameObject.material = mat;
90
+ this.gameObject.material.onBeforeCompile = this.onBeforeCompile;
91
+ }
84
92
 
85
93
  if (this.lightmapIndex >= 0) {
86
94
  const lightmap = this.lightmapTexture;
87
- const mat = this.gameObject["material"];
95
+ const mat = this.gameObject.material as any;
88
96
  if (mat && lightmap) {
89
97
  if (!mat.uniforms) mat.uniforms = {};
90
98
  mat.lightMap = lightmap;
@@ -93,27 +101,25 @@ export class RendererLightmap {
93
101
  }
94
102
  }
95
103
 
96
- onBeforeRenderThree(material: THREE.Material) {
97
-
98
- const uniforms = material["uniforms"];
99
- if (uniforms && uniforms.lightmap) {
100
- this.lightmapScaleOffsetUniform.value = this.lightmapScaleOffset;
101
- this.lightmapUniform.value = this.lightmapTexture;
102
- uniforms.lightmap = this.lightmapUniform;
103
- uniforms.lightmapScaleOffset = this.lightmapScaleOffsetUniform;
104
- }
104
+ private onBeforeCompile = (shader: Shader, _) => {
105
+ if(debug) console.log("Lightmaps, before compile")
106
+ //@ts-ignore
107
+ shader.lightMapUv = "uv1";
108
+ this.lightmapScaleOffsetUniform.value = this.lightmapScaleOffset;
109
+ this.lightmapUniform.value = this.lightmapTexture;
110
+ shader.uniforms.lightmap = this.lightmapUniform;
111
+ shader.uniforms.lightmapScaleOffset = this.lightmapScaleOffsetUniform;
105
112
  }
106
113
 
107
114
  private setLightmapDebugMaterial() {
108
115
 
109
116
  // debug lightmaps
110
- this.gameObject["material"] = new THREE.ShaderMaterial({
117
+ this.gameObject["material"] = new ShaderMaterial({
111
118
  vertexShader: `
112
- attribute vec2 uv2;
113
- varying vec2 vUv2;
119
+ varying vec2 vUv1;
114
120
  void main()
115
121
  {
116
- vUv2 = uv2;
122
+ vUv1 = uv1;
117
123
  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
118
124
  }
119
125
  `,
@@ -121,7 +127,7 @@ export class RendererLightmap {
121
127
  uniform sampler2D lightmap;
122
128
  uniform float lightMapIntensity;
123
129
  uniform vec4 lightmapScaleOffset;
124
- varying vec2 vUv2;
130
+ varying vec2 vUv1;
125
131
 
126
132
  // took from threejs 05fc79cd52b79e8c3e8dec1e7dca72c5c39983a4
127
133
  vec4 conv_sRGBToLinear( in vec4 value ) {
@@ -129,7 +135,7 @@ export class RendererLightmap {
129
135
  }
130
136
 
131
137
  void main() {
132
- vec2 lUv = vUv2.xy * lightmapScaleOffset.xy + vec2(lightmapScaleOffset.z, (1. - (lightmapScaleOffset.y + lightmapScaleOffset.w)));
138
+ vec2 lUv = vUv1.xy * lightmapScaleOffset.xy + vec2(lightmapScaleOffset.z, (1. - (lightmapScaleOffset.y + lightmapScaleOffset.w)));
133
139
 
134
140
  vec4 lightMapTexel = texture2D( lightmap, lUv);
135
141
  // The range of RGBM lightmaps goes from 0 to 34.49 (5^2.2) in linear space, and from 0 to 5 in gamma space.
@@ -138,7 +144,7 @@ export class RendererLightmap {
138
144
  //lightMapTexel = conv_sRGBToLinear(lightMapTexel);
139
145
  // lightMapTexel.rgb = vec3(1.);
140
146
 
141
- // gl_FragColor = vec4(vUv2.xy, 0, 1);
147
+ // gl_FragColor = vec4(vUv1.xy, 0, 1);
142
148
  gl_FragColor = lightMapTexel;
143
149
  }
144
150
  `,
@@ -184,6 +184,7 @@ export { UIRootComponent } from "../ui/BaseUIComponent";
184
184
  export { UsageMarker } from "../Interactable";
185
185
  export { USDZExporter } from "../export/usdz/USDZExporter";
186
186
  export { USDZText } from "../export/usdz/extensions/USDZText";
187
+ export { USDZUIExtension } from "../export/usdz/extensions/USDZUI";
187
188
  export { VariantAction } from "../export/usdz/extensions/behavior/Actions";
188
189
  export { VelocityOverLifetimeModule } from "../ParticleSystemModules";
189
190
  export { VerticalLayoutGroup } from "../ui/Layout";
@@ -657,7 +657,7 @@ function addResources( object, context: USDZExporterContext ) {
657
657
 
658
658
  if ( geometry ) {
659
659
 
660
- if ( material.isMeshStandardMaterial ) { // || material.isMeshBasicMaterial // TODO convert unlit to lit+emissive
660
+ if ( material.isMeshStandardMaterial || material.isMeshBasicMaterial ) { // TODO convert unlit to lit+emissive
661
661
 
662
662
  const geometryFileName = 'geometries/Geometry_' + geometry.id + '.usd';
663
663
 
@@ -1124,7 +1124,7 @@ ${array.join( '' )}
1124
1124
 
1125
1125
  }
1126
1126
 
1127
- function buildMaterial( material: MeshStandardMaterial, textures, quickLookCompatible = false ) {
1127
+ function buildMaterial( material: MeshBasicMaterial, textures, quickLookCompatible = false ) {
1128
1128
 
1129
1129
  // https://graphics.pixar.com/usd/docs/UsdPreviewSurface-Proposal.html
1130
1130
 
@@ -1182,7 +1182,9 @@ function buildMaterial( material: MeshStandardMaterial, textures, quickLookCompa
1182
1182
 
1183
1183
  const needsTextureScale = mapType !== 'normal' && (color && (color.r !== 1 || color.g !== 1 || color.b !== 1 || opacity !== 1)) || false;
1184
1184
  const needsNormalScaleAndBias = mapType === 'normal';
1185
- const normalScaleValueString = (material.normalScale ? material.normalScale.x * 2 : 2).toFixed( PRECISION );
1185
+ const normalScaleValueString = material instanceof MeshStandardMaterial
1186
+ ? (material.normalScale ? material.normalScale.x * 2 : 2).toFixed( PRECISION )
1187
+ : "1";
1186
1188
 
1187
1189
  return `
1188
1190
  ${needsTextureTransform ? `def Shader "Transform2d_${mapType}" (
@@ -1254,72 +1256,76 @@ function buildMaterial( material: MeshStandardMaterial, textures, quickLookCompa
1254
1256
 
1255
1257
  }
1256
1258
 
1257
- if ( material.emissiveMap ) {
1259
+ if ( material.aoMap ) {
1258
1260
 
1259
- inputs.push( `${pad}color3f inputs:emissiveColor.connect = </Materials/Material_${material.id}/Texture_${material.emissiveMap.id}_emissive.outputs:rgb>` );
1261
+ inputs.push( `${pad}float inputs:occlusion.connect = </Materials/Material_${material.id}/Texture_${material.aoMap.id}_occlusion.outputs:r>` );
1260
1262
 
1261
- samplers.push( buildTexture( material.emissiveMap, 'emissive' ) );
1263
+ samplers.push( buildTexture( material.aoMap, 'occlusion' ) );
1264
+
1265
+ }
1262
1266
 
1263
- } else if ( material.emissive?.getHex() > 0 ) {
1267
+ if ( material.alphaMap ) {
1268
+
1269
+ inputs.push( `${pad}float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.alphaMap.id}_opacity.outputs:r>` );
1270
+ inputs.push( `${pad}float inputs:opacityThreshold = 0.0001` );
1264
1271
 
1265
- inputs.push( `${pad}color3f inputs:emissiveColor = ${buildColor( material.emissive )}` );
1272
+ samplers.push( buildTexture( material.alphaMap, 'opacity' ) );
1266
1273
 
1267
1274
  } else {
1268
-
1269
- inputs.push( `${pad}color3f inputs:emissiveColor = (0, 0, 0)` );
1275
+
1276
+ inputs.push( `${pad}float inputs:opacity = ${effectiveOpacity}` );
1270
1277
 
1271
1278
  }
1272
1279
 
1273
- if ( material.normalMap ) {
1280
+ if ( material instanceof MeshStandardMaterial ) {
1274
1281
 
1275
- inputs.push( `${pad}normal3f inputs:normal.connect = </Materials/Material_${material.id}/Texture_${material.normalMap.id}_normal.outputs:rgb>` );
1282
+ if ( material.emissiveMap ) {
1276
1283
 
1277
- samplers.push( buildTexture( material.normalMap, 'normal' ) );
1284
+ inputs.push( `${pad}color3f inputs:emissiveColor.connect = </Materials/Material_${material.id}/Texture_${material.emissiveMap.id}_emissive.outputs:rgb>` );
1278
1285
 
1279
- }
1286
+ samplers.push( buildTexture( material.emissiveMap, 'emissive' ) );
1280
1287
 
1281
- if ( material.aoMap ) {
1282
-
1283
- inputs.push( `${pad}float inputs:occlusion.connect = </Materials/Material_${material.id}/Texture_${material.aoMap.id}_occlusion.outputs:r>` );
1288
+ } else if ( material.emissive?.getHex() > 0 ) {
1284
1289
 
1285
- samplers.push( buildTexture( material.aoMap, 'occlusion' ) );
1290
+ inputs.push( `${pad}color3f inputs:emissiveColor = ${buildColor( material.emissive )}` );
1286
1291
 
1287
- }
1292
+ } else {
1293
+
1294
+ inputs.push( `${pad}color3f inputs:emissiveColor = (0, 0, 0)` );
1288
1295
 
1289
- if ( material.roughnessMap && material.roughness === 1 ) {
1296
+ }
1290
1297
 
1291
- inputs.push( `${pad}float inputs:roughness.connect = </Materials/Material_${material.id}/Texture_${material.roughnessMap.id}_roughness.outputs:g>` );
1298
+ if ( material.normalMap ) {
1292
1299
 
1293
- samplers.push( buildTexture( material.roughnessMap, 'roughness' ) );
1300
+ inputs.push( `${pad}normal3f inputs:normal.connect = </Materials/Material_${material.id}/Texture_${material.normalMap.id}_normal.outputs:rgb>` );
1294
1301
 
1295
- } else {
1302
+ samplers.push( buildTexture( material.normalMap, 'normal' ) );
1296
1303
 
1297
- inputs.push( `${pad}float inputs:roughness = ${material.roughness !== undefined ? material.roughness : 1 }` );
1304
+ }
1298
1305
 
1299
- }
1306
+ if ( material.roughnessMap && material.roughness === 1 ) {
1300
1307
 
1301
- if ( material.metalnessMap && material.metalness === 1 ) {
1308
+ inputs.push( `${pad}float inputs:roughness.connect = </Materials/Material_${material.id}/Texture_${material.roughnessMap.id}_roughness.outputs:g>` );
1302
1309
 
1303
- inputs.push( `${pad}float inputs:metallic.connect = </Materials/Material_${material.id}/Texture_${material.metalnessMap.id}_metallic.outputs:b>` );
1310
+ samplers.push( buildTexture( material.roughnessMap, 'roughness' ) );
1304
1311
 
1305
- samplers.push( buildTexture( material.metalnessMap, 'metallic' ) );
1312
+ } else {
1306
1313
 
1307
- } else {
1314
+ inputs.push( `${pad}float inputs:roughness = ${material.roughness !== undefined ? material.roughness : 1 }` );
1308
1315
 
1309
- inputs.push( `${pad}float inputs:metallic = ${material.metalness !== undefined ? material.metalness : 0 }` );
1316
+ }
1310
1317
 
1311
- }
1318
+ if ( material.metalnessMap && material.metalness === 1 ) {
1312
1319
 
1313
- if ( material.alphaMap ) {
1320
+ inputs.push( `${pad}float inputs:metallic.connect = </Materials/Material_${material.id}/Texture_${material.metalnessMap.id}_metallic.outputs:b>` );
1314
1321
 
1315
- inputs.push( `${pad}float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.alphaMap.id}_opacity.outputs:r>` );
1316
- inputs.push( `${pad}float inputs:opacityThreshold = 0.0001` );
1322
+ samplers.push( buildTexture( material.metalnessMap, 'metallic' ) );
1317
1323
 
1318
- samplers.push( buildTexture( material.alphaMap, 'opacity' ) );
1324
+ } else {
1319
1325
 
1320
- } else {
1326
+ inputs.push( `${pad}float inputs:metallic = ${material.metalness !== undefined ? material.metalness : 0 }` );
1321
1327
 
1322
- inputs.push( `${pad}float inputs:opacity = ${effectiveOpacity}` );
1328
+ }
1323
1329
 
1324
1330
  }
1325
1331
 
@@ -16,6 +16,7 @@ import { hasProLicense } from "../../../engine/engine_license";
16
16
  import { BehaviorExtension } from "./extensions/behavior/Behaviour";
17
17
  import { AudioExtension } from "./extensions/behavior/AudioExtension";
18
18
  import { TextExtension } from "./extensions/USDZText";
19
+ import { USDZUIExtension } from "./extensions/USDZUI";
19
20
  import { Renderer } from "../../Renderer"
20
21
 
21
22
  const debug = getParam("debugusdz");
@@ -97,6 +98,7 @@ export class USDZExporter extends Behaviour {
97
98
  this.extensions.push(new BehaviorExtension());
98
99
  this.extensions.push(new AudioExtension());
99
100
  this.extensions.push(new TextExtension());
101
+ this.extensions.push(new USDZUIExtension());
100
102
  }
101
103
  }
102
104
 
@@ -146,8 +146,13 @@ export class TextExtension implements IUSDExporterExtension {
146
146
  return "text";
147
147
  }
148
148
 
149
- onExportObject(object: Object3D, model: USDObject, _context: USDZExporterContext) {
149
+ // HACK we should clean this up, text export has moved to USDZUI.ts and is
150
+ // integrated into the hierarchy now
151
+ onExportObject(_object: Object3D, _model: USDObject, _context: USDZExporterContext) {
150
152
 
153
+ return;
154
+
155
+ /*
151
156
  const text = GameObject.getComponent(object, Text);
152
157
  if (text) {
153
158
  const rt = GameObject.getComponent(object, RectTransform);
@@ -186,6 +191,41 @@ export class TextExtension implements IUSDExporterExtension {
186
191
  textObj.writeTo(undefined, writer);
187
192
  });
188
193
  }
194
+ */
195
+ }
196
+
197
+ exportText(object: Object3D, newModel: USDObject, _context: USDZExporterContext) {
198
+
199
+ const text = GameObject.getComponent(object, Text);
200
+ if (!text) return;
201
+
202
+ const rt = GameObject.getComponent(object, RectTransform);
203
+ let width = 100;
204
+ let height = 100;
205
+ if (rt) {
206
+ width = rt.width;
207
+ height = rt.height;
208
+ }
209
+
210
+ newModel.matrix = rotateYAxisMatrix.clone();
211
+ if (rt) // Not ideal but works for now:
212
+ newModel.matrix.premultiply(invertX);
213
+
214
+ const color = new Color().copySRGBToLinear(text.color);
215
+ newModel.material = new MeshStandardMaterial({ color: color, emissive: color });
216
+
217
+ newModel.addEventListener("serialize", (writer: USDWriter, _context: USDZExporterContext) => {
218
+ let txt = text.text;
219
+ txt = txt.replace(/\n/g, "\\n");
220
+ const textObj = TextBuilder.multiLine(txt, width, height, HorizontalAlignment.center, VerticalAlignment.bottom, TextWrapMode.flowing);
221
+ this.setTextAlignment(textObj, text.alignment);
222
+ this.setOverflow(textObj, text);
223
+ if (newModel.material)
224
+ textObj.material = newModel.material;
225
+ textObj.pointSize = this.convertToTextSize(text.fontSize);
226
+ textObj.depth = .001;
227
+ textObj.writeTo(undefined, writer);
228
+ });
189
229
  }
190
230
 
191
231
  private convertToTextSize(pixel: number) {
@@ -0,0 +1,120 @@
1
+ import { IUSDExporterExtension } from "../Extension";
2
+ import { USDObject, USDZExporterContext } from "../ThreeUSDZExporter";
3
+ import { GameObject } from "../../../Component";
4
+ import { Canvas } from "../../../ui/Canvas";
5
+ import { CanvasGroup } from "../../../ui/CanvasGroup";
6
+ import { $shadowDomOwner } from "../../../ui/BaseUIComponent";
7
+ import { RectTransform } from "../../../ui/RectTransform";
8
+ import { Color, Mesh, MeshBasicMaterial, Object3D } from "three";
9
+ import { TextExtension } from "./USDZText";
10
+ import { RenderMode } from "../../../ui/Canvas";
11
+
12
+ export class USDZUIExtension implements IUSDExporterExtension {
13
+ get extensionName(): string {
14
+ return "tmui";
15
+ }
16
+
17
+ // TODO would probably be better to export each object instead of the entire Canvas
18
+ // so that we don't export them twice (once as regular hierarchy, once as part of Canvas export)
19
+ onExportObject(object: Object3D, model: USDObject, _context: USDZExporterContext) {
20
+ const canvas = GameObject.getComponent(object, Canvas);
21
+
22
+ if (canvas && canvas.activeAndEnabled && canvas.renderMode === RenderMode.WorldSpace) {
23
+ const textExt = new TextExtension();
24
+ const rt = GameObject.getComponent(object, RectTransform);
25
+ const canvasGroup = GameObject.getComponent(object, CanvasGroup);
26
+
27
+ let width = 100;
28
+ let height = 100;
29
+ if (rt) {
30
+ width = rt.width;
31
+ height = rt.height;
32
+
33
+ const shadowRootModel = USDObject.createEmpty();
34
+ const shadowComponent = rt.shadowComponent;
35
+ model.add(shadowRootModel);
36
+
37
+ if (shadowComponent) {
38
+ const mat = shadowComponent.matrix;
39
+ shadowRootModel.matrix.copy(mat);
40
+ // shadowRootModel.matrix.premultiply(invertX);
41
+
42
+ // TODO build map of parent GOs to USDObjects so we can reparent while traversing
43
+ const usdObjectMap = new Map<Object3D, USDObject>();
44
+ const opacityMap = new Map<Object3D, number>();
45
+ usdObjectMap.set(shadowComponent, shadowRootModel);
46
+ opacityMap.set(shadowComponent, canvasGroup ? canvasGroup.alpha : 1);
47
+
48
+ shadowComponent.traverse((child) => {
49
+ if (child === shadowComponent) return;
50
+
51
+ const childModel = USDObject.createEmpty();
52
+ childModel.matrix.copy(child.matrix);
53
+
54
+ const childParent = child.parent;
55
+ const isText = childParent && typeof childParent["textContent"] === "string" && childParent["textContent"].length;
56
+ let hierarchyOpacity = opacityMap.get(childParent!) || 1;
57
+
58
+ // TODO CanvasGroup doesn't render something but modifies opacity
59
+ // get CanvasGroup and modify alpha here
60
+
61
+ const canvasGroup = GameObject.getComponent(child, CanvasGroup);
62
+ if (canvasGroup)
63
+ hierarchyOpacity *= canvasGroup.alpha;
64
+
65
+ if (child instanceof Mesh && isText) {
66
+ // get shadoDomOwner so we can export Text from the text extension directly
67
+ const shadowDomOwner = child[$shadowDomOwner].gameObject;
68
+ textExt.exportText(shadowDomOwner, childModel, _context);
69
+ }
70
+
71
+ if (child instanceof Mesh && !isText)
72
+ {
73
+ // UI behaves weird: it seems it's always flipped right now,
74
+ // and three magically fixes it when rendering
75
+ // see https://github.com/mrdoob/three.js/pull/12720#issue-275923930
76
+ // https://github.com/mrdoob/three.js/issues/17361
77
+ // So we need to fix the winding order after applying the negative scale.
78
+ const clonedGeo = child.geometry.clone();
79
+ clonedGeo.scale(1, 1, -1);
80
+ this.flipWindingOrder(clonedGeo);
81
+ childModel.geometry = clonedGeo;
82
+
83
+ const color = new Color();
84
+ const ownOpacity = child.material.opacity;
85
+ color.copy(child.material.color);
86
+
87
+ // Calculate opacity from parent chain and own alpha
88
+ childModel.material = new MeshBasicMaterial({
89
+ color: color,
90
+ opacity: ownOpacity * hierarchyOpacity,
91
+ map: child.material.map,
92
+ transparent: true,
93
+ });
94
+ }
95
+
96
+ usdObjectMap.set(child, childModel);
97
+ opacityMap.set(child, hierarchyOpacity);
98
+
99
+ const parentUsdzObject = usdObjectMap.get(childParent!);
100
+ if (!parentUsdzObject) {
101
+ console.error("Error when exporting UI: shadow component parent not found!", child, child.parent);
102
+ return;
103
+ }
104
+ parentUsdzObject.add(childModel);
105
+ });
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ private flipWindingOrder(geometry) {
112
+ const index = geometry.index.array
113
+ for (let i = 0, il = index.length / 3; i < il; i++) {
114
+ let x = index[i * 3]
115
+ index[i * 3] = index[i * 3 + 2]
116
+ index[i * 3 + 2] = x
117
+ }
118
+ geometry.index.needsUpdate = true
119
+ }
120
+ }
@@ -6,8 +6,11 @@ import { showGizmos } from '../../engine/engine_default_parameters';
6
6
  import { AxesHelper, Object3D } from 'three';
7
7
  import { ICanvas, IGraphic } from './Interfaces';
8
8
  import { ShadowCastingMode } from '../Renderer';
9
+ import { getParam } from '../../engine/engine_utils';
9
10
  export const includesDir = "./include";
10
11
 
12
+ const debug = getParam("debugshadowcomponents");
13
+
11
14
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
12
15
 
13
16
 
@@ -128,6 +131,8 @@ export class BaseUIComponent extends Behaviour {
128
131
  // otherwise it will fail when object are enabled at runtime
129
132
  if (needsUpdate)
130
133
  ThreeMeshUI.update();
134
+
135
+ if(debug) console.log(this.shadowComponent)
131
136
  }
132
137
 
133
138
 
@@ -116,8 +116,10 @@ export class Button extends Behaviour implements IPointerEventHandler {
116
116
  }
117
117
  }
118
118
 
119
- onPointerClick(_args: PointerEventData) {
119
+ onPointerClick(args: PointerEventData) {
120
120
  if (!this.interactable) return;
121
+ // Button clicks should only run with left mouse button
122
+ if(args.pointerId !== 0) return;
121
123
  if (debug) {
122
124
  console.warn("Button Click", this.onClick);
123
125
  showBalloonMessage("CLICKED button " + this.name + " at " + this.context.time.frameCount);
@@ -190,6 +190,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
190
190
  }
191
191
 
192
192
  onBeforeRenderRoutine = () => {
193
+ if(this.context.isInVR) return;
193
194
  this.previousParent = this.gameObject.parent;
194
195
  // console.log(this.previousParent?.name + "/" + this.gameObject.name);
195
196
 
@@ -208,6 +209,7 @@ export class Canvas extends UIRootComponent implements ICanvas {
208
209
  }
209
210
 
210
211
  onAfterRenderRoutine = () => {
212
+ if(this.context.isInVR) return;
211
213
  if ((this.screenspace || this.renderOnTop) && this.previousParent && this.context.mainCamera) {
212
214
  if (this.screenspace) {
213
215
  const camObj = this.context.mainCamera;
@@ -215,7 +217,10 @@ export class Canvas extends UIRootComponent implements ICanvas {
215
217
  } else {
216
218
  this.previousParent.add(this.gameObject);
217
219
  }
220
+ const prevAutoClearDepth = this.context.renderer.autoClear;
221
+ const prevAutoClearColor = this.context.renderer.autoClearColor;
218
222
  this.context.renderer.autoClear = false;
223
+ this.context.renderer.autoClearColor = false;
219
224
  this.context.renderer.clearDepth();
220
225
  this.onUpdateRenderMode(true);
221
226
  this.handleLayoutUpdates();
@@ -223,7 +228,8 @@ export class Canvas extends UIRootComponent implements ICanvas {
223
228
  // this.handleLayoutUpdates();
224
229
  EventSystem.ensureUpdateMeshUI(ThreeMeshUI, this.context);
225
230
  this.context.renderer.render(this.gameObject, this.context.mainCamera);
226
- this.context.renderer.autoClear = true;
231
+ this.context.renderer.autoClear = prevAutoClearDepth;
232
+ this.context.renderer.autoClearColor = prevAutoClearColor;
227
233
  this.previousParent.add(this.gameObject);
228
234
  }
229
235
  this._lastMatrixWorld?.copy(this.gameObject.matrixWorld);
@@ -127,6 +127,7 @@ export class EventSystem extends Behaviour {
127
127
  MeshUIHelper.resetLastSelected();
128
128
  const opts = new PointerEventData(this.context.input);
129
129
  opts.inputSource = ctrl;
130
+ opts.pointerId = 0;
130
131
  opts.isDown = ctrl.selectionDown;
131
132
  opts.isUp = ctrl.selectionUp;
132
133
  opts.isPressed = ctrl.selectionPressed;
@@ -136,10 +137,11 @@ export class EventSystem extends Behaviour {
136
137
  args.grab = null;
137
138
  };
138
139
  }
139
- this._selectEndFn ??= (ctrl, args: { grab: THREE.Object3D }) => {
140
+ this._selectEndFn ??= (ctrl: WebXRController, args: { grab: THREE.Object3D }) => {
140
141
  if (!args.grab) return;
141
142
  const opts = new PointerEventData(this.context.input);
142
143
  opts.inputSource = ctrl;
144
+ opts.pointerId = 0;
143
145
  opts.isDown = ctrl.selectionDown;
144
146
  opts.isUp = ctrl.selectionUp;
145
147
  opts.isPressed = ctrl.selectionPressed;
@@ -3,7 +3,7 @@ import * as ThreeMeshUI from 'three-mesh-ui'
3
3
  import { RGBAColor } from "../js-extensions/RGBAColor"
4
4
  import { BaseUIComponent } from "./BaseUIComponent";
5
5
  import { serializable } from '../../engine/engine_serialization_decorator';
6
- import { Color, LinearEncoding, sRGBEncoding, Texture } from 'three';
6
+ import { Color, LinearSRGBColorSpace, SRGBColorSpace, Texture } from 'three';
7
7
  import { RectTransform } from './RectTransform';
8
8
  import { onChange, scheduleAction } from "./Utils"
9
9
  import { GameObject } from '../Component';
@@ -191,12 +191,12 @@ export class Graphic extends BaseUIComponent implements IGraphic, IRectTransform
191
191
  this.setOptions({ backgroundOpacity: 0 });
192
192
  if (tex) {
193
193
  // workaround for https://github.com/needle-tools/needle-engine-support/issues/109
194
- if (tex.encoding === sRGBEncoding) {
194
+ if (tex.colorSpace === SRGBColorSpace) {
195
195
  if (Graphic.textureCache.has(tex)) {
196
196
  tex = Graphic.textureCache.get(tex)!;
197
197
  } else {
198
198
  const clone = tex.clone();
199
- clone.encoding = LinearEncoding;
199
+ clone.colorSpace = LinearSRGBColorSpace;
200
200
  Graphic.textureCache.set(tex, clone);
201
201
  tex = clone;
202
202
  }