Three.js 本地矩阵 .materix 和世界矩阵 .matrixWorld
在学习本地矩阵 .materix
之前你应该先对 WebGL 的旋转、平移、缩放等变换矩阵有一定的认知,在了解世界矩阵.matrixWorld
之前你应该现对象Three.js中层级模型的概念有一定的了解,Threejs如何通过Group
来创建一个父子关系层级模型。
一个对象的本地矩阵.materix
包含了该对象的旋转、平移和缩放变换,本地矩阵是平移矩阵、缩放矩阵和旋转矩阵的乘积。
一个对象的世界矩阵.matrixWorld
是该对象本地矩阵及其所有所有祖宗对象本地矩阵的乘积,或者每一个对象的世界矩阵是对象本地矩阵和父对象的世界矩阵的乘积。
流程图
下面用一章流程图来表达Three.js本地矩阵.materix
是什么,本地矩阵.materix
和世界矩阵.matrixWorld
又有什么关系。
Object3D
Object3D
是网格Mesh、点Points、线Line等模型对象的基类,组对象Group
也是Object3D
对象的基类。
Object3D
封装本地矩阵.matrix
、位置.position
、缩放.scale
、角度.rotation
等属性,封装了旋转相关方法.rotateX()
、.rotateZ()
,平移相关方法.translateX()
、.translateZ()
。
四元数属性 .quaternion
和角度属性 .rotation
两个属性表达的含义是一样的,都是旋转相关的信息,都会被转化为旋转矩阵。
方法改变属性
对于Three.js一些对象的属性可以直接设置属性值,也可以通过方法改变属性值。
执行旋转方法.rotateZ()
查看,查看角度属性.rotation
属性值欧拉对象z属性的变化
// 一个网格模型对象,基类是Object3D
var mesh = new THREE.Mesh()
// 绕z轴旋转
mesh.rotateZ(Math.PI)
console.log('查看角度属性值的变化',mesh.rotation);
console.log('查看四元数属性变化',mesh.quaternion);
执行平移方法.translateX()
查看,查看位置.position
属性值x分量变化
// 一个网格模型对象,基类是Object3D
var mesh = new THREE.Mesh()
// 沿着x轴平移100
mesh.translateX(100)
console.log('查看位置属性的变化',mesh.position);
更新本地矩阵属性 .updateMatrix()
执行Object3D
的.updateMatrix()
方法可以提取位置.position
、缩放.scale
和四元数.quaternion
的属性值转化为变换矩阵设置本地矩阵属性.matrix
。
// Object3D.js源码
updateMatrix: function () {
// 把位置、四元数、缩放属性转化为平移、旋转、缩放矩阵,三个矩阵的乘积是本地矩阵
this.matrix.compose( this.position, this.quaternion, this.scale );
this.matrixWorldNeedsUpdate = true;
},
// Matrix4.js源码
// 通过属性值设置变换矩阵
compose: function ( position, quaternion, scale ) {
// 四元数矩阵转化为旋转矩阵,然后改变本地矩阵
this.makeRotationFromQuaternion( quaternion );
// 缩放属性转化为缩放矩阵,然后改变本地矩阵
this.scale( scale );
// 位置属性转化为平移矩阵,然后改变本地矩阵
this.setPosition( position );
return this;
},
// 一个网格模型对象,基类是Object3D
var mesh = new THREE.Mesh()
// 缩放网格模型
mesh.scale.set(900,900,900)
// 位置、角度、缩放属性值更新到矩阵属性matrix
mesh.updateMatrix();
console.log('查看本地矩阵属性matrix',mesh.matrix.elements);
更新世界矩阵属性 .updateMatrixWorld()
调用.updateMatrixWorld()
方法首先会更新对象的本地矩阵属性,然后更新对象的世界矩阵属性。
.updateMatrixWorld()
方法封装了递归算法,会遍历对象的所有子对象,对象本身和
// Object3D.js源码
updateMatrixWorld: function ( force ) {
// 更新对象的本地矩阵属性
if ( this.matrixAutoUpdate ) this.updateMatrix();
...
if ( this.parent === null ) {
// 如果一个对象没有父对象,也就是树结构对象的根节点对象,世界矩阵就等于本地矩阵
this.matrixWorld.copy( this.matrix );
} else {
// 更新对象的世界矩阵,父对象的世界矩阵和对象本地矩阵的乘积
this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
}
...
// 通过递归算法遍历一个对象的所有子对象,执行与根对象一样的操作更新本地和世界矩阵属性
var children = this.children;
for ( var i = 0, l = children.length; i < l; i ++ ) {
children[ i ].updateMatrixWorld( force );
}
},
WebGL 渲染器
场景对象的.autoUpdate
属性默认值是true,执行.render()
方法的时候scene.updateMatrixWorld()
默认执行,也就是说执行
Threejs执行渲染器渲染方法的时候,场景对象所有子孙对象的世界矩阵属性和本地矩阵属性才会更新。
// WebGLRenderer.js源码
this.render=function(){
...
// WebGL渲染器中执行场景对象的updateMatrixWorld()方法,更新场景和场景所有子孙对象的本地矩阵
if (scene.autoUpdate === true) scene.updateMatrixWorld();
...
}
世界坐标和本地坐标
位置属性.position
表示本地坐标,也就是说该对象相对父对象的偏移位置。通过Object3D
的.getWorldPosition()
方法可以返回一个模型的世界坐标,是模型对象相对坐标原点的位置坐标,也就是该对象位置属性.position
及其所有祖宗对象的.position
相加。
var worldPosition = new THREE.Vector3();
mesh.getWorldPosition(worldPosition)
console.log('世界坐标',worldPosition);
console.log('本地坐标',mesh.position);
// Object3D.js源码
getWorldPosition: function ( target ) {
if ( target === undefined ) {
console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' );
target = new Vector3();
}
this.updateMatrixWorld( true );
通过矩阵对象setFromMatrixPosition方法从世界矩阵中提取平移矩阵分量,然后转化为position属性
return target.setFromMatrixPosition( this.matrixWorld );
},
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论