5
votes

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?

1
"I have no idea of how to convert the vec4-values back to vec3" you need to divide your vector by w, this is implicitly done within shaders.LJᛃ
@LJ_1102 Moin und danke für die Info! As Entity Black said, I will have to write separate functions each, for converting translation- / rotation- / scale-matrix-content to vertex-data though...user4512363
Well maybe I dont understand what you're aiming at, but you certainly do not need to decompose your matrix transforms to apply it to a vertex. Maybe have a look at the implementation of vec3.transformMat4(translation is applied in line 498). There is nothing "magically" happening within shaders except for that perspective divide for gl_Position.LJᛃ

1 Answers

3
votes

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:enter image description here

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:

http://upload.wikimedia.org/wikipedia/commons/thumb/e/e4/Matrix_transpose.gif/200px-Matrix_transpose.gif

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).

enter image description here