UNPKG

cione-comp-lib

Version:

`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`

367 lines (366 loc) 10.9 kB
import Base from "./core/Base.mjs"; import Vector3 from "./math/Vector3.mjs"; import Quaternion from "./math/Quaternion.mjs"; import Matrix4 from "./math/Matrix4.mjs"; import mat4 from "./glmatrix/mat4.mjs"; import BoundingBox from "./math/BoundingBox.mjs"; var nameId = 0; var Node = Base.extend( { name: "", position: null, rotation: null, scale: null, worldTransform: null, localTransform: null, autoUpdateLocalTransform: true, _parent: null, _scene: null, _needsUpdateWorldTransform: true, _inIterating: false, __depth: 0 }, function() { if (!this.name) { this.name = (this.type || "NODE") + "_" + nameId++; } if (!this.position) { this.position = new Vector3(); } if (!this.rotation) { this.rotation = new Quaternion(); } if (!this.scale) { this.scale = new Vector3(1, 1, 1); } this.worldTransform = new Matrix4(); this.localTransform = new Matrix4(); this._children = []; }, { target: null, invisible: false, isSkinnedMesh: function() { return false; }, isRenderable: function() { return false; }, setName: function(name) { var scene = this._scene; if (scene) { var nodeRepository = scene._nodeRepository; delete nodeRepository[this.name]; nodeRepository[name] = this; } this.name = name; }, add: function(node) { var originalParent = node._parent; if (originalParent === this) { return; } if (originalParent) { originalParent.remove(node); } node._parent = this; this._children.push(node); var scene = this._scene; if (scene && scene !== node.scene) { node.traverse(this._addSelfToScene, this); } node._needsUpdateWorldTransform = true; }, remove: function(node) { var children = this._children; var idx = children.indexOf(node); if (idx < 0) { return; } children.splice(idx, 1); node._parent = null; if (this._scene) { node.traverse(this._removeSelfFromScene, this); } }, removeAll: function() { var children = this._children; for (var idx = 0; idx < children.length; idx++) { children[idx]._parent = null; if (this._scene) { children[idx].traverse(this._removeSelfFromScene, this); } } this._children = []; }, getScene: function() { return this._scene; }, getParent: function() { return this._parent; }, _removeSelfFromScene: function(descendant) { descendant._scene.removeFromScene(descendant); descendant._scene = null; }, _addSelfToScene: function(descendant) { this._scene.addToScene(descendant); descendant._scene = this._scene; }, isAncestor: function(node) { var parent = node._parent; while (parent) { if (parent === this) { return true; } parent = parent._parent; } return false; }, children: function() { return this._children.slice(); }, childAt: function(idx) { return this._children[idx]; }, getChildByName: function(name) { var children = this._children; for (var i = 0; i < children.length; i++) { if (children[i].name === name) { return children[i]; } } }, getDescendantByName: function(name) { var children = this._children; for (var i = 0; i < children.length; i++) { var child = children[i]; if (child.name === name) { return child; } else { var res = child.getDescendantByName(name); if (res) { return res; } } } }, queryNode: function(path) { if (!path) { return; } var pathArr = path.split("/"); var current = this; for (var i = 0; i < pathArr.length; i++) { var name = pathArr[i]; if (!name) { continue; } var found = false; var children = current._children; for (var j = 0; j < children.length; j++) { var child = children[j]; if (child.name === name) { current = child; found = true; break; } } if (!found) { return; } } return current; }, getPath: function(rootNode) { if (!this._parent) { return "/"; } var current = this._parent; var path = this.name; while (current._parent) { path = current.name + "/" + path; if (current._parent == rootNode) { break; } current = current._parent; } if (!current._parent && rootNode) { return null; } return path; }, traverse: function(callback, context) { callback.call(context, this); var _children = this._children; for (var i = 0, len = _children.length; i < len; i++) { _children[i].traverse(callback, context); } }, eachChild: function(callback, context) { var _children = this._children; for (var i = 0, len = _children.length; i < len; i++) { var child = _children[i]; callback.call(context, child, i); } }, setLocalTransform: function(matrix) { mat4.copy(this.localTransform.array, matrix.array); this.decomposeLocalTransform(); }, decomposeLocalTransform: function(keepScale) { var scale = !keepScale ? this.scale : null; this.localTransform.decomposeMatrix(scale, this.rotation, this.position); }, setWorldTransform: function(matrix) { mat4.copy(this.worldTransform.array, matrix.array); this.decomposeWorldTransform(); }, decomposeWorldTransform: function() { var tmp = mat4.create(); return function(keepScale) { var localTransform = this.localTransform; var worldTransform = this.worldTransform; if (this._parent) { mat4.invert(tmp, this._parent.worldTransform.array); mat4.multiply(localTransform.array, tmp, worldTransform.array); } else { mat4.copy(localTransform.array, worldTransform.array); } var scale = !keepScale ? this.scale : null; localTransform.decomposeMatrix(scale, this.rotation, this.position); }; }(), transformNeedsUpdate: function() { return this.position._dirty || this.rotation._dirty || this.scale._dirty; }, updateLocalTransform: function() { var position = this.position; var rotation = this.rotation; var scale = this.scale; if (this.transformNeedsUpdate()) { var m = this.localTransform.array; mat4.fromRotationTranslation(m, rotation.array, position.array); mat4.scale(m, m, scale.array); rotation._dirty = false; scale._dirty = false; position._dirty = false; this._needsUpdateWorldTransform = true; } }, _updateWorldTransformTopDown: function() { var localTransform = this.localTransform.array; var worldTransform = this.worldTransform.array; if (this._parent) { mat4.multiplyAffine( worldTransform, this._parent.worldTransform.array, localTransform ); } else { mat4.copy(worldTransform, localTransform); } }, updateWorldTransform: function() { var rootNodeIsDirty = this; while (rootNodeIsDirty && rootNodeIsDirty.getParent() && rootNodeIsDirty.getParent().transformNeedsUpdate()) { rootNodeIsDirty = rootNodeIsDirty.getParent(); } rootNodeIsDirty.update(); }, update: function(forceUpdateWorld) { if (this.autoUpdateLocalTransform) { this.updateLocalTransform(); } else { forceUpdateWorld = true; } if (forceUpdateWorld || this._needsUpdateWorldTransform) { this._updateWorldTransformTopDown(); forceUpdateWorld = true; this._needsUpdateWorldTransform = false; } var children = this._children; for (var i = 0, len = children.length; i < len; i++) { children[i].update(forceUpdateWorld); } }, getBoundingBox: function() { function defaultFilter(el) { return !el.invisible && el.geometry; } var tmpBBox = new BoundingBox(); var tmpMat4 = new Matrix4(); var invWorldTransform = new Matrix4(); return function(filter, out) { out = out || new BoundingBox(); if (this._parent) { Matrix4.invert(invWorldTransform, this._parent.worldTransform); } else { Matrix4.identity(invWorldTransform); } this.traverse(function(mesh) { if (mesh.geometry && mesh.geometry.boundingBox) { tmpBBox.copy(mesh.geometry.boundingBox); Matrix4.multiply(tmpMat4, invWorldTransform, mesh.worldTransform); tmpBBox.applyTransform(tmpMat4); out.union(tmpBBox); } }, this, defaultFilter); return out; }; }(), getWorldPosition: function(out) { if (this.transformNeedsUpdate()) { this.updateWorldTransform(); } var m = this.worldTransform.array; if (out) { var arr = out.array; arr[0] = m[12]; arr[1] = m[13]; arr[2] = m[14]; return out; } else { return new Vector3(m[12], m[13], m[14]); } }, clone: function() { var node = new this.constructor(); var children = this._children; node.setName(this.name); node.position.copy(this.position); node.rotation.copy(this.rotation); node.scale.copy(this.scale); for (var i = 0; i < children.length; i++) { node.add(children[i].clone()); } return node; }, rotateAround: function() { var v = new Vector3(); var RTMatrix = new Matrix4(); return function(point, axis, angle) { v.copy(this.position).subtract(point); var localTransform = this.localTransform; localTransform.identity(); localTransform.translate(point); localTransform.rotate(angle, axis); RTMatrix.fromRotationTranslation(this.rotation, v); localTransform.multiply(RTMatrix); localTransform.scale(this.scale); this.decomposeLocalTransform(); this._needsUpdateWorldTransform = true; }; }(), lookAt: function() { var m = new Matrix4(); return function(target, up) { m.lookAt(this.position, target, up || this.localTransform.y).invert(); this.setLocalTransform(m); this.target = target; }; }() } ); var Node3D = Node; export { Node3D as default };