【threejs】实现绕指定点/物体旋转 |
您所在的位置:网站首页 › ai中如何围绕一个点旋转 › 【threejs】实现绕指定点/物体旋转 |
背景
实现方块A绕方块B旋转(方块B在原点,且不动) 思路 将方块A平移到方块B所在位置,旋转方块A,将方块A平移回去 方向上没错,但缺少细节,下面我们分两种情况实践一下。(区别就在于:平移时,使用的坐标系) 方法一:对方块A,基于世界坐标系平移,再基于自身/局部坐标系旋转,最后基于世界坐标系平移回去。 方法二:对方块A,基于自身坐标系平移,再基于自身/局部坐标系旋转,最后基于自身坐标系平移回去。 过程 方法一: 基于世界坐标系平移(按照红轴方向,平移-N个单位)表现:对比最初的状态,方块A看起来是在原地绕自身旋转。
方法二: 基于自身坐标系平移(按照红轴方向,平移-N个单位)表现:对比最初的状态,方块A表现出绕物体B旋转。 分析 将两方法结合对比可得: 第一步:效果一致。 按世界坐标系的红轴 和 自身坐标系的红轴方向完全一致,所以平移效果一致。 第二步:效果一致。 实现一致,都是按照自身坐标系旋转 第三步:效果不一致。 方法一世界坐标系的红轴不受物体A旋转影响,世界的红轴方向不变。所以平移回去,还是最初的位置。 方法二自身坐标系受到的旋转的影响,此时自身坐标系的红轴方向改变,因此根据变化方向后的红轴平移回去的结果,和最初的位置不同。 疑问 Q:为什么第一步和第三步的平移,要么都是按世界坐标系,要么都是按自身坐标系?不可以第一步按世界坐标系,第三步按自身坐标系吗? A:为了方便,因为计算第一步的平移矩阵M后,第三步的平移矩阵只需要用api求出M的逆矩阵。 第二个问题是可以按照这个思路,你只要确保算出的平移矩阵是对的就行。
总结 绕定点/物体旋转,最简单的方式是:将动点基于自身坐标系平移到定点的位置,(动点)再基于自身坐标系旋转,最后(动点)基于自身坐标系平移回去。
部分核心ts代码 感受threejs 里multiply和premultiply的应用, 还涉及到“同一向量在不同基底上表示为不同坐标”的计算(应用场景:某物体在世界坐标系下平移到目标点的向量是T1,那转换到某物体的局部坐标系下,T1在局部坐标系下如何计算)。 (链接为gitchat专栏《机器学习中的数据:线性代数》 的第二篇 空间:从向量和基底谈起 ,专栏29元,16篇,个人觉得还挺划算的) // 世界平移-自身旋转-世界平移的逆(表现为原地旋转) public worldTranslation_SelfRotate() { let worldPosZero = this.getWorldPosition(this.cubeArr[0]);//本质上就是Object3D里的getWorldPosition() 获取世界坐标 let worldPosOne = this.getWorldPosition(this.cubeArr[1]); let worldOffset = worldPosZero.sub(worldPosOne); let goZeroMatrix = new Matrix4().makeTranslation(worldOffset.x, worldOffset.y, worldOffset.z); this.cubeArr[1].matrix.premultiply(goZeroMatrix); let angle = 30 * Math.PI / 180; let absAngle = Math.abs(angle); this.cubeArr[1].matrix.multiply(new THREE.Matrix4().makeRotationZ(absAngle)); let mat4I = new THREE.Matrix4(); mat4I.copy(goZeroMatrix).invert();// mat4I.getInverse(goZeroMatrix);getInverse函数已弃用 this.cubeArr[1].matrix.premultiply(mat4I); } // 自身平移-自身旋转-自身平移的逆(表现为绕轴旋转) public SelfTranslation_SelfRotate() { let worldPosZero = this.getWorldPosition(this.cubeArr[0]); let worldPosOne = this.getWorldPosition(this.cubeArr[1]); let worldOffset = worldPosZero.sub(worldPosOne); // 世界空间转局部空间 let itemBaseVec = this.getBasisVec(this.cubeArr[1].matrix);//本质上就是extractBasis() 获取基坐标系 let localOffset = this.vectorChangBasic(worldOffset,itemBaseVec); let goZeroMatrix = new Matrix4().makeTranslation(localOffset.x, localOffset.y, localOffset.z); this.cubeArr[1].matrix.multiply(goZeroMatrix); let angle = 30 * Math.PI / 180; let absAngle = Math.abs(angle); this.cubeArr[1].matrix.multiply(new THREE.Matrix4().makeRotationZ(absAngle)); let mat4I = new THREE.Matrix4(); mat4I.copy(goZeroMatrix).invert();// mat4I.getInverse(goZeroMatrix);getInverse函数已弃用 this.cubeArr[1].matrix.multiply(mat4I); } private vectorChangBasic(needChangeVec: Vector3, baseVec: baseVectorObj) { // 世界空间的相对位置,转成基于baseVec坐标系下的位置 let newVec: Vector3 = new Vector3(); newVec.x = needChangeVec.dot(baseVec.x); newVec.y = needChangeVec.dot(baseVec.y); newVec.z = needChangeVec.dot(baseVec.z); return newVec; } 项目https://github.com/LJLCarrien/threejsCube 分支 test_2Rotate 初衷:为了学下矩阵和threejs |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |