尝试使用“属性mat4”而不是“属性制服”

时间:2018-10-30 19:11:19

标签: javascript webgl

我有这个变量'xformMatrix',每个元素都包含16个值的数组:

var xformMatrix = 
[[0.9238795325112867, 0.3826834323650898, 0.0,
  -0.3826834323650898, 0.9238795325112867, 0.0, 0.0,
  0.0, 0.0, 1.0, 0.0,
  0.0, 0.0, 0.0, 1.0],
 [0.7071067811865476, 0.7071067811865475, 0.0, 0.0,
  -0.7071067811865475, 0.7071067811865476, 0.0, 0.0,
  0.0, 0.0, 1.0, 0.0,
  0.0, 0.0, 0.0, 1.0],
 [0.38268343236508984, 0.9238795325112867, 0.0, 0.0,
  -0.9238795325112867, 0.38268343236508984, 0.0, 0.0,
  0.0, 0.0, 1.0, 0.0,
  0.0, 0.0, 0.0, 1.0],
 [6.123233995736766e-17, 1, 0.0, 0.0,
  -1, 6.123233995736766e-17, 0.0, 0.0,
  0.0, 0.0, 1.0, 0.0,
  0.0, 0.0, 0.0, 1.0]]

我正在尝试使用4x4矩阵作为属性来旋转我的三角形,而不必填充其顶点数组。我相信我对gl.vertexAttribPointer要求的尺寸感到困惑:

gl.vertexAttribPointer(a_xformMatrix, 1, gl.FLOAT, false, 6 * 
Float32Array.BYTES_PER_ELEMENT, 5 * Float32Array.BYTES_PER_ELEMENT);

这是我的着色器的设置方式:

var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute mat4 a_xformMatrix;\n' +
  'attribute vec3 a_Color;\n' +
  'varying vec3 v_Color;\n' +
  'void main() {\n' +
  '  v_Color = a_Color;\n' +
  '  gl_Position = a_xformMatrix * a_Position;\n' +
  '}\n';

// Fragment shader program
var FSHADER_SOURCE =
  'precision mediump float;\n' +
  'varying vec3 v_Color;\n' +
  'void main() {\n' +
  '  gl_FragColor = vec4(v_Color, 1.0);\n' +
  '}\n';

我的功能示例:

function initVertexBuffers(gl) {

  // Triangle Verticies
  var vertices = new Float32Array(
  [ // x, y             r, g, b             rotate matrix
    0.0, 0.5,           1.0, 0.0, 0.0,      xformMatrix[0],
    -0.5, -0.5,         1.0, 0.0, 0.0,      xformMatrix[0],
    0.5, -0.5,          1.0, 0.0, 0.0,      xformMatrix[0],
    0.0, 0.5,           0.0, 1.0, 0.0,      xformMatrix[1],
    -0.5, -0.5,         0.0, 1.0, 0.0,      xformMatrix[1],
    0.5, -0.5,          0.0, 1.0, 0.0,      xformMatrix[1],
    0.0, 0.5,           0.0, 0.0, 1.0,      xformMatrix[2],
    -0.5, -0.5,         0.0, 0.0, 1.0,      xformMatrix[2],
    0.5, -0.5,          0.0, 0.0, 1.0,      xformMatrix[2],
    0.0, 0.5,           1.0, 0.0, 1.0,      xformMatrix[3],
    -0.5, -0.5,         1.0, 0.0, 1.0,      xformMatrix[3],
    0.5, -0.5,          1.0, 0.0, 1.0,      xformMatrix[3]
  ]);

  var n = 12; // The number of vertices

  // Create a buffer object
  var vertexBuffer = gl.createBuffer();
  if (!vertexBuffer) {
    console.log('Failed to create the buffer object');
    return false;
  }

  // Bind the buffer object to target
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  // Write date into the buffer object
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  // Assign the buffer object to the position attribute variable
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  if (a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return -1;
  }
  // Assign the buffer object to the color attribute variable
  var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
  if (a_Color < 0) {
    console.log('Failed to get the storage location of a_Color');
    return -1;
  }
  // Assign the buffer object to the rotation matrix attribute variable
  var a_xformMatrix = gl.getAttribLocation(gl.program, 'a_xformMatrix');
  if (a_xformMatrix < 0) {
    console.log('Failed to get the storage location of a_xformMatrix');
    return -1;
  }

  // Set Pointers
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 6 * Float32Array.BYTES_PER_ELEMENT, 0);
  gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 6 * Float32Array.BYTES_PER_ELEMENT, 2 * Float32Array.BYTES_PER_ELEMENT);
  gl.vertexAttribPointer(a_xformMatrix, 1, gl.FLOAT, false, 6 * Float32Array.BYTES_PER_ELEMENT, 5 * Float32Array.BYTES_PER_ELEMENT);

  // Enable the assignment to a_Position variable
  gl.enableVertexAttribArray(a_Position);
  gl.enableVertexAttribArray(a_Color);
  gl.enableVertexAttribArray(a_xformMatrix);

  return n;
}

