我正在尝试使用实例化渲染(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
(即每个实例的顶点),我似乎并没有完全通过顶点缓冲区,实际上我那么每个立方体只渲染一个三角形。
我将如何渲染这样的大量多维数据集;有不同颜色的面孔?
答案 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 = 6
,numInstances = 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>