WebGL的;实例渲染 - 设置除数

时间:2016-08-06 12:34:39

标签: buffer webgl instance

我正在尝试使用实例化渲染(ANGLE_instanced_arrays)在webgl中绘制大量多维数据集。

然而,我似乎无法理解如何设置除数。我有以下缓冲区;

36个顶点(6个面由2个三角形构成,每个3个顶点使用3个顶点)。 每个立方体6种颜色(每个面1个)。 每个立方体1个翻译。

重用每个立方体的顶点;我把它的除数设为0。 对于颜色,我将除数设置为2(即对两个三角形使用相同的颜色 - 一个面))。 对于翻译,我将除数设置为12(即6个面的相同平移*每个面2个三角形)。

为了渲染我正在打电话 ext_angle.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 36, num_cubes);

然而,这似乎不会渲染我的立方体。

使用翻译除数1,但颜色偏离,立方体是单一的纯色。

我在想这是因为我的实例现在是完整的立方体,但是如果我限制count(即每个实例的顶点),我似乎并没有完全通过顶点缓冲区,实际上我那么每个立方体只渲染一个三角形。

我将如何渲染这样的大量多维数据集;有不同颜色的面孔?

1 个答案:

答案 0 :(得分:3)

Instancing就是这样的:

最终你要打电话

ext.drawArraysInstancedANGLE(mode, first, numVertices, numInstances);

因此,假设您正在绘制多维数据集的实例。一个立方体有36个顶点(每个面6个* 6个面)。所以

numVertices = 36

让我们说你要绘制100个立方体

numInstances = 100

假设你有一个像这样的顶点着色器

假设您有以下着色器

attribute vec4 position;

uniform mat4 matrix;

void main() {
  gl_Position = matrix * position;
}

如果你什么也没做,只是打电话

var mode = gl.TRIANGLES;
var first = 0;
var numVertices = 36
var numInstances = 100

ext.drawArraysInstancedANGLE(mode, first, numVertices, numInstances);

它只会在相同的位置绘制相同的立方体100次

接下来,您希望为每个多维数据集指定不同的翻译,以便将着色器更新为此

attribute vec4 position;
attribute vec3 translation;

uniform mat4 matrix;

void main() {
  gl_Position = matrix * (position + vec4(translation, 0));
}

现在你创建一个缓冲区并为每个多维数据集放置一个翻译,然后像普通

一样设置属性
gl.vertexAttribPointer(translationLocation, 3, gl.FLOAT, false, 0, 0)

但你也设置了一个除数

ext.vertexAttribDivisorANGLE(translationLocation, 1);

1表示'每个实例仅转换到翻译缓冲区中的下一个值'

现在,您希望每个立方体的每个面具有不同的颜色,并且您只希望数据中每个面具有一种颜色(您不想重复颜色)。 没有设置因为numVertices = 36你只能选择推进每个顶点(除数= 0)或每36个顶点的倍数(即numVertices)。

所以你说,如果实例面对而不是立方体怎么办?那么现在你遇到了相反的问题。每张脸上涂一种颜色。 numVertices = 6numInstances = 600(每个立方体100个立方体* 6个面)。将颜色的除数设置为1可使每个面部颜色前进一次。您可以将转换除数设置为6,每6个面(每6个实例)仅转换一次。但是现在你不再拥有一个只有一张脸的立方体。换句话说,你将以相同的方式绘制600张面孔,每6张面孔翻译成相同的位置。

要获得一个立方体,你必须添加一些东西来面向6个方向的面部实例。

好的,你填充了6个方向的缓冲区。那不行。你不能将除数设置为任何使用这6个方向的东西,每个面只前进一次,然后在下一个立方体的6个面后重置。只有一个除数设置。将其设置为6以重复每个面或36重复每个立方体,但您希望每个面前进重置每个立方体。没有这样的选择。

你可以做的是用6个绘制调用绘制它,每个面部方向一个。换句话说,你将绘制所有左脸,然后是所有右脸,所有顶面等......

为此,我们只制作1个面,每个立方体1个平移,每个立方体每个面1个颜色。我们将翻译的除数和颜色设置为1.

然后我们画6次,每次面部方向一次。每次绘制之间的差异是我们传递面部的方向,我们更改颜色属性的属性偏移,并将其步长设置为6 * 4浮动(6 * 4 * 4)。

