ThreeJS核心基类-Object3D

ThreeJS的核心基类Object3D被很多场景对象所继承,例如Scene、Camera、Mesh、Light等;凡是继承于该基类的对象都会拥有“旋转平移缩放”(物理世界三大基本变换)的能力,该类还有两个“绝顶”重要的矩阵:matrix(本地矩阵)和matrixWorld(模型矩阵也叫作世界矩阵)。

1.WebGL中的MVP矩阵

在计算机图形学中,“矩阵”是无法逃避的话题。渲染管线最终是要将3D物体经过变换和投影转换成2D纹理数据,2D纹理数据更新进帧缓冲区就会绘制到屏幕上,其中变换和投影所使用的就是MVP矩阵左乘3D物体每个顶点。接下来介绍MVP矩阵是如何构建而成的:

1.M矩阵

模型顶点左乘M矩阵的效果:将该模型转换到世界坐标系下。
M矩阵如何构建:通过该模型的旋转平移缩放构建而成。矩阵是如何存储旋转平移缩放变换的可参见《3D数学基础:图形与游戏开发》一书第7、8章节。如果想深入理解向量和矩阵,可以观看老外做的非常棒的视频《线性代数的本质》系列(中文字幕),地址:https://www.bilibili.com/video/av6731067/?p=1
在这里插入图片描述

2.V矩阵

模型顶点左乘M矩阵再乘V矩阵的效果:将该模型从世界坐标系下转换到视图坐标系(相机坐标系)。
V矩阵如何构建:通过相机在世界坐标系下的旋转平移缩放构建而成。但是需要注意:渲染管线中的真实用的V矩阵是相机世界矩阵的逆矩阵,也就是说,我们使用相机的旋转平移缩放构建的矩阵再计算出的逆矩阵才是渲染管线中的真实使用的那个V矩阵,为什么呢?在3D世界中,我们变换相机观察世界,和相机不动,将世界所有物体向相机变换的反方向变换,效果是等价的。

3.P矩阵

模型顶点左乘M矩阵再乘V矩阵再乘P矩阵的效果:将该模型从视图坐标系转换到投影坐标系。
P矩阵如何构建:P矩阵的构建需要相机的视椎体信息(left, left + width, top, top - height, near, far),具体怎么把矩阵算出来,就去找个Matrix的数学库看一眼吧,这里只说理论。

2.Object3D中的本地矩阵和世界矩阵

ThreeJS-Object3D中matrix和matrixWorld矩阵有时相同有时不同,这要看该对象是否拥有父物体。当该对象没有父物体的时候,matrix和matrixWorld是相同的;当该对象有父物体的时候,matrixWorld= 父物体的世界矩阵matrixWorld * matrix,注意:矩阵的左乘和右乘是不一样。
在ThreeJS渲染器类WebGLRenderer中的render方法中(相信用过ThreeJS的人都会知道),我们会传入scene和camera两个参数,该函数首先就会递归计算scene下所有对象和camera的matrix和matrixWorld两个矩阵,代码如下:

	// 递归计算场景中所有对象的本地矩阵和世界矩阵
	if (scene.autoUpdate === true) scene.updateMatrixWorld();
	// 计算相机本地矩阵、相机世界矩阵、相机世界矩阵的逆矩阵(MVP的V)
	if (camera.parent === null) camera.updateMatrixWorld();

updateMatrixWorld方法就在Object3D中,scene会递归所有的子物体都计算matrix和matrixWorld矩阵,camera在自己类中重写此方法,具体实现如下:

	// 根据PRS计算对象Matrix
	updateMatrix: function () {
		this.matrix.compose( this.position, this.quaternion, this.scale );
		this.matrixWorldNeedsUpdate = true;
	},
	// 在Render中,此处用于计算scene以及子物体和camera的matrix和matrixWorld
	updateMatrixWorld: function ( force ) {
		if ( this.matrixAutoUpdate ) this.updateMatrix();
		if ( this.matrixWorldNeedsUpdate || force ) {
			if ( this.parent === null ) {
				this.matrixWorld.copy( this.matrix );
			} else {
				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
			}
			this.matrixWorldNeedsUpdate = false;
			force = true;
		}
		// update children
		var children = this.children;
		for ( var i = 0, l = children.length; i < l; i ++ ) {
			children[ i ].updateMatrixWorld( force );
		}
	},

3.Object3D中lookAt方法的计算原理

在这里插入图片描述
lookAt是一个经常使用的接口,相机可以设置lookAt(瞅着目标点),物体也可以调用lookAt设置朝向(如上图),那么lookAt是如何计算出物体的姿态信息的呢?源码代码如下:

lookAt: function () {

		// This method does not support objects having non-uniformly-scaled parent(s)
		var q1 = new Quaternion();
		var m1 = new Matrix4();
		var target = new Vector3();
		var position = new Vector3();
		
		return function lookAt( x, y, z ) {
			if ( x.isVector3 ) {
				target.copy( x );
			} else {
				target.set( x, y, z );
			}

			var parent = this.parent;
			this.updateWorldMatrix( true, false );
			position.setFromMatrixPosition( this.matrixWorld );
			
			if ( this.isCamera || this.isLight ) {
				m1.lookAt( position, target, this.up );
			} else {
				m1.lookAt( target, position, this.up );
			}

			this.quaternion.setFromRotationMatrix( m1 );

			if ( parent ) {
				m1.extractRotation( parent.matrixWorld );
				q1.setFromRotationMatrix( m1 );
				this.quaternion.premultiply( q1.inverse() );
			}
		};
	}()

Matrix4中的lookAt矩阵计算源码如下:

	lookAt: function () {

		var x = new Vector3();
		var y = new Vector3();
		var z = new Vector3();

		return function lookAt( eye, target, up ) {
		
			var te = this.elements;
			z.subVectors( eye, target );
			
			if ( z.lengthSq() === 0 ) {
				// eye and target are in the same position
				z.z = 1;
			}

			z.normalize();
			x.crossVectors( up, z );

			if ( x.lengthSq() === 0 ) {
				// up and z are parallel
				if ( Math.abs( up.z ) === 1 ) {
					z.x += 0.0001;
				} else {
					z.z += 0.0001;
				}

				z.normalize();
				x.crossVectors( up, z );
			}

			x.normalize();
			y.crossVectors( z, x );

			te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
			te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
			te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;

			return this;
		};
	}(),

文末奉上自己整理的ThreeJS Render绘制流程图(还需完善,如有错误请指正,邮箱:1780721345@qq.com):
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Superman_ztf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值