Переглянути джерело

Camera beaviors and lights (alpha) configuration

Raanan Weber 7 роки тому
батько
коміт
1f7c5b32dd

+ 2 - 1
Viewer/package.json

@@ -4,6 +4,7 @@
     "description": "A viewer using BabylonJS to display 3D elements natively",
     "scripts": {
         "start:server": "webpack-dev-server",
+        "build": "webpack",
         "test": "echo \"Error: no test specified\" && exit 1"
     },
     "repository": {
@@ -44,4 +45,4 @@
         "lodash.merge": "^4.6.0",
         "promise-polyfill": "^6.0.2"
     }
-}
+}

+ 7 - 5
Viewer/src/configuration/configuration.ts

@@ -27,11 +27,12 @@ export interface ViewerConfiguration {
     canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
 
     model?: {
-        url: string;
-        loader: string; // obj, gltf?
+        url?: string;
+        loader?: string; // obj, gltf?
         position?: { x: number, y: number, z: number };
         rotation?: { x: number, y: number, z: number, w: number };
         scaling?: { x: number, y: number, z: number };
+        parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
     } | string,
     scene?: {
         autoRotate?: boolean;
@@ -47,13 +48,14 @@ export interface ViewerConfiguration {
         fieldOfView?: number;
         minZ?: number;
         maxZ?: number;
-        behavior?: {
+        behaviors?: Array<number | {
             type?: number;
             [propName: string]: any;
-        }
+        }>
     },
     lights?: Array<{
-        type?: number;
+        type: number;
+        name?: string;
         [propName: string]: any;
     }>
     // engine configuration. optional!

+ 116 - 24
Viewer/src/viewer/defaultViewer.ts

@@ -1,6 +1,7 @@
 import { Template } from './../templateManager';
 import { AbstractViewer } from './viewer';
-import { Observable, Engine, Scene, AbstractMesh, StandardMaterial, ShadowOnlyMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
+import { Observable, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ShadowOnlyMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
+import { CameraBehavior } from '../interfaces';
 
 // A small hack for the inspector. to be removed!
 import * as BABYLON from 'babylonjs';
@@ -8,6 +9,8 @@ window['BABYLON'] = BABYLON;
 
 export class DefaultViewer extends AbstractViewer {
 
+    private camera: ArcRotateCamera;
+
     protected onTemplatesLoaded() {
 
         this.showLoadingScreen();
@@ -43,23 +46,19 @@ export class DefaultViewer extends AbstractViewer {
 
         // recreate the camera
         this.scene.createDefaultCameraOrLight(true, true, true);
+        this.camera = <ArcRotateCamera>this.scene.activeCamera;
+
+        meshes[0].rotation.y += Math.PI;
 
-        // TODO do it better, no casting!
-        let camera: ArcRotateCamera = <ArcRotateCamera>this.scene.activeCamera;
-        // We want framing to move the camera at the best spot
-        camera.useFramingBehavior = true;
-        camera.useAutoRotationBehavior = true;
+        this.setupCamera(meshes);
 
         // Get the bounding vectors of the mesh hierarchy (meshes[0] = root node in gltf)
-        meshes[0].rotation.y += Math.PI;
-        let bounding = meshes[0].getHierarchyBoundingVectors();
-        camera.framingBehavior.zoomOnBoundingInfo(bounding.min, bounding.max);
 
         // Remove default light and create a new one to have a dynamic shadow                            
-        this.scene.lights[0].dispose();
-        var light = new BABYLON.DirectionalLight('light', new BABYLON.Vector3(-0.2, -1, 0), this.scene)
-        light.position = new BABYLON.Vector3(bounding.max.x * 0.2, bounding.max.y * 2, 0)
-        light.intensity = 4.5;
+        //this.scene.lights[0].dispose();
+        //var light = new BABYLON.DirectionalLight('light', new BABYLON.Vector3(-0.2, -1, 0), this.scene)
+        //light.position = new BABYLON.Vector3(bounding.max.x * 0.2, bounding.max.y * 2, 0)
+        //light.intensity = 4.5;
 
         // TODO - move it away from here.
 
@@ -69,17 +68,6 @@ export class DefaultViewer extends AbstractViewer {
         ground.material = new ShadowOnlyMaterial('shadow-only-mat', this.scene)
         ground.material.alpha = 0.4;
 
-        var shadowGenerator = new BABYLON.ShadowGenerator(512, light)
-        shadowGenerator.useBlurExponentialShadowMap = true;
-        shadowGenerator.useKernelBlur = true;
-        shadowGenerator.blurKernel = 64;
-        shadowGenerator.blurScale = 4;
-
-        // Add the bus in the casters
-        for (var index = 0; index < meshes.length; index++) {
-            shadowGenerator.getShadowMap().renderList.push(meshes[index]);
-        }
-
         return Promise.resolve(this.scene);
     }
 
@@ -147,4 +135,108 @@ export class DefaultViewer extends AbstractViewer {
             return Promise.resolve(template);
         }));
     }
+
+    private setupLights(focusMeshes: Array<AbstractMesh> = []) {
+        if (!this.configuration.scene.defaultLight && (this.configuration.lights && this.configuration.lights.length)) {
+            // remove old lights
+            this.scene.lights.forEach(l => {
+                l.dispose();
+            });
+
+            this.configuration.lights.forEach((lightConfig, idx) => {
+                lightConfig.name = lightConfig.name || 'light-' + idx;
+
+                //let light = Light.Parse(lightConfig, this.scene);
+
+                /*
+                // TODO fix the shadow mechanism
+                var shadowGenerator = new BABYLON.ShadowGenerator(512, light)
+                shadowGenerator.useBlurExponentialShadowMap = true;
+                shadowGenerator.useKernelBlur = true;
+                shadowGenerator.blurKernel = 64;
+                shadowGenerator.blurScale = 4;
+                
+        
+                // Add the bus in the casters
+                for (var index = 0; index < focusMeshes.length; index++) {
+                    shadowGenerator.getShadowMap().renderList.push(focusMeshes[index]);
+                }
+
+                */
+            });
+        }
+    }
+
+    private setupCamera(focusMeshes: Array<AbstractMesh> = []) {
+        if (this.configuration.scene.defaultCamera) {
+            return;
+        }
+
+        let cameraConfig = this.configuration.camera || {};
+
+        if (cameraConfig.position) {
+            this.camera.position.copyFromFloats(cameraConfig.position.x || 0, cameraConfig.position.y || 0, cameraConfig.position.z || 0);
+        }
+
+        if (cameraConfig.rotation) {
+            this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
+        }
+
+        this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
+        this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
+
+        if (cameraConfig.behaviors) {
+            cameraConfig.behaviors.forEach((behaviorConfig) => {
+
+            });
+        };
+
+        if (this.configuration.scene.autoRotate) {
+            this.camera.useAutoRotationBehavior = true;
+        }
+    }
+
+    private setCameraBehavior(behaviorConfig: {
+        type: number;
+        [propName: string]: any;
+    }, payload: any) {
+
+
+
+        let behavior: Behavior<ArcRotateCamera>;
+        let type = (typeof behaviorConfig !== "object") ? behaviorConfig : behaviorConfig.type;
+
+        switch (type) {
+            case CameraBehavior.AUTOROTATION:
+                behavior = new AutoRotationBehavior();
+                break;
+            case CameraBehavior.BOUNCING:
+                behavior = new BouncingBehavior();
+                break;
+            case CameraBehavior.FRAMING:
+                behavior = new FramingBehavior();
+                if (behaviorConfig.zoomOnBoundingInfo) {
+                    //payload is an array of meshes
+                    let meshes = <Array<AbstractMesh>>payload;
+                    let bounding = meshes[0].getHierarchyBoundingVectors();
+                    (<FramingBehavior>behavior).zoomOnBoundingInfo(bounding.min, bounding.max);
+                }
+                break;
+        }
+
+        if (behavior) {
+            if (typeof behaviorConfig === "object") {
+                this.extendClassWithConfig(behavior, behaviorConfig);
+            }
+            this.camera.addBehavior(behavior);
+        }
+    }
+
+    private extendClassWithConfig(object: any, config: any) {
+        Object.keys(config).forEach(key => {
+            if (object.hasOwnProperty(key)) {
+                object[key] = config[key];
+            }
+        })
+    }
 }