var vs = `
attribute vec4 position;
attribute vec3 translation;
attribute vec4 color;

uniform mat4 viewProjectionMatrix;
uniform mat4 localMatrix;

varying vec4 v_color;

void main() {
  vec4 localPosition = localMatrix * position + vec4(translation, 0);
  gl_Position = viewProjectionMatrix * localPosition;
  v_color = color;
}
`;

var fs = `
precision mediump float;

varying vec4 v_color;

void main() {
  gl_FragColor = v_color;
}
`;

var m4 = twgl.m4;
var gl = document.querySelector("canvas").getContext("webgl");
var ext = gl.getExtension("ANGLE_instanced_arrays");
if (!ext) {
  alert("need ANGLE_instanced_arrays");
}
var program = twgl.createProgramFromSources(gl, [vs, fs]);

var positionLocation = gl.getAttribLocation(program, "position");
var translationLocation = gl.getAttribLocation(program, "translation");
var colorLocation = gl.getAttribLocation(program, "color");

var localMatrixLocation = gl.getUniformLocation(program, "localMatrix");
var viewProjectionMatrixLocation = gl.getUniformLocation(
    program, 
    "viewProjectionMatrix");

function r(min, max) {
  if (max === undefined) {
    max = min;
    min = 0;
  }
  return Math.random() * (max - min) + min;
}

function rp() {
  return r(-20, 20);
}

// make translations and colors, colors are separated by face
var numCubes = 1000;
var colors = [];
var translations = [];

for (var cube = 0; cube < numCubes; ++cube) {
  translations.push(rp(), rp(), rp());

  // pick a random color;
  var color = [r(1), r(1), r(1), 1];

  // now pick 4 similar colors for the faces of the cube
  // that way we can tell if the colors are correctly assigned
  // to each cube's faces.
  var channel = r(3) | 0;  // pick a channel 0 - 2 to randomly modify
  for (var face = 0; face < 6; ++face) {
    color[channel] = r(.7, 1);
    colors.push.apply(colors, color);
  }
}

var buffers = twgl.createBuffersFromArrays(gl, {
  position: [  // one face
    -1, -1, -1,
    -1,  1, -1,
     1, -1, -1,
     1, -1, -1,
    -1,  1, -1,
     1,  1, -1,
  ],
  color: colors, 
  translation: translations,
});

var faceMatrices = [
  m4.identity(),
  m4.rotationX(Math.PI /  2),
  m4.rotationX(Math.PI / -2),
  m4.rotationY(Math.PI /  2),
  m4.rotationY(Math.PI / -2),
  m4.rotationY(Math.PI),
];

function render(time) {
  time *= 0.001;

  twgl.resizeCanvasToDisplaySize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  
  gl.enable(gl.DEPTH_TEST);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  
  gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
  gl.enableVertexAttribArray(positionLocation);
  gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);

  gl.bindBuffer(gl.ARRAY_BUFFER, buffers.translation);
  gl.enableVertexAttribArray(translationLocation);
  gl.vertexAttribPointer(translationLocation, 3, gl.FLOAT, false, 0, 0);
  
  gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
  gl.enableVertexAttribArray(colorLocation);
  
  ext.vertexAttribDivisorANGLE(positionLocation, 0);
  ext.vertexAttribDivisorANGLE(translationLocation, 1);
  ext.vertexAttribDivisorANGLE(colorLocation, 1);

  gl.useProgram(program);
  
  var fov = 60;
  var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  var projection = m4.perspective(fov * Math.PI / 180, aspect, 0.5, 100);
  
  var radius = 30;
  var eye = [
    Math.cos(time) * radius, 
    Math.sin(time * 0.3) * radius, 
    Math.sin(time) * radius,
  ];
  var target = [0, 0, 0];
  var up = [0, 1, 0];

  var camera = m4.lookAt(eye, target, up);
  var view = m4.inverse(camera);
  var viewProjection = m4.multiply(projection, view); 
  
  gl.uniformMatrix4fv(viewProjectionMatrixLocation, false, viewProjection);

  // 6 faces * 4 floats per color * 4 bytes per float
  var stride = 6 * 4 * 4;  
  var numVertices = 6; 
  faceMatrices.forEach(function(faceMatrix, ndx) {
    var offset = ndx * 4 * 4;  // 4 floats per color * 4 floats
    gl.vertexAttribPointer(
       colorLocation, 4, gl.FLOAT, false, stride, offset);
    gl.uniformMatrix4fv(localMatrixLocation, false, faceMatrix);
    ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, numVertices, numCubes);
  });
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/2.x/twgl-full.min.js"></script>
<canvas></canvas>