如何在不改变格式的情况下变换顶点?

时间:2015-05-14 17:47:17

标签: javascript webgl

如果我想在WebGL中更改对象的大小或位置,我会获取此对象的原始顶点数据{x,y,z}并将其传递给顶点着色器,并在其中与矩阵相乘,它保存有关转换的信息,产生一组新的坐标,这些坐标只有我的GPU知道,但对我来说是不可见的。

这是唯一可行的,就像唯一重要的是屏幕上的图片,但我希望能够保存变换后的顶点而不需要有关矩阵乘法的附加信息,只需要x,y,z值,就像原始数据一样。

我的想法是,最后一步是在JavaScript中将转换矩阵与我自己的原始顶点数据相乘,但我只是不能让它工作!

我编写了以下函数,通过添加第四个值{1.0}将4x4矩阵与x,y,z值数组相乘,将vec3数据更改为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;

}

...但除了我不知道如何将vec4值转换回vec3值之外,整个概念一定有问题:

假设我们有一个像

这样的简单三角形的顶点
var vertices = [0.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, -1.0, 0.0];

我们用

创建一个4x4矩阵
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;

}

翻译它 - 假设[0,0,-5] - 使用此函数

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;

}

最后使用上面提到的vertices函数将创建和翻译的矩阵与matrixVectorProduct中存储的顶点数据相乘,结果应为

translatedVertices = [0.0, 1.0, -5.0, -1.0, -1.0, -5.0, 1.0, -1.0, -5.0];

但它只是[x,y,z,1],因为-5 x 0.0(z值)等于0,所以它不能这样工作。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

你非常接近。我将从头开始实现它,仅用于案例。

让我们有一个带顶点的三角形简单模型:

var triangleVertices = [ 0.0,  1.0, 0.0, 
                        -1.0, -1.0, 0.0, 
                         1.0, -1.0, 0.0 ];

现在我们创建一个mat4,它代表在这个模型上完成的所有转换。没有变换由单位矩阵表示,它在对角线上全是0但是1。

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

我们准备进行翻译,轮换或缩放。在模型上应用它的最佳方法是创建另一个mat4,它将代表我们所需的变换,然后将模型矩阵与变换矩阵相乘。通过这种方式,我们可以通过几个矩阵运算以所需的顺序进行多次转换,而现在我们根本不需要打扰顶点。

所以让我们创建最简单的翻译矩阵。你从单位矩阵开始,你必须只更改mat [12,13,14],即x,y,z。

  

翻译它 - 让我们说[0,0,-5] - 使用这个函数

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 ];

转换矩阵已完成,我们希望将其与模型矩阵相乘。乘法矩阵是转换,任何转换。矩阵乘法的功能我现在已经完成了。它应该工作我希望:) 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

只是为了演示如何进行乘法,短代码:

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]

现在我们必须只进行顶点的最终转换。正如我所说,翻译是最容易的转换,所以我只会做翻译功能,this is related article from wiki

不要对这张照片感到困惑:enter image description here

这是OpenGL中使用的表示,但后来我们决定使用矩阵的转置版本,这对下面的图片操作简单:

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

结束注释

翻译功能:

function vec3TranslateMat4(vec, mat4) {
    vec[0] += mat4[12];
    vec[1] += mat4[13];
    vec[2] += mat4[14];
    return vec;
}

要转换三角形顶点,您必须执行以下操作:

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];
}

一旦我们应用了变换矩阵,我们应该再次将模型矩阵设置为单位矩阵。之后,我们可以在修改的顶点上进行新的转换。

我们完成了。 Personaly我使用gl matrix library已经包含了我需要的矩阵和向量的所有操作。

有和没有矩阵的转换

所有转换都可以在没有矩阵的情况下完成。但矩阵允许我们将当前位置保持在一个变量中,而无需立即变换顶点。顶点变换是漫长而耗时的。

另一个很好的理由是你只能使用几个核心功能,mat4Multiply和vec3TransformMat4(我没有告诉你这个)。了解如何在矩阵中集成旋转和比例(图像的左侧部分,右侧部分是相机)。

enter image description here