Files
scaenae/js/scene.js

152 lines
4.4 KiB
JavaScript

// 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;
}