本打算从 Object3D.js 入手,奈何发现其中好多基础的矩阵操作不明白,还是从基础的数学操作开始吧。

Math.js

该文件中基本上是一些简单数学运算的实现。

generateUUID()

蛮有趣的一个函数,用JS生成UUID,参考了StackOverflow上的回答:https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript/21963136#21963136。可见,如果想要优化JS的运行性能的话,还是有好多可以考虑的事情。最前边的那个 _lut 是LookUp Table的意思,也是为这个函数服务的。

euclideanModule(n, m)

第一次接触到这个东西,应该是对取余操作做了一个round操作?反正就是不会出现负值:

  1. THREE.Math.euclideanModulo(-3, 2)
  2. // 1
  3. -3 % 2
  4. // -1
  5. THREE.Math.euclideanModulo(-2, 2)
  6. // 0
  7. -2 % 2
  8. // -0

另外,这里关于JavaScript的+0和-0还是一个蛮有趣的点:https://stackoverflow.com/questions/7223359/are-0-and-0-the-same

isPowerOfTwo(val)

判断是不是2的幂次,值得稍微学习一下:

  1. ( value & ( value - 1 ) ) === 0 && value !== 0;

其它

其它的应该都比较直观,没有很多值得关注的地方:

  • clamp
  • mapLinear
  • lerp : 线性插值,这名字取得。。。
  • smoothstep , smootherstep :平滑的差值吧算是,挺常用的
  • randInt , randFloat , randFloatSpread
  • degToRad , radToDeg
  • ceilPowerOfTwo , floorPowerOfTwo

Vector2.js

就是个简单的长度为2的向量类,作为一个3D的库,这些基本数据结构还是要有的。

width, height

为类添加了width和height属性,并设置了setter和getter。不太清楚这个的具体作用,感觉有些鸡肋?可能会在某些场合用到并。

isVector2

Three基本上为每个类都有一个 isXXX 的属性,用来判断object的类型,感觉可以学习借鉴。

clone()

clone一个对象如何操作?学习了!

  1. clone: function () {
  2. return new this.constructor( this.x, this.y );
  3. },

addVectors(a, b)

它是设置了当前对象作为运算的接受者,那样的话,如果想从a,b创建一个新的vector,就得先new出来。
对于这样的实现,我不知道是设计者有意为之,还是受限于JS的语法?我感觉ES6的Class的static method更优雅的样子。

链式调用

可能这算是一种风格吧,虽然感觉这样改来改去的有时候会乱。调用的对象可能会改变,但是传入的对象不会改变,比如:

  1. lerpVectors: function ( v1, v2, alpha ) {
  2. return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
  3. },

rotateAround(center, angle)

二维的旋转矩阵:https://en.wikipedia.org/wiki/Rotation_matrix

Vector3.js

transformDirection(m)

仿射变换,y = Ax, 这里把向量当作方向,相当于变换到新空间中

projectOnVector(v)

