nanogl-gltf
Version:
118 lines (117 loc) • 4.76 kB
JavaScript
import NGLNode from 'nanogl-node';
import { mat4 } from 'gl-matrix';
import GltfTypes from '../types/GltfTypes';
import MeshRenderer from '../renderer/MeshRenderer';
/**
* The Node element is a node in the scene graph, it contains a transformation matrix or a translation/scale vectors & scale quaternion, and can be used to control a camera, a skin, a mesh, or children nodes.
*/
export default class Node extends NGLNode {
constructor() {
super(...arguments);
this.gltftype = GltfTypes.NODE;
/**
* If the node is used to control a mesh with morph targets, this is the weights array
*/
this.weights = null;
/**
* The initial transform of this node as defined in the gltf file
*/
this.restMatrix = mat4.create();
}
/**
* Parse the Node data, apply the transformation matrix or the translation/scale vectors & scale quaternion,
* link the camera, skin and mesh elements and weights array if needed, and add children nodes to this node.
*
* Is async as it needs to wait for all possible Camera, Skin, Mesh and children Nodes elements to be created.
* @param gltfLoader GLTFLoader to use
* @param data Data to parse
*/
async parse(gltfLoader, data) {
var _a, _b;
// super.parse();
// this.uuid = data.uuid;
// this.elementIndex = data.elementIndex;
// this.gltf = gltfLoader.gltf;
this.extras = data.extras;
// this.extensions = data.extensions
if (data.camera !== undefined)
this.camera = await gltfLoader.getElement(GltfTypes.CAMERA, data.camera);
if (data.matrix !== undefined)
this.setMatrix(new Float32Array(data.matrix));
if (data.scale !== undefined)
this.scale.set(data.scale);
if (data.translation !== undefined)
this.position.set(data.translation);
if (data.rotation !== undefined)
this.rotation.set(data.rotation);
if (data.children !== undefined) {
const childPromises = data.children.map((index) => gltfLoader.getElement(GltfTypes.NODE, index));
const children = await Promise.all(childPromises);
for (const child of children) {
this.add(child);
}
}
if (data.skin !== undefined) {
this.skin = await gltfLoader.getElement(GltfTypes.SKIN, data.skin);
}
if (data.mesh !== undefined) {
this.mesh = await gltfLoader.getElement(GltfTypes.MESH, data.mesh);
const targets = this.mesh.primitives[0].targets;
if (targets) {
this.weights = new Float32Array(targets.length);
}
}
if (data.weights !== undefined) {
if (this.weights === null || this.weights.length !== data.weights.length) {
throw new Error("morph weights on node doesn't match mesh targets");
}
this.weights.set(data.weights);
}
this.name = (_a = data.name) !== null && _a !== void 0 ? _a : ((_b = this.mesh) === null || _b === void 0 ? void 0 : _b.name);
this.invalidate();
this.updateMatrix();
this.restMatrix.set(this._matrix);
}
/**
* Find a child Node by name.
*
* It will search only at the first level of children, not recursively. If you want to search recursively, use findDescendant.
* @param name Name of the child Node to find
*/
findChild(name) {
for (let i = 0; i < this._children.length; i++) {
const child = this._children[i];
if (child.name === name)
return child;
}
return undefined;
}
/**
* Find a descendant Node by name.
*
* It will search recursively in all levels of the children nodes.
* @param name Name of the descendant Node to find
*/
findDescendant(name) {
var _a;
let res = this.findChild(name);
if (res === undefined) {
for (let i = 0; i < this._children.length; i++) {
const child = this._children[i];
res = (_a = child.findDescendant) === null || _a === void 0 ? void 0 : _a.call(child, name);
if (res !== undefined)
return res;
}
}
return res;
}
/**
* If the Node has a Mesh, creates a MeshRenderer and stores it to the renderable attribute, getting the Node ready to be rendered.
* @param gltf The Gltf object which this Node belongs to
*/
allocateGl(gltf) {
if (this.mesh) {
this.renderable = new MeshRenderer(gltf, this);
}
}
}