In our project, we use right-hand cartesian coordinates.
However, in computer graphics, we prefer 3D Homogeneous coordinates. This system allows for the representation of points at infinity and simplified equations involving linear transformations. In 3D, a points will represented by a 4 element vector(vec4) [x,y,z,w]T.
The primary benefit of using homogeneous coordinates is that they enable affine transformations (translation, rotation, scaling) and perspective projections to be represented as matrix multiplications. This unifies the handling of different geometric transformations and simplifies the implementation of these operations in computer graphics algorithms. The w does not have a direct physical meaning like x,y,z, its more playing a mathematical role. It is indispensable for the computational and conceptual framework that underpins projective geometry, enabling the representation and manipulation of geometric information in ways that are not possible with only Cartesian coordinates.
Point & Vector
We use vec4 to represent points. In rust, we can use nalgebra-glm, its based on nalgebra, but all APIs are translated in form of GLM in C++. So we can focus on CG math instead of entire Abstract Algebra.
To create a point, its very simple (Note, in our GLM, vectors are COLUMN_MAJOR)
let origin_vec:Vec4 = Vec4::new(0f32,0f32,0f32,1f32);
v=0001
In fact, a point is no different with vector, however, we would love to use Vec4[a,b,c,0].
For a point, we are concerned with its coordinate position. However, for a vector, it represents a direction; therefore, a vector does not have a fixed start and end point. We are interested in its direction and magnitude, which often leads to it being decomposed into a unit vectorv^ representing direction (or coefficients of three orthogonal unit vectors) and its magnitude Scala∣∣v∣∣.
Addition, Subtraction, Dot Product, Cross Product and Magnitude & Normalize. The last two is reflection and refraction, its too complicated so we just need to know they are exist.
let v1:Vec3 = vec3(1.0, 2.0, 3.0);
let v2:Vec3 = vec3(4.0, 5.0, 6.0);
let add = v1+v2;
let sub = v1-v2;
let mult = v1 * 2f32;
let dot = dot(&v1, &v2);
let cross = cross(&v1, &v2);
let mag = magnitude(&v1);
let norm = normalize(&v1);
Vector add or subtract Vector is still a Vector. But when vector's dot product is a Scala, as we show before: a⋅b=[a1a2a3a4]⋅b1b2b3b4=a1b1+a2b2+a3b3+a4b4 We can obtain the angle between two vectors by calculating their dot product. a⋅b=∣∣a∣∣∣b∣∣cosθcosθ=a^⋅b^θ=arccos(a^⋅b^) Vector dot production satisfies the commutative law, associative law, and distributive law. a⋅b=b⋅aa⋅(b+c)=a⋅b+a⋅cka⋅b=a⋅kb=k(a⋅b)
With dot production, we can do Projection (Decomposition) in CG by Gram–Schmidt process:
b⊥a=∣∣b_⊥a∣∣a^=∣∣b∣∣a^cosθ=(∥a∥2b⋅a)a
Therefore, we can also decompose any vector into the sum of three orthogonal unit vectors x, y, and z.
p=(p⋅x)x+(p⋅y)y+(p⋅z)z
Through the result of the dot product, we can also determine the relative direction of two vectors. For example, a dot product equal to 0 means orthogonal, a dot product greater than 0 indicates the same direction, and conversely, a negative dot product indicates opposite directions.
Cross Production
The cross product of vectors a and b results in a new vector c, which is orthogonal to the plane defined by a and b, and is known as the normal vector. It's important to note that the order of the cross product determines the direction of the normal vector, and this calculation follows the right-hand rule. a×b=A∗b=0a3−a2−a30a1a2−a10b1b2b3=−a3b2+a2b3a3b1−a1b3−a2b1+a1b2∣∣a×b∣∣=∣∣a∣∣∣∣b∣∣sinθ The commutative law, associative law, and distributive law will be slightly different. Note, in a×a=0, the 0 is still a zero-magnitude vector, not a scalar. a×b=−b×aa×a=0a×(b+c)=a×b+a×cka×b=a×kb=k(a×b) Do you remember what we said about the right-hand coordinate system? Regarding how to define a right-hand coordinate system, it satisfies the condition that the unit orthogonal vectors x cross y equals z, which defines the right-hand coordinate system. x×y=z Similar to the dot product, through the cross product of two vectors a and b, we can determine on which side of a, vector b, lies. For example, when greater than 0, b, is in the counter clockwise direction of a, (left side), and when less than 0, b, is in the clockwise direction of a,(right side). Through this operation, we can determine whether a point P is inside a polygon. We consider the polygon as a series of vectors connected head to tail, and cross each with a vector from a point to P. If all the cross product results have the same sign, this indicates that the point is inside the polygon.
Matrix
We use mat4 to represent a matrix. To generate a unit matrix:
let unit_mat:Mat4 = Mat4::identity();
I=1000010000100001
Matrix transpose (Note, in OpenGL and GLM, mats are COLUMN_MAJOR):