复习一下向量投影的公式:https://en.wikipedia.org/wiki/Vector_projection
![](https://cdn.nlark.com/yuque/__latex/d0fef386cb522212b7c2c39f0048f8fa.svg#card=math&code=%7B%5Cdisplaystyle%20%5Cmathbf%20%7Ba%7D%20%7B1%7D%3D%7B%5Cfrac%20%7B%5Cmathbf%20%7Ba%7D%20%5Ccdot%20%5Cmathbf%20%7Bb%7D%20%7D%7B%5Cleft%5C%7C%5Cmathbf%20%7Bb%7D%20%5Cright%5C%7C%5E%7B2%7D%7D%7D%7B%5Cmathbf%20%7Bb%7D%20%7D%3D%7B%5Cfrac%20%7B%5Cmathbf%20%7Ba%7D%20%5Ccdot%20%5Cmathbf%20%7Bb%7D%20%7D%7B%5Cmathbf%20%7Bb%7D%20%5Ccdot%20%5Cmathbf%20%7Bb%7D%20%7D%7D%7B%5Cmathbf%20%7Bb%7D%20%7D.%7D&height=63&width=221)_

projectOnPlane(planeNormal)

原始向量-到法线到投影向量,就是到平面的投影向量了。

reflect(normal)

镜像向量的话,减去2倍的到法线投影向量就OK了,很优雅

setFromMatrixPosition(m)

指的是平移变换的分量:
Three.js 源码阅读 #1 Math, Vector, Matrix - 图1

setFromMatrixScale(m)

获取缩放变换的方法:每列的长度!平移和旋转都不改变前三列的向量长度。

Vector4.js

特别的地方不多,主要有两个地方。

setAxisAngleFromQuaternion(q)

AxisAngle是Three中对旋转呢的另一种表示方式,vector4的前三个分量表示旋转的Axis,最后一个是旋转的角度。
这里有相应的转换公式:http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm

setAxisAngleFromRotationMatrix(m)

也是将另一种表示旋转的方法表示成AxisAngle

Matrix3.js

矩阵这个数据结构在Three中相当重要,好多变换操作都离不开矩阵。

set(n11, n12, ...)

因为在矩阵运算中,如果是column-major的矩阵话,效率会高一点(虽然具体怎么高不太清楚,猜测是因为3D变换的一些矩阵运算用到的成列读取的更多吧)所以Three在内部实现中使用的是column-major的,但是在给用户的API中,为了照顾用户习惯,是row-major的方式排列参数顺序的,这一点需要注意。

premultiply(m)

左乘的意思,与 multiply(m) 刚好相反

transposeIntoArray(r)

这里相当于transpose然后存到数组中,其实意思就是按照row-major的方式存储为数组,而 toArray() 是按照column-major的方式(也就是内部存储的方式)。

getNormalMatrix(mat4)

  1. return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose();

normal matrix是个数学概念,指的是一个矩阵求逆之后,再求转置。具体的用法似乎在图形学里边用到挺多的。
https://paroj.github.io/gltut/Illumination/Tut09%20Normal%20Transformation.html
http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix/
啊 第一个教程说的太好了!!normal matrix,应该就是对法线应用的变换矩阵。
image.png
如图所示,如果只是对法线应用物体的变换的话,法线信息会错误(中间的图),我们更希望得到右边的图,然后经过一番推导,就可以得到这个normal matrix就是逆的转置。

setUvTransform(tx, ty, sx, sy, rotation, cx, cy)

UV坐标变换,实现可以借鉴一下,不过对于UV坐标自己还不是太熟悉,需要进一步学习。

scale , rotate , translate

有点奇怪,文档中并没有说明什么,应该deprecated了
git commit说是另一种设定贴图变换的API

Matrix4.js

Matrix4在Three中用到的应该更多,因为图形学里的变换都采用4x4的矩阵。

extractRotation

去除translate分量(最后一列)和scale分量(作归一化操作),就得到了rotation的变换

getInverse(m)

求逆的优化:http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm

makeRotation...()

旋转公式,绕固定轴以及任意轴

makeShear(x, y, z)

Shear变换的方程
https://www.tutorialspoint.com/computer_graphics/3d_transformation.htm
Three.js 源码阅读 #1 Math, Vector, Matrix - 图3

makePerspective(...)

生成透视投影矩阵
https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/building-basic-perspective-projection-matrix
https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/opengl-perspective-projection-matrix
Three.js 源码阅读 #1 Math, Vector, Matrix - 图4
具体推导自己有功夫再看,不过这个系列教程讲的似乎很可以,循序渐进!

makeOrthographic(...)

生成Orthographic的投影矩阵
https://en.wikipedia.org/wiki/Orthographic_projection
相比Perspective简单很多,主要是两个操作:

  • scale:归一化到-1,1的空间中
  • translate:将坐标中心移到原点