Reputation:
If I want to change the size or position of an object in WebGL, I take the original vertex-data {x,y,z} of this object and pass it to the vertex-shader, where it's multiplied with a matrix, that holds the information about the transformations, resulting in a new set of coordinates, which is only known to my GPU, but invisible for me.
That works fine, as far as the only thing that counts, is the picture on the screen, but I want to be able to save the transformed vertices without additional information about matrix multiplications, simply as x,y,z-values, just like the original data.
The idea was, to take the final step of multiplying the transformation-matrix with the original vertex-data by my own in JavaScript, but I just don't get it working!
I wrote the following function to multiply a 4x4-matrix with an array of x,y,z-values, by adding a fourth value {1.0} to change the vec3-data into vec4-data...
function matrixVectorProduct (mat4, data) {
var result = new Array( );
for (var i = 0; i < data.length / 3; i++) {
var n = i * 3;
var vec4 = [data[n], data[n + 1], data[n + 2], 1.0];
var x = mat4[0] * vec4[0] + mat4[1] * vec4[1] +
mat4[2] * vec4[2] + mat4[3] * vec4[3];
var y = mat4[4] * vec4[0] + mat4[5] * vec4[1] +
mat4[6] * vec4[2] + mat4[7] * vec4[3];
var z = mat4[8] * vec4[0] + mat4[9] * vec4[1] +
mat4[10] * vec4[2] + mat4[11] * vec4[3];
var w = mat4[12] * vec4[0] + mat4[13] * vec4[1] +
mat4[14] * vec4[2] + mat4[15] * vec4[3];
result.push(x, y, z, w);
}
return result;
}
...but beside the fact that I have no idea of how to convert the vec4-values back to vec3-values, there must be something wrong with the concept as a whole:
Let's suppose we have the vertices for a simple triangle like
var vertices = [0.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, -1.0, 0.0];
and we create a 4x4-matrix with
function createMat4 ( ) {
var mat4 = new Float32Array(16);
mat4[0] = 1; mat4[1] = 0; mat4[2] = 0; mat4[3] = 0;
mat4[4] = 0; mat4[5] = 1; mat4[6] = 0; mat4[7] = 0;
mat4[8] = 0; mat4[9] = 0; mat4[10] = 1; mat4[11] = 0;
mat4[12] = 0; mat4[13] = 0; mat4[14] = 0; mat4[15] = 1;
return mat4;
}
translate it by - let's say [0, 0, -5] - using this function
function translateMat4 (mat4, vec3) {
var x = vec3[0],
y = vec3[1],
z = vec3[2];
var a = mat4;
mat4[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
mat4[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
mat4[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
mat4[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
return mat4;
}
and finally multiply the created and translated matrix with the vertex-data stored in vertices
by using the matrixVectorProduct
-function noted above, the result should be
translatedVertices = [0.0, 1.0, -5.0, -1.0, -1.0, -5.0, 1.0, -1.0, -5.0];
but it is just [x,y,z,1], because -5 x 0.0 (z-value) equals 0, so it cannot work this way.
What am I doing wrong?
Upvotes: 5
Views: 1623
Reputation: 3491
You are very close. I will implement it from start, just for case.
Lets have a simple model of triangle with vertices:
var triangleVertices = [ 0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0 ];
Now we create a mat4 which represent all transformations done on this model. No transformation is represented by identity matrix wich is all 0 but 1 on diagonal.
var identityMatrix = [ 1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 ];
var modelMatrix = identityMatrix.slice(0); // slice = clone the array
We are ready to do translations, rotations or scale. Best way to apply it on the model is to create another mat4 wich will represent our desired transformation, then multiply model matrix with transformation matrix. This way we can do multiple transformations in desired order with just few matrix operations and we dont have to bother with vertices at all for now.
So lets create translation matrix wich is the most easy. You start with identity matrix and you must change only mat[12, 13, 14] which is x, y, z.
translate it by - let's say [0, 0, -5] - using this function
var translate = [ 1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0,-5.0, 1.0 ];
Transformation matrix is done and we want to multiply it with our model matrix. Multipling matrices is the transformation, any transformation. Function for matrix multiplication I have done right now. It should work I hope :) Math source from wiki.
var mat4Multiply = (function () {
function ABProduct(i, j, a, b) {
var k, sum = 0;
for (k = 0; k < 4; k++) {
sum += a[i * 4 + k] * b[j + k * 4];
}
return sum;
}
function mat4Multiply(a, b) {
var i, j, product = [];
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
product[i * 4 + j] = ABProduct(i, j, a, b);
}
}
return product;
}
return mat4Multiply;
})();
// a = model matrix, b = transformation
Just to demonstrate how to do the multiplication, short code:
modelMatrix = mat4Multiply(modelMatrix, translate);
// but now I change my mind and I want to move model again by another 3 in Z
translate = [ 1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 3.0, 1.0 ];
modelMatrix = mat4Multiply(modelMatrix, translate);
// after this content of the modelMatrix is:
// [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -2, 1]
Now we must only do the final transformation of vertices. As I said, translation is the most easy transformation so I will do only translation function, this is related article from wiki.
NOTE
Dont get confused by this picture:
This was the representation used in OpenGL but later we decided to use transposed version of the matrix, wich is simple operation on following picture:
END NOTE
Translation function:
function vec3TranslateMat4(vec, mat4) {
vec[0] += mat4[12];
vec[1] += mat4[13];
vec[2] += mat4[14];
return vec;
}
To translate triangle vertices you must only do:
var i, vertex;
for(i=0;i<triangleVertices.length;i+=3) {
vertex = triangleVertices.slice(i, i+3);
vertex = vec3TranslateMat4(vertex, modelMatrix)
triangleVertices[i] = vertex[0];
triangleVertices[i+1] = vertex[1];
triangleVertices[i+2] = vertex[2];
}
Once we applied transformation matrix, we should set model matrix to identity matrix again. After that, we can do new transformations but on modified vertices.
And we are done. Personaly I use gl matrix library which already contains all the operations for matrices and vectors I need.
Transformations with and without matrices
All the transformations could be done also without matrices. But matrix allow us to keep current location in one variable without need to transform vertices immediately. Vertex transformations are long and time consuming.
Another good reason is you can go with only few core functions, mat4Multiply and vec3TransformMat4 (I didnt show you this one). See how is rotation and scale integrated in the matrix (left part of the image, right part is about camera).
Upvotes: 3