WebGL教程_Three.js教程_郭隆邦技术博客 郭隆邦_技术博客 一对一班

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 );
},
本站版权所有,本站任何内容未经允许不得转载   备案号:豫ICP备16004767号 QQ群:187740169 (WebGL-Three.js教程)   邮箱:guolongbang@163.com