· Create the world is committed to creating the first “cloud CAD” collaborative design platform integrating viewing, modeling, assembly and rendering in China.
At the request of readers, we hope to set up a professional WEBGL and Threejs industry QQ communication group for front-end developers in Chengdu-Chongqing area to facilitate discussion. There are webGL and Threejs in the group, welcome to join! — Click the link to join the group chat [three.js/ webGL Chongqing Union Group] : jq.qq.com/?_wv=1027&k…
The authors introduce
Qingqing Xia, r&d engineer of large front end of Cloud Map, is responsible for the development of 3d front end of cloud map.
The body of the
Many beginners, the understanding of ThreeJS matrix application is relatively fuzzy, such as the author. When the author just started to contact ThreeJS, he was immediately infused with many basic theories of computer graphics, including matrix transformation. In the process, the author had several questions about matrix transformation in his mind:
1. What is a matrix? 2. What is the use of matrices? 3. Why use a 4 by 4 matrix?
Believe that beginners understand these three problems, you can understand the application of ThreeJS matrix, the following for these three problems are discussed.
What exactly is a matrix?
The first sentence of Baidu Encyclopedia reads:
In mathematics, a Matrix is a set of complex numbers or real numbers arranged according to a rectangular array. It originated from the square Matrix composed of coefficients and constants of equations.
I took a look at the API of Object3D, the core base class of ThreeJS documentation.
The API documentation mentions the word Matrix several times. So far, we know that matrices are collections of data that are used a lot in ThreeJS. But out of curiosity, I tried the following code in the JS file:
import {Object3D} from "three"; ...const obj = new Object3D();
console.log(obj);
Copy the code
The screenshot of the result is as follows:
As can be seen here, every instance object generated by Object3D New has a property called matrix, and normally the initial value is the same as the above, which contains an array of length 16. Many beginners may wonder: What does the array element in the Martix attribute represent? Let’s leave that question open and move on to the next question.
What is the use of matrices?
Before we do that, let’s think about a question: How do we shift a line segment in three dimensions? The idea is not difficult. A line segment consists of two endpoints. We can achieve translation by adding each component (x,y,z) of the coordinates of the two endpoints and the translation distance on the corresponding axis. The following is the pseudo-code to achieve the idea for reference only.
/ * * *@description Shift the line segment * by adding the shift component of (x,y,z)@param {LineSegments} Line Instance of the line segment *@param {number} DeltaX the translation component on the x axis *@param {number} Delta tay the translation component on the y axis *@param {number} DeltaZ the translation component on the z-axis **/
function translationLine(line:LineSegments,deltaX:number,deltaY:number,deltaZ:number) :void{
const pastPoints:Float32Array[] = line.geometry.attributes.instanceStart.data.array;// Two dots, array length 6
const points:Vector3[]=[]
points.push( new THREE.Vector3( pastPoints[0]+deltaX, pastPoints[1]+deltaY, pastPoints[2]+deltaZ ) );
points.push( new THREE.Vector3( pastPoints[3]+deltaX, pastPoints[4]+deltaY, pastPoints[5]+deltaZ ) );
line.geometry.setFromPoints( points );
}
Copy the code
Isn’t that easy? Now let’s look at another transformation, rotation.
As shown in the figure above, line segment OP1 overlaps with OP2 after being rotated by β degrees clockwise along the Z-axis. First simulate a junior high school math problem. Given the coordinates of P1 (x1,y1,z1) and the rotation Angle β, find the coordinates of P2 after rotation (x2,y2,z2). We first assume that the length of OP1 is L, and the included Angle between OP1 and Y-axis is α, then we can first obtain the coordinates of P1 according to the trigonometric function formula:
X1 is equal to L sine alpha y1 is equal to L cosine alpha z1 is equal to 0
Also according to the trigonometric formula, we can continue to calculate the specific coordinates of P2:
X2 = L·sin(α + β) y2 = L·cos(α + β) z2 = 0
P2 is represented, but there are two hypothetical unknowns, L and α. What can we do? Don’t worry, keep going down. We get the following formula from the Angle sum difference formula.
X2 = l. sin (alpha + beta) = l. (sine alpha cos beta + cosine alpha, sine beta) y2 = l. cos (alpha + beta) = l. (cosine alpha cos beta sin sin, alpha, beta) z2 = 0
And then you plug P1 into P2, and you get
X2 = l. (sine alpha cos beta + cosine alpha, sine beta) = cosine beta, x1 + sin, beta y1, y2 = l. (cosine alpha cos beta sin sin, alpha, beta) = cosine beta, y1 – sine beta, x1 z2 = 0
We convert the above mathematical expression into ThreeJS pseudocode:
function rotateLine(line:LineSegments,angle){
const pastPoints:Float32Array[] = line.geometry.attributes.instanceStart.data.array;// Two dots, array length 6
const points:Vector3[]=[]
points.push( new THREE.Vector3(Math.cos(angle)*pastPoints[0] +Math.sin(angle)*pastPoints[1].Math.cos(angle)*pastPoints[1] -Math.sin(angle)*pastPoints[0].0)); points.push(new THREE.Vector3(Math.cos(angle)*pastPoints[3] +Math.sin(angle)*pastPoints[4].Math.cos(angle)*pastPoints[4] -Math.sin(angle)*pastPoints[3].0 ));
line.geometry.setFromPoints( points );
}
Copy the code
Readers may notice something is wrong here — I see the problem, but… So aren’t you talking about the use of matrices in ThreeJS? Why look at it look at it I realize that none of your examples have anything to do with matrices.
Don’t worry. Here’s the explanation. This is just a primer. Theoretically, we can really achieve translation, rotation, scaling, etc by a mathematical formula transformation, but the reality is likely to be very complex, using a mathematical expression for computing will be quite tedious, if using the above method to in the threeJS translations or rotations, once has the superposition of multiple rotation or translation, The resulting code is not only less elegant, but also less efficient to execute.
Therefore, in reality, matrices (rectangular arrays of m by N scalars) are often used to represent linear transformations such as translation, rotation, and scaling. But A more interesting fact is that when the product of two transformation matrices A and B is P=AB, then the transformation matrix P corresponds to the transformation represented by A and B. For example, if A is A rotation matrix and B is A translation matrix, then the matrix P can perform rotation and translation transformations. Note, however, that matrix multiplication does not obey the commutative law, so AB and BA are not equal. Next, we try to represent the above rotation with a 3 by 3 matrix. First, let’s look at a matrix multiplied by a three-dimensional vector:
You can see that the matrix is a 3 by 3 matrix, and the right side of the matrix is the coordinate of point P1, and the left side of the matrix is the coordinate of point P2. According to this expression, we can get the following formula:
X2 = a·x1 + b·y1 + c·z1 y2 = d·x1 + E ·y1 + f·z1 z2 = g·x1 + h·y1 + I ·z1
To relate the matrix equation to the mathematical expression in the previous section, let’s compare the rotation expression with this matrix equation.
X2 is equal to a times x1 plus b times y1 plus c times z1 and x2 is equal to cosine beta times x1 plus sin beta times y1
Y2 is equal to d times x1 plus e times y1 plus f times z1. Y2 is equal to cosine beta times y1 minus sin beta times x1
Z2 is equal to g times x1 plus h times y1 plus I times z1 and z2 is equal to 0
By comparing x2, we can find that a=cosβ, b=sinβ, c=0; D =-sinβ, e=cosβ, f=0; Finally, by comparing z2, it can be determined that g=0, H =0, I =1; Substituting this into the previous matrix, our equation would look something like this:
With this 3 by 3 transformation matrix, we have achieved rotation transformation in three dimensions, and obviously if this 3 by 3 matrix is really the perfect solution to transformation, then obviously it must also be suitable for other transformations, such as translation. But does it really satisfy the need for translation? Now let’s try to find the answer by comparing matrix equations with mathematical expressions.
X2 = a·x1 + b·y1 + c·z1 x2 = x1 + δ x
Y2 is equal to d times x1 plus e times y1 plus f times z1. Y2 is equal to y1 plus delta y
Z2 = g·x1 + h·y1 + I ·z1 and z2 = z1 + δ z
An interesting difference between a translation and a rotation is that there is a constant δ x in the translation expression, whereas there is no such constant in either the rotation expression or the matrix equation. So the problem is, we can’t use a 3 by 3 matrix to represent a shift. How to solve this problem? This brings us to our third question.
Why use a 4 by 4 matrix?
To solve the problem of multiplying a three-dimensional vector by a 4×4 matrix, we cleverly add a fourth component to the three-dimensional vector, so that the previous three-dimensional vector (x,y,z) becomes a four-dimensional vector (x,y,z,w), and a vector composed of four components is called a homogeneous coordinate. It should be noted that the homogeneous coordinate (x,y,z,w) is equivalent to the three-dimensional coordinate (x/w,y/w,z/w). Therefore, as long as the value of w component is 1, the homogeneous coordinate can be used as the three-dimensional coordinate, and the coordinate represented is the point with x,y,z as the coordinate value. So, in order to multiply by a 4 by 4 matrix, our P1 coordinates become x1,y1,z1,1. And the matrix equation looks like this:
Let’s compare this new matrix equation with the mathematical expression for transformation:
X2 = a·x1 + b·y1 + C ·z1 + d x2 = x1 + δ x
Y2 = e·x1 + f·y1 + g·z1 + h y2 = y1 + delta y
Z2 = I ·x1 + j·y1 + K ·z1 + L Z2 = Z1 + δ z
1 is m times x1 plus n times y1 plus o times z1 plus p
By comparing x2, we can find that a=1, b=0, C =0, d= δ x; Compared with y2, it can also be found that e=0, F =1, g=0, h= δ y; By comparing z2, it can be determined that I =0, j=0, k=1, l= δ z; M =0, n=0, o=0, p=1; In this way, we have solved our 4-by-4 translation matrix:
At this point, we return to our underlined question — what do array elements in the Martix attribute (matrix) represent in Object3D? Let’s take this 16 length array and turn it into a 4 by 4 matrix. By contrast with the 4×4 matrix mentioned above, it can be concluded that:
δ x = 0 δ y = 0 δ z = 0 w = 1
Found no? This is an original matrix that hasn’t been transformed.
conclusion
Finally, let’s go back to three.js and conclude.
- A matrix is a collection of data.
- In ThreeJS, matrices are used to record the transformation of objects (translation, rotation, scaling).
- The 4×4 matrix is used to solve the consistency of data format of translation transformation and other transformation matrices in 3d coordinate system.