最终输出应如下所示:

Output

这样做有技巧吗?还是我走错了方向?

1 个答案:

答案 0 :(得分:0)

您在做什么并不常见

您有x,y,r,g,b,m [0],m [1],m [2],m [3],m [4],m [5],m [6 ],m [7],m [8],m [9],m [10],m [11],m [12],m [13],m [14],m [15]每个顶点大步前进,因为您要尝试将所有数据放在同一个缓冲区中,所以

 21 * Float32Array.BYTES_PER_ELEMENT

然后您需要为mat4设置4个属性,每个属性的大小为4(4个属性,每个大小4 =矩阵的16个值)

  // Set Pointers
  const stride = 21 * Float32Array.BYTES_PER_ELEMENT;
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, stride, 0);
  gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, stride, 2 * Float32Array.BYTES_PER_ELEMENT);
  gl.vertexAttribPointer(a_xformMatrix + 0, 4, gl.FLOAT, false, stride, 5 * Float32Array.BYTES_PER_ELEMENT);
  gl.vertexAttribPointer(a_xformMatrix + 1, 4, gl.FLOAT, false, stride, 9 * Float32Array.BYTES_PER_ELEMENT);
  gl.vertexAttribPointer(a_xformMatrix + 2, 4, gl.FLOAT, false, stride, 13 * Float32Array.BYTES_PER_ELEMENT);
  gl.vertexAttribPointer(a_xformMatrix + 3, 4, gl.FLOAT, false, stride, 17 * Float32Array.BYTES_PER_ELEMENT);

此外,此代码还没有将矩阵数据放入Float32Array中。您可以编写一些代码来合并数据,或者如果您想手工完成

  var vertices = new Float32Array(
  [ // x, y             r, g, b             rotate matrix
    0.0, 0.5,           1.0, 0.0, 0.0,      
    xformMatrix[0][0], xformMatrix[0][1], xformMatrix[0][2], xformMatrix[0][3],
    xformMatrix[0][4], xformMatrix[0][5], xformMatrix[0][6], xformMatrix[0][7],
    xformMatrix[0][8], xformMatrix[0][9], xformMatrix[0][10], xformMatrix[0][11],
    xformMatrix[0][12], xformMatrix[0][13], xformMatrix[0][14], xformMatrix[0][15],
    ... repeat for the next vertex .. 
  ]);

请注意,如果您的代码可以工作,我不会费心检查是否进行了所有这些更改。最明显的问题就是基于您所说的那样。

您可能会发现,如果采用这种方式,尝试旋转三角形时您将要更新大量数据,因此您可能希望找到其他方法。

签出these tutorials。第一篇文章绘制了一堆不同颜色的矩形。它对每种颜色使用一次绘制调用,这是最常见的方法。然后在下面的文章中建立使用矩阵的方法。

您还可以仅传递每个三角形的旋转并在着色器中计算旋转。这样,每个顶点的每个三角形只有一个旋转值,而不是每个顶点的每个矩阵都有一个旋转值。您必须为每个三角形更新3个旋转以对其进行动画处理。

您还可以间接地通过纹理,因此,每个顶点每个三角形都有一个三角形ID,而不是每个顶点每个三角形都有一个旋转。因此,前3个顶点的ID = 0,后3个ID = 1,依此类推。将其作为属性传递,然后可以像rotation = ID * constant中那样使用它生成旋转,或者可以使用该ID查找如rotation = texture2D(textureWithRotationData, vec2((id + .5) / textureWidth, 0.5).r中的纹理旋转。这种方法的优点是您只需要更新每个三角形1圈。纹理中的一个。