// Global ATON import AppState from "./state.js"; import { config } from "../config.js"; import { toggleAmbientOcclusion } from "./utils/environment.js"; /** * @module Scene */ /** * @todo Experimental... * @param {THREE.Object3D} object - A THREE Object3D instance */ function showEdges (object) { const edgeMaterial = new THREE.LineBasicMaterial( { color: 0x000000 } ); object.traverse(function(child) { if (child.isMesh) { let edges = new THREE.EdgesGeometry(child.geometry, 45); let line = new THREE.LineSegments(edges, edgeMaterial); child.add(line); console.log(child); } }); } function init () { ATON.realize(); ATON.UI.addBasicEvents(); ATON.UI.init(); // All assets for this app are stored here ATON.setPathCollection('/a/scaenae/assets/'); // Initial light direction ATON.setMainLightDirection(new THREE.Vector3(...config.scene.initLightDir)); ATON.toggleShadows(config.scene.shadows); ATON.setExposure(config.scene.initialExposure); AppState.camera = ATON.Nav._camera; AppState.renderer = ATON._renderer; AppState.shadows = config.scene.shadows; AppState.lightDirection = ATON.getMainLightDirection(); AppState.exposure = config.scene.initialExposure; ATON.Nav.setUserControl(true); // Avoid semantic occlusion ATON._bQuerySemOcclusion = false; } /** * @param {Object} marker - The marker object from config * @param {Object[]} nodes - The flat list of nodes for this scene */ export function openScene (marker, nodes) { init(); // Filter nodes with models first nodes = nodes.filter(n => n.model); // Load 3D models and create nodes loadNodes(nodes); ATON.setMainPanorama(marker.pano); // TODO: hardcoded... AppState.initialRotation = new THREE.Vector3(...config.scene.initRotation); ATON.setAutoLP(config.scene.autoLP); AppState.lightProbe = config.scene.autoLP; toggleAmbientOcclusion(config.scene.ambientOcclusion); AppState.ambientOcclusion = config.scene.ambientOcclusion; AppState.root = ATON.getRootScene(); } /** * * @param {Object[]} nodes */ function loadNodes(nodes) { nodes.forEach(n => { let node = ATON.createSceneNode(n.label); node.load(n.model); node.setRotation(...config.scene.initRotation); /* node.setMaterial(new THREE.MeshPhongMaterial({ transparent: false, color: n.color ?? '#fff', })); */ // Apply any transparency before attaching to scene if (n.opacity !== undefined && n.opacity !== null) { node.setMaterial(new THREE.MeshPhongMaterial({ transparent: true, opacity: n.opacity, color: '#fff' })); } // Disable a node for picking (shadows, light probe etc.) if (n.isInvisible) node.hide(); node.attachToRoot(); if (n.isMain) { AppState.mainNodeId = n.label; // ATON.Node.getBound() returns a THREE.Sphere object AppState.clipping.boundingSphere = node.getBound(); } if (n.isSemantic) { createSemanticNode(n.model, n.label); AppState.semanticNodes.set(n.label, n.content); //ATON.getSemanticRoot().attach(semNode); } AppState.nodes.push({ id: n.label, active: n.isInvisible ? false: true, isSemantic: n.isSemantic }); }); if (!AppState.clipping.boundingSphere) { console.error("No bounding sphere computed, clipping will fail. Ensure one node has 'isMain: true'."); } } /** * Creates a semantic annotation from a model * @param {string} model The model's path to load * @param {string} id The original scene node ID (3D object) * @returns {ATON.SceneNode} */ function createSemanticNode(model, id) { // Default/highlight materials for semantic node let matSemDef = new THREE.MeshPhongMaterial({ color: '#ecee66', transparent: true, opacity: 0.3, }); let matSemHL = ATON.MatHub.materials.semanticShapeHL; const semNode = ATON.createSemanticNode(id) .setCloneOnLoadHit(false) .load(model) .setDefaultAndHighlightMaterials(matSemDef, matSemHL) .attachToRoot(); semNode.setRotation(...config.scene.initRotation); return semNode; }