Three.js 本地矩阵 .materix 和世界矩阵 .matrixWorld

发布于 2021-07-17 09:59:32 字数 4866 浏览 2088 评论 0

在学习本地矩阵 .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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

虐人心

有一天你能到我的心里去,你会看到那里全是你给的伤悲。

0 文章
0 评论
24514 人气
更多

推荐作者

qq_Yqvrrd

文章 0 评论 0

2503248646

文章 0 评论 0

浮生未歇

文章 0 评论 0

养猫人

文章 0 评论 0

第七度阳光i

文章 0 评论 0

新雨望断虹

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文