@combeenation/3d-viewer 4.0.0-beta3 → 4.0.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.
- package/README.md +3 -1
- package/dist/lib-cjs/api/classes/element.d.ts +14 -9
- package/dist/lib-cjs/api/classes/element.js +148 -87
- package/dist/lib-cjs/api/classes/element.js.map +1 -1
- package/dist/lib-cjs/api/classes/event.d.ts +15 -1
- package/dist/lib-cjs/api/classes/event.js +15 -1
- package/dist/lib-cjs/api/classes/event.js.map +1 -1
- package/dist/lib-cjs/api/classes/parameter.d.ts +101 -7
- package/dist/lib-cjs/api/classes/parameter.js +141 -21
- package/dist/lib-cjs/api/classes/parameter.js.map +1 -1
- package/dist/lib-cjs/api/classes/parameterObservable.js +11 -36
- package/dist/lib-cjs/api/classes/parameterObservable.js.map +1 -1
- package/dist/lib-cjs/api/classes/placementAnimation.d.ts +2 -2
- package/dist/lib-cjs/api/classes/placementAnimation.js +11 -0
- package/dist/lib-cjs/api/classes/placementAnimation.js.map +1 -1
- package/dist/lib-cjs/api/classes/variant.d.ts +48 -4
- package/dist/lib-cjs/api/classes/variant.js +320 -46
- package/dist/lib-cjs/api/classes/variant.js.map +1 -1
- package/dist/lib-cjs/api/classes/variantInstance.d.ts +5 -1
- package/dist/lib-cjs/api/classes/variantInstance.js +10 -0
- package/dist/lib-cjs/api/classes/variantInstance.js.map +1 -1
- package/dist/lib-cjs/api/classes/viewer.d.ts +6 -3
- package/dist/lib-cjs/api/classes/viewer.js +140 -59
- package/dist/lib-cjs/api/classes/viewer.js.map +1 -1
- package/dist/lib-cjs/api/internal/sceneSetup.d.ts +5 -1
- package/dist/lib-cjs/api/internal/sceneSetup.js +75 -71
- package/dist/lib-cjs/api/internal/sceneSetup.js.map +1 -1
- package/dist/lib-cjs/api/util/babylonHelper.d.ts +54 -4
- package/dist/lib-cjs/api/util/babylonHelper.js +160 -8
- package/dist/lib-cjs/api/util/babylonHelper.js.map +1 -1
- package/dist/lib-cjs/api/util/globalTypes.d.ts +62 -8
- package/dist/lib-cjs/api/util/resourceHelper.d.ts +13 -8
- package/dist/lib-cjs/api/util/resourceHelper.js +14 -14
- package/dist/lib-cjs/api/util/resourceHelper.js.map +1 -1
- package/dist/lib-cjs/index.d.ts +24 -22
- package/dist/lib-cjs/index.js +42 -38
- package/dist/lib-cjs/index.js.map +1 -1
- package/package.json +5 -5
- package/src/api/classes/element.ts +118 -91
- package/src/api/classes/event.ts +16 -1
- package/src/api/classes/parameter.ts +153 -22
- package/src/api/classes/parameterObservable.ts +9 -31
- package/src/api/classes/{elementParameterizable.ts → parameterizable.ts} +12 -1
- package/src/api/classes/placementAnimation.ts +10 -0
- package/src/api/classes/variant.ts +187 -40
- package/src/api/classes/variantInstance.ts +8 -1
- package/src/api/classes/variantParameterizable.ts +73 -0
- package/src/api/classes/viewer.ts +83 -17
- package/src/api/classes/viewerLight.ts +330 -0
- package/src/api/internal/sceneSetup.ts +99 -109
- package/src/api/util/babylonHelper.ts +173 -10
- package/src/api/util/globalTypes.ts +71 -10
- package/src/api/util/resourceHelper.ts +16 -16
- package/src/api/util/stringHelper.ts +26 -0
- package/src/dev.ts +3 -7
- package/src/index.ts +27 -23
- package/src/pagesconfig.json +4 -0
|
@@ -1,180 +1,171 @@
|
|
|
1
|
-
|
|
1
|
+
import { Camera } from '@babylonjs/core/Cameras/camera';
|
|
2
2
|
import { Engine } from '@babylonjs/core/Engines/engine';
|
|
3
|
-
import '@babylonjs/core/Materials/Textures/Loaders/ddsTextureLoader';
|
|
4
3
|
import '@babylonjs/core/Helpers/sceneHelpers';
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import { Texture } from '@babylonjs/core/Materials/Textures/texture';
|
|
8
|
-
import { Color3, Color4 } from '@babylonjs/core/Maths/math.color';
|
|
4
|
+
import '@babylonjs/core/Materials/Textures/Loaders/ddsTextureLoader';
|
|
5
|
+
import { Color4 } from '@babylonjs/core/Maths/math.color';
|
|
9
6
|
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
7
|
+
import { GroundMesh } from '@babylonjs/core/Meshes/groundMesh';
|
|
10
8
|
import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder';
|
|
11
9
|
import { DefaultRenderingPipeline } from '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline';
|
|
12
10
|
import { Scene } from '@babylonjs/core/scene';
|
|
13
|
-
import
|
|
14
|
-
import { Camera } from '@babylonjs/core/Cameras/camera';
|
|
15
|
-
import { Light } from '@babylonjs/core/Lights/light';
|
|
11
|
+
import { get, isEmpty, set } from 'lodash-es';
|
|
16
12
|
import { Parameter } from '../classes/parameter';
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
14
|
+
/**
|
|
15
|
+
* @param scene
|
|
16
|
+
* @param name
|
|
17
|
+
* @param definition
|
|
18
|
+
*/
|
|
19
|
+
const processGround = async function( scene: Scene, name: string, definition: GroundDefinition ): Promise<Mesh | GroundMesh> {
|
|
20
|
+
return new Promise( resolve => {
|
|
21
|
+
const _resolve = ( ground: Mesh ) => {
|
|
22
|
+
if( definition.receiveShadows !== undefined ) {
|
|
23
|
+
ground.receiveShadows = definition.receiveShadows;
|
|
24
|
+
}
|
|
25
|
+
resolve( ground );
|
|
26
|
+
};
|
|
27
|
+
switch( definition.type ) {
|
|
28
|
+
case 'baked':
|
|
29
|
+
if( !definition.meshId ) {
|
|
30
|
+
throw new Error( `A baked ground must define a "meshId".` );
|
|
31
|
+
}
|
|
32
|
+
_resolve( scene.getMeshByID( definition.meshId ) as Mesh );
|
|
33
|
+
break;
|
|
34
|
+
case 'ground':
|
|
35
|
+
_resolve( MeshBuilder.CreateGround(
|
|
36
|
+
name,
|
|
37
|
+
definition,
|
|
38
|
+
scene
|
|
39
|
+
) );
|
|
40
|
+
break;
|
|
41
|
+
case 'heightmap':
|
|
42
|
+
if( !definition.url ) {
|
|
43
|
+
throw new Error( `A heightmap ground must define an "url".` );
|
|
44
|
+
}
|
|
45
|
+
definition.onReady = ( _ground: GroundMesh ) => {
|
|
46
|
+
_resolve( _ground );
|
|
47
|
+
};
|
|
48
|
+
MeshBuilder.CreateGroundFromHeightMap(
|
|
49
|
+
name,
|
|
50
|
+
definition.url,
|
|
51
|
+
definition,
|
|
52
|
+
scene,
|
|
53
|
+
);
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
throw new Error( `Ground of type "${definition.type}" not implemented (yet).` );
|
|
57
|
+
}
|
|
58
|
+
} );
|
|
50
59
|
};
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
/**
|
|
62
|
+
* @param scene
|
|
63
|
+
*/
|
|
64
|
+
const defaultCamera = async function( scene: Scene ): Promise<Camera> {
|
|
65
|
+
return await processCamera( scene, 'default_camera', {
|
|
56
66
|
type: 'arc',
|
|
57
67
|
active: true,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const defaultCamera = await processCamera(scene, 'default_camera', cameraSetup);
|
|
61
|
-
|
|
62
|
-
return defaultCamera;
|
|
68
|
+
} );
|
|
63
69
|
};
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
/**
|
|
72
|
+
* @param scene
|
|
73
|
+
* @param name
|
|
74
|
+
* @param cameraSetup
|
|
75
|
+
*/
|
|
76
|
+
const processCamera = async function( scene: Scene, name: string, cameraSetup: CameraDefinition ): Promise<Camera> {
|
|
67
77
|
let camera: Camera;
|
|
68
|
-
|
|
69
78
|
let target = Vector3.Zero();
|
|
70
|
-
if(cameraSetup.target) {
|
|
71
|
-
target = Parameter.parseVector(cameraSetup.target);
|
|
79
|
+
if( cameraSetup.target ) {
|
|
80
|
+
target = Parameter.parseVector( cameraSetup.target );
|
|
72
81
|
}
|
|
73
|
-
|
|
74
|
-
switch(cameraSetup.type ) {
|
|
82
|
+
switch( cameraSetup.type ) {
|
|
75
83
|
case 'arc':
|
|
76
84
|
// @ts-ignore
|
|
77
85
|
const arcCameraModule = await import(/* webpackChunkName: "arc-rotate-camera" */ '@babylonjs/core/Cameras/arcRotateCamera');
|
|
78
|
-
camera = new arcCameraModule.ArcRotateCamera(name, Math.PI / 4, Math.PI / 4, 2, target, scene );
|
|
86
|
+
camera = new arcCameraModule.ArcRotateCamera( name, Math.PI / 4, Math.PI / 4, 2, target, scene );
|
|
79
87
|
camera.metadata = {
|
|
80
88
|
alpha: Math.PI / 4,
|
|
81
89
|
beta: Math.PI / 4,
|
|
82
90
|
radius: 2
|
|
83
91
|
};
|
|
84
92
|
break;
|
|
85
|
-
|
|
86
93
|
}
|
|
87
|
-
|
|
88
|
-
if(cameraSetup.active) {
|
|
94
|
+
if( cameraSetup.active ) {
|
|
89
95
|
camera.attachControl( scene.getEngine().getRenderingCanvas()!, true );
|
|
90
96
|
}
|
|
91
|
-
|
|
92
97
|
if( cameraSetup.fov ) {
|
|
93
98
|
camera.fov = cameraSetup.fov;
|
|
94
99
|
}
|
|
95
|
-
|
|
96
100
|
camera.storeState();
|
|
97
101
|
return camera;
|
|
98
102
|
};
|
|
99
103
|
|
|
100
|
-
|
|
104
|
+
/**
|
|
105
|
+
* @param engine
|
|
106
|
+
* @param sceneJson
|
|
107
|
+
*/
|
|
108
|
+
const sceneSetup = async function(engine: Engine, sceneJson: SceneJson): Promise<Scene> {
|
|
101
109
|
const scene = new Scene( engine );
|
|
102
110
|
scene.clearColor = new Color4(0, 0, 0, 0);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if( !
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
cameras.push(camera);
|
|
110
|
-
} else {
|
|
111
|
-
for(let camera in sceneJson.scene.cameras) {
|
|
112
|
-
cameras.push(await processCamera(scene, camera, sceneJson.scene.cameras[camera]));
|
|
111
|
+
// cameras
|
|
112
|
+
const cameras: Camera[] = [];
|
|
113
|
+
const cameraDefinitions = get( sceneJson.scene, 'cameras' ) as CameraDefinitions;
|
|
114
|
+
if( !isEmpty( cameraDefinitions ) ) {
|
|
115
|
+
for( let cameraName in cameraDefinitions ) {
|
|
116
|
+
cameras.push( await processCamera( scene, cameraName, cameraDefinitions[cameraName] ) );
|
|
113
117
|
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
//there is either no "lights" or "lights" is empty
|
|
118
|
-
if( ! sceneJson.scene.hasOwnProperty('lights') || (sceneJson.scene.lights && ! Object.keys(sceneJson.scene.lights).length ) ) {
|
|
119
|
-
// await defaultLightning(scene);
|
|
120
118
|
} else {
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
const camera = await defaultCamera( scene );
|
|
120
|
+
cameras.push( camera );
|
|
121
|
+
}
|
|
122
|
+
// grounds
|
|
123
|
+
const groundDefinitions = get( sceneJson.scene, 'grounds' ) as GroundDefinitions;
|
|
124
|
+
if( !isEmpty( groundDefinitions ) ) {
|
|
125
|
+
for( const groundName in groundDefinitions ) {
|
|
126
|
+
await processGround( scene, groundName, groundDefinitions[groundName] );
|
|
123
127
|
}
|
|
124
128
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
129
|
// TODO: try to split this away from the default rendering pipeline to save module imports
|
|
128
130
|
// The "hdr" setting had negative effect on rendering in Safari. Everything looked a little "edgy". I'm not completely
|
|
129
131
|
// sure if disabling it comes with other negative side effects I don't see right now, so we should probably
|
|
130
132
|
// investigate this a little more in detail at some point.
|
|
131
133
|
const defaultPipeline = new DefaultRenderingPipeline( 'default-rendering-pipeline', false, scene );
|
|
132
|
-
|
|
133
134
|
/* DISABLED: causes problems with Internet Explorer
|
|
134
135
|
defaultPipeline.imageProcessingEnabled = true;
|
|
135
136
|
*/
|
|
136
|
-
|
|
137
137
|
if( sceneJson.scene.globals.aa ) {
|
|
138
138
|
defaultPipeline.fxaaEnabled = true; //implicitly does FxaaPostProcess()
|
|
139
139
|
}
|
|
140
|
-
|
|
141
140
|
// Set samples regardless of fxaa setting since we don't want to use fxaa but still increase the sample count
|
|
142
141
|
defaultPipeline.samples = 8;
|
|
143
|
-
|
|
144
142
|
if( sceneJson.scene.globals['camera-settings'] ) {
|
|
145
|
-
if( sceneJson.scene.globals['camera-settings']
|
|
143
|
+
if( sceneJson.scene.globals['camera-settings']!.sharpen && sceneJson.scene.globals['camera-settings']!.sharpen.enabled ) {
|
|
146
144
|
defaultPipeline.sharpenEnabled = true; //implicitly does SharpenPostProcess()
|
|
147
145
|
//defaultPipeline.sharpen.colorAmount = 1;
|
|
148
146
|
//defaultPipeline.sharpen.edgeAmount = 0;
|
|
149
147
|
}
|
|
150
|
-
|
|
151
|
-
if( sceneJson.scene.globals['camera-settings'].bloom && sceneJson.scene.globals['camera-settings'].bloom.enabled ) {
|
|
148
|
+
if( sceneJson.scene.globals['camera-settings']!.bloom && sceneJson.scene.globals['camera-settings']!.bloom.enabled ) {
|
|
152
149
|
defaultPipeline.bloomEnabled = true;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
defaultPipeline.bloomScale = sceneJson.scene.globals['camera-settings'].bloom.size;
|
|
150
|
+
if( sceneJson.scene.globals['camera-settings']!.bloom.size ) {
|
|
151
|
+
defaultPipeline.bloomScale = sceneJson.scene.globals['camera-settings']!.bloom.size;
|
|
156
152
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
defaultPipeline.bloomThreshold = sceneJson.scene.globals['camera-settings'].bloom.threshold;
|
|
153
|
+
if( sceneJson.scene.globals['camera-settings']!.bloom.threshold ) {
|
|
154
|
+
defaultPipeline.bloomThreshold = sceneJson.scene.globals['camera-settings']!.bloom.threshold;
|
|
160
155
|
}
|
|
161
156
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
scene.imageProcessingConfiguration.contrast = sceneJson.scene.globals['camera-settings'].contrast;
|
|
157
|
+
if( sceneJson.scene.globals['camera-settings']!.contrast ) {
|
|
158
|
+
scene.imageProcessingConfiguration.contrast = sceneJson.scene.globals['camera-settings']!.contrast;
|
|
165
159
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
scene.imageProcessingConfiguration.exposure = sceneJson.scene.globals['camera-settings'].exposure;
|
|
160
|
+
if( sceneJson.scene.globals['camera-settings']!.exposure ) {
|
|
161
|
+
scene.imageProcessingConfiguration.exposure = sceneJson.scene.globals['camera-settings']!.exposure;
|
|
169
162
|
}
|
|
170
|
-
|
|
171
|
-
if( sceneJson.scene.globals['camera-settings'].dof && sceneJson.scene.globals['camera-settings'].dof.enabled ) {
|
|
163
|
+
if( sceneJson.scene.globals['camera-settings']!.dof && sceneJson.scene.globals['camera-settings']!.dof.enabled ) {
|
|
172
164
|
//@ts-ignore
|
|
173
165
|
const module = await import(/* webpackChunkName: "lens-rendering" */ './lensRendering');
|
|
174
|
-
new module.LensRenderingPipeline( 'lens-rendering', sceneJson.scene.globals['camera-settings'].
|
|
166
|
+
new module.LensRenderingPipeline( 'lens-rendering', sceneJson.scene.globals['camera-settings']!.dof.settings, scene, 1.0, cameras );
|
|
175
167
|
}
|
|
176
168
|
}
|
|
177
|
-
|
|
178
169
|
// TODO: make this dynamic
|
|
179
170
|
/*
|
|
180
171
|
const texture = new HDRCubeTexture("/assets/small_cave_1k.hdr", scene, 256);
|
|
@@ -195,10 +186,9 @@ const sceneSetup = async function(engine: Engine, sceneJson: SceneJson) {
|
|
|
195
186
|
*/
|
|
196
187
|
|
|
197
188
|
// TODO: shadows don't work with HemishpericLight
|
|
198
|
-
|
|
199
189
|
return scene;
|
|
200
190
|
};
|
|
201
191
|
|
|
202
192
|
export {
|
|
203
193
|
sceneSetup
|
|
204
|
-
}
|
|
194
|
+
};
|
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
import { HighlightLayer } from '@babylonjs/core/Layers/highlightLayer';
|
|
2
|
+
import { Light } from '@babylonjs/core/Lights/light';
|
|
3
|
+
import { ShadowGenerator } from '@babylonjs/core/Lights/Shadows/shadowGenerator';
|
|
2
4
|
import { Material } from '@babylonjs/core/Materials/material';
|
|
3
5
|
import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
|
|
4
6
|
import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
|
|
7
|
+
import { Axis } from '@babylonjs/core/Maths/math.axis';
|
|
5
8
|
import { Color3 } from '@babylonjs/core/Maths/math.color';
|
|
6
|
-
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
9
|
+
import { Quaternion, Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
7
10
|
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
|
|
8
11
|
import { InstancedMesh } from '@babylonjs/core/Meshes/instancedMesh';
|
|
9
12
|
import { Mesh } from '@babylonjs/core/Meshes/mesh';
|
|
10
13
|
import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
|
|
11
14
|
import { Node } from '@babylonjs/core/node';
|
|
12
15
|
import { Scene } from '@babylonjs/core/scene';
|
|
13
|
-
import {
|
|
16
|
+
import { Nullable } from '@babylonjs/core/types';
|
|
17
|
+
import { cloneDeep, get, has, merge } from 'lodash-es';
|
|
14
18
|
import { DottedPath } from '../classes/dottedPath';
|
|
15
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @param node
|
|
22
|
+
* @return Node
|
|
23
|
+
*/
|
|
24
|
+
const getRootNode = function( node: Node ): Node {
|
|
25
|
+
let _node = node;
|
|
26
|
+
while( _node.parent ) {
|
|
27
|
+
_node = _node.parent;
|
|
28
|
+
}
|
|
29
|
+
return _node;
|
|
30
|
+
}
|
|
31
|
+
|
|
16
32
|
/**
|
|
17
33
|
* @param nodes
|
|
18
34
|
* @param predicate
|
|
@@ -39,18 +55,17 @@ const mapToDottedNodes = function <T>( nodes: Node[],
|
|
|
39
55
|
* @param node
|
|
40
56
|
* @return DottedPath
|
|
41
57
|
*/
|
|
42
|
-
const
|
|
58
|
+
const getDottedPathForNode = function( node: Node ): DottedPath {
|
|
43
59
|
const dottedPath = DottedPath.create( node.name );
|
|
44
60
|
let _parent = node;
|
|
45
61
|
while( _parent.parent ) {
|
|
46
|
-
_parent = _parent.parent
|
|
62
|
+
_parent = _parent.parent;
|
|
47
63
|
dottedPath.unshiftPart( _parent.name );
|
|
48
64
|
}
|
|
49
65
|
return dottedPath;
|
|
50
66
|
};
|
|
51
67
|
|
|
52
68
|
/**
|
|
53
|
-
*
|
|
54
69
|
* @param node
|
|
55
70
|
* @param predicate
|
|
56
71
|
* @param deep
|
|
@@ -78,6 +93,21 @@ const cloneTransformNode = function( node: TransformNode,
|
|
|
78
93
|
return clone;
|
|
79
94
|
};
|
|
80
95
|
|
|
96
|
+
/**
|
|
97
|
+
* @param node
|
|
98
|
+
*/
|
|
99
|
+
const cloneNodeWithParents = function( node: Node | null ): Node | null {
|
|
100
|
+
let clone = null;
|
|
101
|
+
if( node instanceof TransformNode ) {
|
|
102
|
+
clone = node.clone( node.name, cloneNodeWithParents( node.parent ) as Nullable<Node>, true );
|
|
103
|
+
} else if( node instanceof Light ) {
|
|
104
|
+
clone = node.clone( node.name, cloneNodeWithParents( node.parent ) as Nullable<Node> );
|
|
105
|
+
} else if( node ) {
|
|
106
|
+
throw new Error( `Cloning of "${node?.constructor.name}" is not implemented (yet).` );
|
|
107
|
+
}
|
|
108
|
+
return clone;
|
|
109
|
+
};
|
|
110
|
+
|
|
81
111
|
/**
|
|
82
112
|
* @param node
|
|
83
113
|
* @param deep
|
|
@@ -106,11 +136,11 @@ const cloneTransformNodeMaterial = function( node: TransformNode,
|
|
|
106
136
|
* @param deep
|
|
107
137
|
* @param metadata
|
|
108
138
|
*/
|
|
109
|
-
const
|
|
139
|
+
const injectNodeMetadata = function( node: Node, metadata: {}, deep: boolean = true ) {
|
|
110
140
|
node.metadata = merge( {}, node.metadata, metadata );
|
|
111
|
-
if( deep ) {
|
|
141
|
+
if( deep && node instanceof TransformNode ) {
|
|
112
142
|
const children = node.getChildTransformNodes( true );
|
|
113
|
-
children.forEach( child =>
|
|
143
|
+
children.forEach( child => injectNodeMetadata( child, metadata, deep ) );
|
|
114
144
|
}
|
|
115
145
|
};
|
|
116
146
|
|
|
@@ -165,6 +195,80 @@ const deactivateTransformNode = function( node: TransformNode, deep: boolean = t
|
|
|
165
195
|
}
|
|
166
196
|
};
|
|
167
197
|
|
|
198
|
+
/**
|
|
199
|
+
* @param node
|
|
200
|
+
*/
|
|
201
|
+
const enableNodeWithParents = function( node: Node ) {
|
|
202
|
+
node.setEnabled( true );
|
|
203
|
+
if ( node.parent ) {
|
|
204
|
+
enableNodeWithParents( node.parent );
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @param node
|
|
210
|
+
*/
|
|
211
|
+
const disableNodeWithParents = function( node: Node ) {
|
|
212
|
+
node.setEnabled( false );
|
|
213
|
+
if ( node.parent ) {
|
|
214
|
+
disableNodeWithParents( node.parent );
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Attention: this function mutates the position of a node. Keep in mind that there are dependencies to other
|
|
220
|
+
* functions moving nodes around.
|
|
221
|
+
* @param node
|
|
222
|
+
* @param rotation
|
|
223
|
+
*/
|
|
224
|
+
const rotateTransformNode = function( node: TransformNode, rotation: Vector3 ): TransformNode {
|
|
225
|
+
// remember absolute rotation and reset it before translating
|
|
226
|
+
if( !has( node.metadata, 'rotation.initial' ) ) {
|
|
227
|
+
let rotationQuaternion = node.rotationQuaternion;
|
|
228
|
+
if( !rotationQuaternion ) {
|
|
229
|
+
rotationQuaternion = Quaternion.RotationYawPitchRoll( node.rotation.x, node.rotation.y, node.rotation.z );
|
|
230
|
+
}
|
|
231
|
+
injectNodeMetadata( node, { 'rotation.initial': rotationQuaternion.asArray() }, false );
|
|
232
|
+
}
|
|
233
|
+
if( !has( node.metadata, 'rotation.position' ) || get( node.metadata, 'position.dirty' ) ) {
|
|
234
|
+
let rotationPosition = node.absolutePosition.clone();
|
|
235
|
+
if( has( node.metadata, 'rotation.offset' ) ) {
|
|
236
|
+
rotationPosition = rotationPosition.subtract( get( node.metadata, 'rotation.offset' ) as Vector3 );
|
|
237
|
+
}
|
|
238
|
+
injectNodeMetadata( node, { 'rotation.position': rotationPosition }, false );
|
|
239
|
+
injectNodeMetadata( node, { 'position.dirty': false }, false );
|
|
240
|
+
}
|
|
241
|
+
node.setAbsolutePosition( get( node.metadata, 'rotation.position' ) );
|
|
242
|
+
node.rotationQuaternion = Quaternion.FromArray( get( node.metadata, 'rotation.initial' ) as [] );
|
|
243
|
+
node.rotateAround( Vector3.Zero(), Axis.X, rotation.x );
|
|
244
|
+
node.rotateAround( Vector3.Zero(), Axis.Y, rotation.y );
|
|
245
|
+
node.rotateAround( Vector3.Zero(), Axis.Z, rotation.z );
|
|
246
|
+
node.computeWorldMatrix( true );
|
|
247
|
+
const rotationOffset = node.absolutePosition.subtract( get( node.metadata, 'rotation.position' ) as Vector3 );
|
|
248
|
+
injectNodeMetadata( node, { 'rotation.offset': rotationOffset }, false );
|
|
249
|
+
return node;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Attention: this function mutates the position of a node. Keep in mind that there are dependencies to other
|
|
254
|
+
* functions moving nodes around.
|
|
255
|
+
* @param node
|
|
256
|
+
* @param distance
|
|
257
|
+
*/
|
|
258
|
+
const moveTransformNode = function( node: TransformNode, distance: Vector3 ): TransformNode {
|
|
259
|
+
// remember absolute position and reset it before translating
|
|
260
|
+
if( !has( node.metadata, 'position.initial' ) ) {
|
|
261
|
+
injectNodeMetadata( node, { 'position.initial': node.absolutePosition.clone() }, false );
|
|
262
|
+
}
|
|
263
|
+
let position = get( node.metadata, 'position.initial' ) as Vector3;
|
|
264
|
+
if( has( node.metadata, 'rotation.offset' ) ) {
|
|
265
|
+
position = position.add( get( node.metadata, 'rotation.offset' ) as Vector3 );
|
|
266
|
+
}
|
|
267
|
+
node.setAbsolutePosition( position.add( distance ) );
|
|
268
|
+
injectNodeMetadata( node, { 'position.dirty': true }, false );
|
|
269
|
+
return node;
|
|
270
|
+
};
|
|
271
|
+
|
|
168
272
|
/**
|
|
169
273
|
* @param node
|
|
170
274
|
* @param material
|
|
@@ -335,6 +439,56 @@ const removeFromHighlightLayer = function( layer: HighlightLayer, node: Transfor
|
|
|
335
439
|
}
|
|
336
440
|
};
|
|
337
441
|
|
|
442
|
+
/**
|
|
443
|
+
* @param node
|
|
444
|
+
* @param receiveShadows
|
|
445
|
+
* @param deep
|
|
446
|
+
*/
|
|
447
|
+
const setReceiveShadows = function( node: TransformNode, receiveShadows: boolean, deep: boolean = true ) {
|
|
448
|
+
if( node instanceof AbstractMesh ) {
|
|
449
|
+
node.receiveShadows = receiveShadows;
|
|
450
|
+
}
|
|
451
|
+
if( deep ) {
|
|
452
|
+
node.getChildTransformNodes( true ).forEach(
|
|
453
|
+
child => setReceiveShadows( child, receiveShadows, deep )
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* @param node
|
|
460
|
+
* @param generator
|
|
461
|
+
* @param deep
|
|
462
|
+
*/
|
|
463
|
+
const addToShadowGenerator = function( generator: ShadowGenerator, node: TransformNode, deep: boolean = true ) {
|
|
464
|
+
if( node instanceof AbstractMesh ) {
|
|
465
|
+
// We have to remove the node because there's no duplicate check in babylon
|
|
466
|
+
generator.removeShadowCaster( node, false );
|
|
467
|
+
generator.addShadowCaster( node, false );
|
|
468
|
+
}
|
|
469
|
+
if( deep ) {
|
|
470
|
+
node.getChildTransformNodes( true ).forEach(
|
|
471
|
+
child => addToShadowGenerator( generator, child, deep )
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* @param node
|
|
478
|
+
* @param generator
|
|
479
|
+
* @param deep
|
|
480
|
+
*/
|
|
481
|
+
const removeFromShadowGenerator = function( generator: ShadowGenerator, node: TransformNode, deep: boolean = true ) {
|
|
482
|
+
if( node instanceof AbstractMesh ) {
|
|
483
|
+
generator.removeShadowCaster( node, false );
|
|
484
|
+
}
|
|
485
|
+
if( deep ) {
|
|
486
|
+
node.getChildTransformNodes( true ).forEach(
|
|
487
|
+
child => removeFromShadowGenerator( generator, child, deep )
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
|
|
338
492
|
/**
|
|
339
493
|
* https://forum.babylonjs.com/t/get-mesh-bounding-box-position-and-size-in-2d-screen-coordinates/1058/3
|
|
340
494
|
* @param mesh
|
|
@@ -372,14 +526,20 @@ const getClientRectFromMesh = function( mesh: AbstractMesh, scene: Scene, canvas
|
|
|
372
526
|
};
|
|
373
527
|
|
|
374
528
|
export {
|
|
529
|
+
getRootNode,
|
|
375
530
|
mapToDottedNodes,
|
|
376
|
-
|
|
531
|
+
getDottedPathForNode,
|
|
377
532
|
cloneTransformNode,
|
|
533
|
+
cloneNodeWithParents,
|
|
378
534
|
cloneTransformNodeMaterial,
|
|
379
|
-
|
|
535
|
+
injectNodeMetadata,
|
|
380
536
|
assertTransformNode,
|
|
381
537
|
activateTransformNode,
|
|
382
538
|
deactivateTransformNode,
|
|
539
|
+
enableNodeWithParents,
|
|
540
|
+
disableNodeWithParents,
|
|
541
|
+
rotateTransformNode,
|
|
542
|
+
moveTransformNode,
|
|
383
543
|
setMaterial,
|
|
384
544
|
setSourceNodeMaterial,
|
|
385
545
|
setMaterialColor,
|
|
@@ -388,5 +548,8 @@ export {
|
|
|
388
548
|
setMaterialRoughness,
|
|
389
549
|
addToHighlightLayer,
|
|
390
550
|
removeFromHighlightLayer,
|
|
551
|
+
setReceiveShadows,
|
|
552
|
+
addToShadowGenerator,
|
|
553
|
+
removeFromShadowGenerator,
|
|
391
554
|
getClientRectFromMesh
|
|
392
555
|
};
|