Three.js 学习笔记(1)--坐标体系和旋转

前言

JavaScript 3D library

The aim of the project is to create an easy to use, lightweight, 3D library. The library provides <canvas>, <svg>, CSS3D and WebGL renderers.(该项目的目标是创建一个易于使用,轻量级的3D库。该库提供了<canvas>,<svg>,CSS3D和WebGL渲染器。)

示例 - 文档 - Wiki - 迁移 - 帮助

官网:https://threejs.org

Github:https://github.com/mrdoob/three.js

学习THREE.JS,可以从《three.js开发指南》开始,有中文电子文档PDF。电子文档代码:https://github.com/josdirksen/learning-threejs

1、3D空间的坐标体系

在threejs中,xyz轴的坐标如图所示,X轴红色,Y轴绿色,Z轴蓝色。

http://www.cnblogs.com/silent-stranger/p/6307372.html

1.相机坐标系(Camera Space)

有一个比较特殊的物体坐标系就是相机坐标系,这个坐标系是我们的视点用来渲染看到的场景所用的坐标系。在相机坐标系中,相机一直处于相机坐标系的原点,+x的方向是向右的,+z的方向是向前的(向屏幕里的方向,因为使用的是左手坐标系),+y的方向是向上。这里的像上不是世界坐标的正上,而是一个相机的上方向。可以来看一下这个相机坐标系的图片。

  这里要注意一些细节,相机的坐标是三维空间,而我们在屏幕上看到的是二维的。
因为我们是做了一个映射,把三维空间的东西映射到了一个二维的平面上,这个映射就是大家知道的“投影”了。

2、二维平面旋转公式

1 x1=Math.cos(angle)*x-Math.sin(angle)*y;
2 y1=Math.cos(angle)*y+Math.sin(angle)*x;
3 //其中x,y表示物体相对于旋转点旋转angle的角度之前的坐标,
4 //  x1,y1表示物体旋转angle后相对于旋转点的坐标

从数学上来说,此公式可以用来计算某个点绕另外一点旋转一定角度后的坐标,

例如:A(x,y)绕B(a,b)旋转β度后的位置为C(c,d),则x,y,a,b,β,c,d有如下关系式:

1。设A点旋转前的角度为δ,则旋转(逆时针)到C点后角度为δ+β

2。求A,B两点的距离:dist1=|AB|=y/sin(δ)=x/cos(δ)

3。求C,B两点的距离:dist2=|CB|=d/sin(δ+β)=c/cos(δ+β)

4。显然dist1=dist2,设dist1=r所以:

  r=x/cos(δ)=y/sin(δ)=d/sin(δ+β)=c/cos(δ+β)

5。由三角函数两角和差公式知:

  sin(δ+β)=sin(δ)cos(β)+cos(δ)sin(β)

  cos(δ+β)=cos(δ)cos(β)-sin(δ)sin(β)

  所以得出:

  c=r*cos(δ+β)=r*cos(δ)cos(β)-r*sin(δ)sin(β)=x*cos(β)-y*sin(β)

  d=r*sin(δ+β)=r*sin(δ)cos(β)+r*cos(δ)sin(β)=y*cos(β)+x*sin(β)

即旋转后的坐标c,d只与旋转前的坐标x,y及旋转的角度β有关

从图中可以很容易理解出A点旋转后的C点总是在圆周上运动,圆周的半径为|AB|,利用这点就可以使物体绕圆周运动,即旋转物体。

3、三维空间旋转公式

【转】https://www.cnblogs.com/silent-stranger/p/6027266.html

  三维空间中主要有两种几何变换,一种是位置的变换,位置变换和二维空间的是一样的。假设一点P(X1,Y1,Z1) 移动到Q(X2,Y2,Z2)只要简单的让P点的坐标值加上偏移值就可以了。但是三维空间的旋转变换就不能简单的使用二维空间的变换了。下面详细介绍一下三维空间的旋转。

  二维空间的旋转可以看作是围绕点的旋转,只有一个自由度。而三维空间的旋转是围绕一条线旋转的。当旋转的轴是Z轴时,旋转可以看作是在二维平面XY平面的旋转,旋转的中心点是P(x=0,y=0)。按照右手法则,让拇指指向Z轴的正方向,四指指向为旋转的正方向。按照Y轴和X轴的旋转也类似。按照不同的轴的旋转可以进行组合。比如,先按照Z轴旋转45度,再按照Y轴旋转45度。但是每一个朝向都可以看成是物体在原始位置处围绕某一个轴转动了一个角度形成的。

                 

