|
@@ -20372,7 +20372,7 @@
|
|
|
r: 255,
|
|
|
g: 255,
|
|
|
b: 255,
|
|
|
- a: 1.0
|
|
|
+ a: 0.7
|
|
|
};
|
|
|
this.textColor = options.textColor ? Common$1.CloneObject(options.textColor) : {
|
|
|
r: 0,
|
|
@@ -75511,7 +75511,8 @@
|
|
|
applyData: data => {
|
|
|
if (data.object.parent /* && data.object == this.selected */) {
|
|
|
data = Potree.Common.CloneObject(data); //避免使用后更改数据又被使用
|
|
|
- data.matrix.decompose(data.object.position, data.object.quaternion, data.object.scale);
|
|
|
+ var matrix = data.object.parent ? data.object.parent.matrixWorld.clone().invert().multiply(data.matrixWorld) : data.matrixWorld;
|
|
|
+ matrix.decompose(data.object.position, data.object.quaternion, data.object.scale);
|
|
|
data.object.boundCenter.copy(data.boundCenter);
|
|
|
data.object.dispatchEvent('changeByHistory');
|
|
|
data.object.dispatchEvent('transformChanged');
|
|
@@ -75522,7 +75523,7 @@
|
|
|
getData: object => {
|
|
|
return {
|
|
|
object,
|
|
|
- matrix: object.matrixWorld.clone(),
|
|
|
+ matrixWorld: object.matrixWorld.clone(),
|
|
|
boundCenter: object.boundCenter.clone()
|
|
|
};
|
|
|
}
|
|
@@ -75967,16 +75968,32 @@
|
|
|
this.bus.dispatchEvent('changeSelect');
|
|
|
},
|
|
|
updateBoxHelper(model) {
|
|
|
+ /* let size = new THREE.Vector3
|
|
|
+ model.boundingBox.getSize(size)
|
|
|
+ size.multiply(model.scale)
|
|
|
+ this.boxHelper.scale.copy(size)
|
|
|
+
|
|
|
+ let center = new THREE.Vector3
|
|
|
+ model.boundingBox.getCenter(center)
|
|
|
+ center.applyMatrix4(model.matrixWorld)
|
|
|
+ //center.add(model.position)
|
|
|
+ this.boxHelper.position.copy(center)
|
|
|
+
|
|
|
+ this.boxHelper.quaternion.copy(model.quaternion) */
|
|
|
+
|
|
|
var size = new Vector3();
|
|
|
model.boundingBox.getSize(size);
|
|
|
- size.multiply(model.scale);
|
|
|
+ size.multiply(model.getWorldScale(new Vector3()));
|
|
|
this.boxHelper.scale.copy(size);
|
|
|
var center = new Vector3();
|
|
|
model.boundingBox.getCenter(center);
|
|
|
center.applyMatrix4(model.matrixWorld);
|
|
|
- //center.add(model.position)
|
|
|
this.boxHelper.position.copy(center);
|
|
|
- this.boxHelper.quaternion.copy(model.quaternion);
|
|
|
+ model.getWorldQuaternion(this.boxHelper.quaternion);
|
|
|
+
|
|
|
+ /* this.boxHelper.scale.copy(model.getWorldScale(new THREE.Vector3))
|
|
|
+ this.boxHelper.quaternion.copy(model.getWorldQuaternion(new THREE.Quaternion))
|
|
|
+ this.boxHelper.position.copy(model.getWorldPosition(new THREE.Vector3)) */
|
|
|
viewer.dispatchEvent('content_changed');
|
|
|
},
|
|
|
showModelOutline(model, state) {
|
|
@@ -86692,6 +86709,328 @@
|
|
|
|
|
|
*/
|
|
|
|
|
|
+ var _q = new Quaternion();
|
|
|
+ var _targetPos = new Vector3();
|
|
|
+ var _targetVec = new Vector3();
|
|
|
+ var _effectorPos = new Vector3();
|
|
|
+ var _effectorVec = new Vector3();
|
|
|
+ var _linkPos = new Vector3();
|
|
|
+ var _invLinkQ = new Quaternion();
|
|
|
+ var _linkScale = new Vector3();
|
|
|
+ var _axis$2 = new Vector3();
|
|
|
+ var _vector$e = new Vector3();
|
|
|
+ var _matrix$2 = new Matrix4();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * CCD Algorithm
|
|
|
+ * - https://web.archive.org/web/20221206080850/https://sites.google.com/site/auraliusproject/ccd-algorithm
|
|
|
+ *
|
|
|
+ * // ik parameter example
|
|
|
+ * //
|
|
|
+ * // target, effector, index in links are bone index in skeleton.bones.
|
|
|
+ * // the bones relation should be
|
|
|
+ * // <-- parent child -->
|
|
|
+ * // links[ n ], links[ n - 1 ], ..., links[ 0 ], effector
|
|
|
+ * iks = [ {
|
|
|
+ * target: 1,
|
|
|
+ * effector: 2,
|
|
|
+ * links: [ { index: 5, limitation: new Vector3( 1, 0, 0 ) }, { index: 4, enabled: false }, { index : 3 } ],
|
|
|
+ * iteration: 10,
|
|
|
+ * minAngle: 0.0,
|
|
|
+ * maxAngle: 1.0,
|
|
|
+ * } ];
|
|
|
+ */
|
|
|
+
|
|
|
+ class CCDIKSolver {
|
|
|
+ /**
|
|
|
+ * @param {THREE.SkinnedMesh} mesh
|
|
|
+ * @param {Array<Object>} iks
|
|
|
+ */
|
|
|
+ constructor(mesh) {
|
|
|
+ var iks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
|
+ this.mesh = mesh;
|
|
|
+ this.iks = iks;
|
|
|
+ this._valid();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Update all IK bones.
|
|
|
+ *
|
|
|
+ * @return {CCDIKSolver}
|
|
|
+ */
|
|
|
+ update() {
|
|
|
+ var iks = this.iks;
|
|
|
+ for (var i = 0, il = iks.length; i < il; i++) {
|
|
|
+ this.updateOne(iks[i]);
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Update one IK bone
|
|
|
+ *
|
|
|
+ * @param {Object} ik parameter
|
|
|
+ * @return {CCDIKSolver}
|
|
|
+ */
|
|
|
+ updateOne(ik) {
|
|
|
+ var bones = this.mesh.skeleton.bones;
|
|
|
+
|
|
|
+ // for reference overhead reduction in loop
|
|
|
+ var math = Math;
|
|
|
+ var effector = bones[ik.effector];
|
|
|
+ var target = bones[ik.target];
|
|
|
+
|
|
|
+ // don't use getWorldPosition() here for the performance
|
|
|
+ // because it calls updateMatrixWorld( true ) inside.
|
|
|
+ _targetPos.setFromMatrixPosition(target.matrixWorld);
|
|
|
+ var links = ik.links;
|
|
|
+ var iteration = ik.iteration !== undefined ? ik.iteration : 1;
|
|
|
+ for (var i = 0; i < iteration; i++) {
|
|
|
+ var rotated = false;
|
|
|
+ for (var j = 0, jl = links.length; j < jl; j++) {
|
|
|
+ var link = bones[links[j].index];
|
|
|
+
|
|
|
+ // skip this link and following links
|
|
|
+ if (links[j].enabled === false) break;
|
|
|
+ var limitation = links[j].limitation;
|
|
|
+ var rotationMin = links[j].rotationMin;
|
|
|
+ var rotationMax = links[j].rotationMax;
|
|
|
+
|
|
|
+ // don't use getWorldPosition/Quaternion() here for the performance
|
|
|
+ // because they call updateMatrixWorld( true ) inside.
|
|
|
+ link.matrixWorld.decompose(_linkPos, _invLinkQ, _linkScale);
|
|
|
+ _invLinkQ.invert();
|
|
|
+ _effectorPos.setFromMatrixPosition(effector.matrixWorld);
|
|
|
+
|
|
|
+ // work in link world
|
|
|
+ _effectorVec.subVectors(_effectorPos, _linkPos);
|
|
|
+ _effectorVec.applyQuaternion(_invLinkQ);
|
|
|
+ _effectorVec.normalize();
|
|
|
+ _targetVec.subVectors(_targetPos, _linkPos);
|
|
|
+ _targetVec.applyQuaternion(_invLinkQ);
|
|
|
+ _targetVec.normalize();
|
|
|
+ var angle = _targetVec.dot(_effectorVec);
|
|
|
+ if (angle > 1.0) {
|
|
|
+ angle = 1.0;
|
|
|
+ } else if (angle < -1.0) {
|
|
|
+ angle = -1.0;
|
|
|
+ }
|
|
|
+ angle = math.acos(angle);
|
|
|
+
|
|
|
+ // skip if changing angle is too small to prevent vibration of bone
|
|
|
+ if (angle < 1e-5) continue;
|
|
|
+ if (ik.minAngle !== undefined && angle < ik.minAngle) {
|
|
|
+ angle = ik.minAngle;
|
|
|
+ }
|
|
|
+ if (ik.maxAngle !== undefined && angle > ik.maxAngle) {
|
|
|
+ angle = ik.maxAngle;
|
|
|
+ }
|
|
|
+ _axis$2.crossVectors(_effectorVec, _targetVec);
|
|
|
+ _axis$2.normalize();
|
|
|
+ _q.setFromAxisAngle(_axis$2, angle);
|
|
|
+ link.quaternion.multiply(_q);
|
|
|
+
|
|
|
+ // TODO: re-consider the limitation specification
|
|
|
+ if (limitation !== undefined) {
|
|
|
+ var c = link.quaternion.w;
|
|
|
+ if (c > 1.0) c = 1.0;
|
|
|
+ var c2 = math.sqrt(1 - c * c);
|
|
|
+ link.quaternion.set(limitation.x * c2, limitation.y * c2, limitation.z * c2, c);
|
|
|
+ }
|
|
|
+ if (rotationMin !== undefined) {
|
|
|
+ link.rotation.setFromVector3(_vector$e.setFromEuler(link.rotation).max(rotationMin));
|
|
|
+ }
|
|
|
+ if (rotationMax !== undefined) {
|
|
|
+ link.rotation.setFromVector3(_vector$e.setFromEuler(link.rotation).min(rotationMax));
|
|
|
+ }
|
|
|
+ link.updateMatrixWorld(true);
|
|
|
+ rotated = true;
|
|
|
+ }
|
|
|
+ if (!rotated) break;
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates Helper
|
|
|
+ *
|
|
|
+ * @param {number} sphereSize
|
|
|
+ * @return {CCDIKHelper}
|
|
|
+ */
|
|
|
+ createHelper(sphereSize) {
|
|
|
+ return new CCDIKHelper(this.mesh, this.iks, sphereSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ // private methods
|
|
|
+
|
|
|
+ _valid() {
|
|
|
+ var iks = this.iks;
|
|
|
+ var bones = this.mesh.skeleton.bones;
|
|
|
+ for (var i = 0, il = iks.length; i < il; i++) {
|
|
|
+ var ik = iks[i];
|
|
|
+ var effector = bones[ik.effector];
|
|
|
+ var links = ik.links;
|
|
|
+ var link0 = void 0,
|
|
|
+ link1 = void 0;
|
|
|
+ link0 = effector;
|
|
|
+ for (var j = 0, jl = links.length; j < jl; j++) {
|
|
|
+ link1 = bones[links[j].index];
|
|
|
+ if (link0.parent !== link1) {
|
|
|
+ console.warn('THREE.CCDIKSolver: bone ' + link0.name + ' is not the child of bone ' + link1.name);
|
|
|
+ }
|
|
|
+ link0 = link1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ function getPosition(bone, matrixWorldInv) {
|
|
|
+ return _vector$e.setFromMatrixPosition(bone.matrixWorld).applyMatrix4(matrixWorldInv);
|
|
|
+ }
|
|
|
+ function setPositionOfBoneToAttributeArray(array, index, bone, matrixWorldInv) {
|
|
|
+ var v = getPosition(bone, matrixWorldInv);
|
|
|
+ array[index * 3 + 0] = v.x;
|
|
|
+ array[index * 3 + 1] = v.y;
|
|
|
+ array[index * 3 + 2] = v.z;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Visualize IK bones
|
|
|
+ */
|
|
|
+ class CCDIKHelper extends Object3D {
|
|
|
+ /**
|
|
|
+ * @param {SkinnedMesh} mesh
|
|
|
+ * @param {Array<Object>} [iks=[]]
|
|
|
+ * @param {number} [sphereSize=0.25]
|
|
|
+ */
|
|
|
+ constructor(mesh) {
|
|
|
+ var iks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
|
+ var sphereSize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.25;
|
|
|
+ super();
|
|
|
+ this.root = mesh;
|
|
|
+ this.iks = iks;
|
|
|
+ this.matrix.copy(mesh.matrixWorld);
|
|
|
+ this.matrixAutoUpdate = false;
|
|
|
+ this.sphereGeometry = new SphereGeometry(sphereSize, 16, 8);
|
|
|
+ this.targetSphereMaterial = new MeshBasicMaterial({
|
|
|
+ color: new Color(0xff8888),
|
|
|
+ depthTest: false,
|
|
|
+ depthWrite: false,
|
|
|
+ transparent: true
|
|
|
+ });
|
|
|
+ this.effectorSphereMaterial = new MeshBasicMaterial({
|
|
|
+ color: new Color(0x88ff88),
|
|
|
+ depthTest: false,
|
|
|
+ depthWrite: false,
|
|
|
+ transparent: true
|
|
|
+ });
|
|
|
+ this.linkSphereMaterial = new MeshBasicMaterial({
|
|
|
+ color: new Color(0x8888ff),
|
|
|
+ depthTest: false,
|
|
|
+ depthWrite: false,
|
|
|
+ transparent: true
|
|
|
+ });
|
|
|
+ this.lineMaterial = new LineBasicMaterial({
|
|
|
+ color: new Color(0xff0000),
|
|
|
+ depthTest: false,
|
|
|
+ depthWrite: false,
|
|
|
+ transparent: true
|
|
|
+ });
|
|
|
+ this._init();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Updates IK bones visualization.
|
|
|
+ *
|
|
|
+ * @param {Boolean} force
|
|
|
+ */
|
|
|
+ updateMatrixWorld(force) {
|
|
|
+ var mesh = this.root;
|
|
|
+ if (this.visible) {
|
|
|
+ var offset = 0;
|
|
|
+ var iks = this.iks;
|
|
|
+ var bones = mesh.skeleton.bones;
|
|
|
+ _matrix$2.copy(mesh.matrixWorld).invert();
|
|
|
+ for (var i = 0, il = iks.length; i < il; i++) {
|
|
|
+ var ik = iks[i];
|
|
|
+ var targetBone = bones[ik.target];
|
|
|
+ var effectorBone = bones[ik.effector];
|
|
|
+ var targetMesh = this.children[offset++];
|
|
|
+ var effectorMesh = this.children[offset++];
|
|
|
+ targetMesh.position.copy(getPosition(targetBone, _matrix$2));
|
|
|
+ effectorMesh.position.copy(getPosition(effectorBone, _matrix$2));
|
|
|
+ for (var j = 0, jl = ik.links.length; j < jl; j++) {
|
|
|
+ var link = ik.links[j];
|
|
|
+ var linkBone = bones[link.index];
|
|
|
+ var linkMesh = this.children[offset++];
|
|
|
+ linkMesh.position.copy(getPosition(linkBone, _matrix$2));
|
|
|
+ }
|
|
|
+ var line = this.children[offset++];
|
|
|
+ var array = line.geometry.attributes.position.array;
|
|
|
+ setPositionOfBoneToAttributeArray(array, 0, targetBone, _matrix$2);
|
|
|
+ setPositionOfBoneToAttributeArray(array, 1, effectorBone, _matrix$2);
|
|
|
+ for (var _j = 0, _jl = ik.links.length; _j < _jl; _j++) {
|
|
|
+ var _link = ik.links[_j];
|
|
|
+ var _linkBone = bones[_link.index];
|
|
|
+ setPositionOfBoneToAttributeArray(array, _j + 2, _linkBone, _matrix$2);
|
|
|
+ }
|
|
|
+ line.geometry.attributes.position.needsUpdate = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.matrix.copy(mesh.matrixWorld);
|
|
|
+ super.updateMatrixWorld(force);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Frees the GPU-related resources allocated by this instance. Call this method whenever this instance is no longer used in your app.
|
|
|
+ */
|
|
|
+ dispose() {
|
|
|
+ this.sphereGeometry.dispose();
|
|
|
+ this.targetSphereMaterial.dispose();
|
|
|
+ this.effectorSphereMaterial.dispose();
|
|
|
+ this.linkSphereMaterial.dispose();
|
|
|
+ this.lineMaterial.dispose();
|
|
|
+ var children = this.children;
|
|
|
+ for (var i = 0; i < children.length; i++) {
|
|
|
+ var child = children[i];
|
|
|
+ if (child.isLine) child.geometry.dispose();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // private method
|
|
|
+
|
|
|
+ _init() {
|
|
|
+ var scope = this;
|
|
|
+ var iks = this.iks;
|
|
|
+ function createLineGeometry(ik) {
|
|
|
+ var geometry = new BufferGeometry();
|
|
|
+ var vertices = new Float32Array((2 + ik.links.length) * 3);
|
|
|
+ geometry.setAttribute('position', new BufferAttribute(vertices, 3));
|
|
|
+ return geometry;
|
|
|
+ }
|
|
|
+ function createTargetMesh() {
|
|
|
+ return new Mesh(scope.sphereGeometry, scope.targetSphereMaterial);
|
|
|
+ }
|
|
|
+ function createEffectorMesh() {
|
|
|
+ return new Mesh(scope.sphereGeometry, scope.effectorSphereMaterial);
|
|
|
+ }
|
|
|
+ function createLinkMesh() {
|
|
|
+ return new Mesh(scope.sphereGeometry, scope.linkSphereMaterial);
|
|
|
+ }
|
|
|
+ function createLine(ik) {
|
|
|
+ return new Line(createLineGeometry(ik), scope.lineMaterial);
|
|
|
+ }
|
|
|
+ for (var i = 0, il = iks.length; i < il; i++) {
|
|
|
+ var ik = iks[i];
|
|
|
+ this.add(createTargetMesh());
|
|
|
+ this.add(createEffectorMesh());
|
|
|
+ for (var j = 0, jl = ik.links.length; j < jl; j++) {
|
|
|
+ this.add(createLinkMesh());
|
|
|
+ }
|
|
|
+ this.add(createLine(ik));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
var loaders = {};
|
|
|
var mapArea;
|
|
|
var shelterHistory = [];
|
|
@@ -91243,6 +91582,8 @@
|
|
|
{
|
|
|
var hasAnimation;
|
|
|
window.pauseAni || this.objs.children.forEach(model => {
|
|
|
+ //model.traverse(object=>object.isSkinnedMesh && object.computeBoundingSphere())
|
|
|
+
|
|
|
if (model.mixer && model.mixer._nActiveActions) {
|
|
|
hasAnimation = true;
|
|
|
model.mixer.update(deltaTime);
|
|
@@ -91250,6 +91591,7 @@
|
|
|
}); //以后有空的话用frust判断是否在画面内,不在的话即使有动画也不要 update 和 render, 如果paused的话是不是也可以不update
|
|
|
hasAnimation && this.dispatchEvent('content_changed');
|
|
|
}
|
|
|
+ if (this.IKSolver) this.IKSolver.update();
|
|
|
|
|
|
// let vrActive = viewer.renderer.xr.isPresenting;
|
|
|
// if(vrActive){
|
|
@@ -91696,8 +92038,8 @@
|
|
|
console.log('加载完毕:', fileInfo_.name, Common$1.getNameFromURL(fileInfo_.url), '耗时(ms)', fileInfo_.loadCostTime /* 模型数据量:' + weight + 'M' */);
|
|
|
if (fileInfo_.fileType == '3dTiles') {
|
|
|
var isGroup = !object.runtime;
|
|
|
- var children = object.runtime ? [object] : object.children;
|
|
|
- children.forEach(object => {
|
|
|
+ var _children = object.runtime ? [object] : object.children;
|
|
|
+ _children.forEach(object => {
|
|
|
var boundingBox_ = new Box3();
|
|
|
var tileset = object.runtime.getTileset();
|
|
|
|
|
@@ -91910,7 +92252,21 @@
|
|
|
var skeleton = new SkeletonHelper(model);
|
|
|
viewer.scene.scene.add(skeleton);
|
|
|
model.skeletonHelper = skeleton; //注意:不能覆盖model.skeleton,因其另有 */
|
|
|
- Potree.Utils.updateVisible(skeleton, 'hide', false); //skeleton.material.opacity = 0.1
|
|
|
+ if (Potree.settings.isOfficial) {
|
|
|
+ Potree.Utils.updateVisible(skeleton, 'hide', false);
|
|
|
+ } else {
|
|
|
+ skeleton.material.opacity = 0.1;
|
|
|
+ skeleton.bones.forEach((bone, i) => {
|
|
|
+ var label = new Potree.TextSprite({
|
|
|
+ text: "".concat(i, " : ").concat(bone.name),
|
|
|
+ sizeInfo: {
|
|
|
+ width2d: 16000
|
|
|
+ }
|
|
|
+ });
|
|
|
+ label.sprite.material.depthTest = false;
|
|
|
+ bone.add(label);
|
|
|
+ });
|
|
|
+ }
|
|
|
var mixer = new AnimationMixer(model);
|
|
|
model.actions = [];
|
|
|
gltf.animations.forEach(ani => {
|
|
@@ -92149,6 +92505,31 @@
|
|
|
});
|
|
|
this.paused = !state;
|
|
|
}
|
|
|
+ setAniIK(model, object) {
|
|
|
+ //不知道为什么一加上胳膊一直动啊??
|
|
|
+ var handIndex = 9;
|
|
|
+ //model.skeletonHelper.bones[handIndex].attach( object ); //bone可以绑定一个球
|
|
|
+ var mesh = children[0].children[1]; //vanguard_Mesh
|
|
|
+ var iks = [{
|
|
|
+ target: 10,
|
|
|
+ //大拇指
|
|
|
+ effector: 9,
|
|
|
+ // 必须是第一个link的child 手腕
|
|
|
+ links: [{
|
|
|
+ index: 8 // 肘关节
|
|
|
+ /* rotationMin: new THREE.Vector3( 1.2, - 1.8, - .4 ),
|
|
|
+ rotationMax: new THREE.Vector3( 1.7, - 1.1, .3 ) */
|
|
|
+ }, {
|
|
|
+ index: 7 // 肩关节
|
|
|
+ /* rotationMin: new THREE.Vector3( 0.1, - 0.7, - 1.8 ),
|
|
|
+ rotationMax: new THREE.Vector3( 1.1, 0, - 1.4 ) */
|
|
|
+ }]
|
|
|
+ }];
|
|
|
+ var IKSolver = new CCDIKSolver(mesh, iks);
|
|
|
+ var ccdikhelper = new CCDIKHelper(mesh, iks, 1.5);
|
|
|
+ viewer.scene.scene.add(ccdikhelper);
|
|
|
+ viewer.IKSolver = IKSolver;
|
|
|
+ }
|
|
|
addFire() {
|
|
|
if (Potree.settings.number == 't-CwfhfqJ') {
|
|
|
var position = Potree.Utils.datasetPosTransform({
|