三维空间的旋转有多种方式,如旋转矩阵,欧拉角,四元数:

1.欧拉角(Euler Angle)

欧拉角这种旋转方式是最直观的,因为这种方式是将旋转表示为物体按坐标系的三个轴X(1,0,0) ,Y(0,1,0),Z(0,0,1)的旋转组合成的。这里首先要明确两个概念,1参考系:类似于物理中的参考系,是静止不动的,比如北极星,不管在那里,那就是北。2坐标系:坐标系是固定于物体的,随着物体的转动而发生变化,最简单的例子就是左右,人所说的左边一直是根据人所面对的方向来决定的。在下图中蓝色为参考系的三个轴,而红色是物体的坐标系的三个轴。虽然说欧拉角表示的旋转是有多个沿坐标轴的旋转组合而成的。但是旋转的顺序不同旋转就不同,所以,欧拉角中旋转的顺序要注明。这里的三个角是zxz顺规的欧拉角。物体先绕Z轴旋转了α°,然后物体坐标系的x轴的位置变化到了图中N的位置,然后绕这个N轴(X轴)旋转β°,最后再沿Z轴旋转γ°。

欧拉角的旋转虽然是最直观的,但是却存在一个非常致命的问题--万向节锁,大致是指。按某一个旋转了90°的时候会使另外两个轴重合,从而丧失一个自由度。无法很好的追踪物体。具体的可以看一下这个视频万向节锁。讲得非常清楚,这里也就不再赘述了。

欧拉角旋转应用于很多第一人称3D游戏中,虽然万向节锁是无法避免的,但可以将触发的概率减至最小。只有当人物视线完全朝上或者朝下的时候才会触发万向节锁。

2.旋转矩阵(Rotation Matrix)

      三维空间的旋转使用旋转矩阵的方式表示比较容易,旋转矩阵是一个3x3的矩阵。可以看作物体沿空间中的某一个轴(x,y,z)旋转了θ°。三维的旋转矩阵可以表示为:

其中:c=cos(θ) , s=sin(θ),t=1-cos(θ)

假设物体在初始位置的旋转矩阵为A ,经过旋转之后的旋转矩阵为A` ,那么A,A`以及R之间的关系可以表示为 A` = AR。

3.四元数(Quaternion

四元数是一种高阶复数,四元数q表示为:q =(x,y ,z ,w)=xi+y j+z k+w  可以将四元数写成一个向量和一个实数的组合。q =(v  ?    +w)=((x,y ,z ),w)  ,四元数也可用矩阵表示。

可以证明这个矩阵和旋转矩阵是一个矩阵。

在数学上四元数来表示的旋转要好一些,但是在程序设计里,旋转矩阵更方便。在Three.js中使用四元数的方式也是将四元数换成了旋转矩阵使用的。

4、Three.JS中的旋转实现

three.js支持上面所说的三种旋转方式。

1.欧拉角

three.js中场景里的物体都属于Object3D这个类。这个类中有表示物体朝向的一个属性–rotation,这是一个欧拉类型的值,有三个轴旋转的角度,单位是π,还有一个旋转的顺序组成。要使物体旋转可以改动这个rotation的值。比如让物体按Y轴正方向旋转45°可以写成 object3D.rotation.y+=0.25*Math.PI。这里的旋转顺序默认使用的是‘XYZ’顺序。另外Object3D 还提供了几个方法来进行旋转,rotateX(angle),rotateY(angle),rotateZ(angle),分别是按照X,Y,Z轴的正反向旋转一个角度。但具体使用的时候和 object3D.rotation.y+=0.25*Math.PI 这种方式还是有一些区别的。另外还有一个方法是rotateOnAxis(axis,angle) 可以指定旋转的轴,这里的axis是一个Vector3类型的值。

2.矩阵

    three.js里的矩阵和之前介绍的不太一样,因为three.js里的矩阵式一个4x4的复合的矩阵(Transform Matrix),将位置信息放在了矩阵的最后一行。可以很容易的从这个矩阵里分解出旋转矩阵(Rotation Matrix),和位置矩阵(Translation Matrix)。Matrix4的主要方法有:

mutiply():矩阵的乘法。
transpose() :矩阵转置。
getInverse(m) :求逆矩阵。
makeRotationFromEuler(euler) :通过一个欧拉类型的值来设置矩阵的值。
makeRotationFromQuaternion(q):通过一个四元数类型的值来设置矩阵。
makeRotationonAxis(axis,theta):按一个轴旋转θ°,然后设置矩阵的值。
makeRotationonAxis(axis,theta) 的源码为:

 1 makeRotationAxis: function ( axis, angle ) {
 2     var c = Math.cos( angle );
 3      var s = Math.sin( angle );
 4     var t = 1 - c;
 5     var x = axis.x, y = axis.y, z = axis.z;
 6     var tx = t * x, ty = t * y;
 7     this.set(
 8         tx * x + c, tx * y - s * z, tx * z + s * y, 0,
 9         tx * y + s * z, ty * y + c, ty * z - s * x, 0,
10         tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
11         0, 0, 0, 1
12     );
13      return this;
14 }

通过源码,可以看出,调用这个方法就可以得到一个旋转矩阵了。然后,让物体的矩阵乘旋转矩阵就可以得到物体转动后的矩阵了。

下面是一段我使用旋转矩阵来旋转物体的代码。

function rotateAroundWorldAxis(object, axis, radians) {
    rotWorldMatrix = new THREE.Matrix4();
    rotWorldMatrix.makeRotationAxis(axis.normalize(), radians);
    rotWorldMatrix.multiply(object.matrix);                // pre-multiply
    object.matrix = rotWorldMatrix;
    object.rotation.setFromRotationMatrix(object.matrix);
}

通过这样的方法,就可以让物体沿参考系中的确定的一个轴进行旋转了。

3.四元数

没有使用四元数,所以没有研究,在object3D中设置rotation可以通过Matrix ,也可以通过Quaternion ,不过setFromRotationQuaternion的内部也是用的Matrix。

坐标体系:http://www.cnblogs.com/silent-stranger/p/6307372.html

三维空间旋转:https://www.cnblogs.com/silent-stranger/p/6027266.html

三维旋转矩阵:https://wenku.baidu.com/view/6dac0c22915f804d2b16c17c.html

参考资料

https://www.fastgraph.com/makegames/3drotation/

http://www.essentialmath.com/GDC2012/GDC2012_JMV_Rotations.pdf

http://www.gamedev.net/page/resources/_/technical/math-and-physics/do-we-really-need-quaternions-r1199

https://threejs.org/docs/

时间: 2024-10-04 14:26:08

Three.js 学习笔记(1)--坐标体系和旋转的相关文章

Vue.js学习笔记:在元素 和 template 中使用 v-if 指令

f 指令 语法比较简单,直接上代码: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title></title> <script src="https://cdn.bootcss.com/vue/2.2.

[Pro Angular.JS]学习笔记1.1:设置开发环境

可以使用yeoman.io,很方便.我已经写了一篇随笔,介绍如何使用.这里也有一篇介绍的文章:http://www.cnblogs.com/JoannaQ/p/3756281.html 代码编辑器,在Mac下用了一下WebStorm,太恶心了.另外发现书的作者使用的开发环境是Windows + VS Express 2013,为了方便学习,我也使用VS Express 2013 Update2.VS2013用起来蛮舒服的,把WebStorm比得跟驼屎一样.也许是因为我没用习惯吧. 1.安装Nod

【转】Backbone.js学习笔记(二)细说MVC

文章转自: http://segmentfault.com/a/1190000002666658 对于初学backbone.js的同学可以先参考我这篇文章:Backbone.js学习笔记(一) Backbone源码结构 1: (function() { 2: Backbone.Events // 自定义事件 3: Backbone.Model // 模型构造函数和原型扩展 4: Backbone.Collection // 集合构造函数和原型扩展 5: Backbone.Router // 路由

Maven学习笔记之——坐标和依赖(上)

Maven学习笔记之--坐标和依赖(上) 1.    Maven坐标概念 Maven通过构件的坐标来在Maven仓库中定位到具体的构件.Maven的坐标元素包括groupId.artifactId.versiion.packaging.classifier.Maven内置了一个中央仓库地址.需要时Maven会根据坐标到其中下载.具体关于中央仓库的介绍在后面. 2.    Maven坐标详解 比如下面一组坐标: <groupId>org.andy.items</groupId> &l

Angular JS 学习笔记

特定领域语言 编译器:遍历DOM来查找和它相关的属性, 分为编译和链接两个阶段, 指令:当关联的HTML结构进入编译阶段时应该执行的操作,可以写在名称里,属性里,css类名里:本质上是函数 稳定的DOM:绑定了数据模型的DOM元素的实例不会在绑定的生命周期发生改变 作用域:用来检测模型的改变和为表达式提供执行上下文的 AngularJS 和其它模板系统不同,它使用的是DOM而不是字符串 指令: 由某个属性.元素名称.css类名出现而导致的行为,或者说是DOM的变化 Filter过滤器:扮演着数据

Node.js学习笔记(3) - 简单的curd

这个算是不算完结的完结吧,前段时间也是看了好久的Node相关的东西,总想着去整理一下,可是当时也没有时间: 现在看来在整理的话,就有些混乱,自己也懒了,就没在整理,只是简单的记录一下 一.demo的简单介绍 这次demo,只涉及到简单的curd操作,用到的数据库是mongo,所以要安装mongo数据库,数据库连接驱动是mongoose: 当然关于mongo的驱动有很多,比如mongous mongoskin等:(详见http://cnodejs.org/topic/4f4ca8e0940ce2e

Maven学习笔记之——坐标和依赖(中)

Maven学习笔记之--坐标和依赖(中) 1.    传递性依赖 1.1    何为传递性依赖 项目中经常有引入一个jar包还要引入其他与其相关的jar包.自己搜的话要注意很多.比如版本问题等.而Maven会解析解析各个直接依赖的POM.将哪些必要的间接依赖以传递依赖的形式引入到项目中. 依赖范围不仅可以控制依赖与三种classpath关系.还对传递依赖产生影响. 假设A依赖B,B依赖C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖.第一直接依赖的范围和第二直接依赖

Maven学习笔记之——坐标和依赖(下)

Maven学习笔记之--坐标和依赖(下) 1.    最佳实践 归纳Maven依赖使用的常用技巧.方便用来避免和处理很多常见问题. 1.1.     排除依赖 传递性依赖会给项目隐式地引入很多依赖,这极大地简化了项目依赖的管理.但是有些时候这种特性也会带来问题.例如,当前项目有一个第三方依赖,而这个第三方依赖由于某些原因依赖了另外一个类库的SNAPSHOT版本,那么这个SNAPSHOT就会成为当前项目的传递性依赖,而SNAPSHOT的不稳定性会直接影响到当前的项目.这时候需要排除掉该SNAPSH

JS学习笔记-OO疑问之封装

封装是面向对象的基础,今天所要学习的匿名函数与闭包就是为了实现JS的面向对象封装.封装实现.封装变量,提高数据.系统安全性,封装正是面向对象的基础. 匿名函数 即没有名字的函数,其创建方式为 function(){...} 单独存在的匿名函数,无法运行,可通过赋值给变量调用或通过表达式自我执行来实现运行. 1.赋值给变量为一般的函数使用方式 var run = function(){ return '方法运行中'; }; alert(run()); 2.通过表达式自我执行 (function(a