twgl.js: как использовать упакованный массив вершин через BufferInfo
Я использую twgl.js ( http://twgljs.org/) в проекте webgl, его очень приятно использовать, но я хочу оптимизировать мой код для использования упакованных массивов вершин. Однако я не могу понять, как это работает в twgl, я вижу, что есть некоторые варианты шага и смещения в нем, но нет дополнительной информации о том, как именно они будут себя вести. Я прочитал код, но от этого у меня возникло ощущение, что он не позволит мне использовать один вызов для createBufferInfoFromArrays, но потребует много больше от руки. Можно ли настроить упакованные массивы с помощью twgl.js? Как?
1 ответ
Короткий ответ: "Да, это потребует гораздо большего количества сантехники", или, скорее, вам нужно упаковать данные. Вы можете легко сделать свой собственный BufferInfo
var packedBuffer = twgl.createBufferFromTypedArray(
gl, typedArrayWithPackedData);
var indexBuffer = twgl.createBufferFromTypedArray(
gl, typedArrayWithIndices, gl.ELEMENT_ARRAY_BUFFER);
var stride = 36; // position + normal + texcoord + rgba8
var handMadeBufferInfo = {
numElements: 123, // or whatever
indices: indexBuffer, // remove if no indices
elementType: gl.UNSIGNED_SHORT, // remove if no indices
attribs: {
position: { buffer: packedBuffer, numComponents: 3, type: gl.FLOAT, stride: stride, offset: 0, },
normal: { buffer: packedBuffer, numComponents: 3, type: gl.FLOAT, stride: stride, offset: 12, },
texcoord: { buffer: packedBuffer, numComponents: 2, type: gl.FLOAT, stride: stride, offset: 24, },
vcolor: { buffer: packedBuffer, numComponents: 4, type: gl.UNSIGNED_BYTE, stride: stride, offset: 32, normalize: true },
},
};
var gl = document.getElementById("c").getContext("webgl");
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
// there's no easy way to interleave the data unless we use pure binary so
// lets do it manually.
var position = [
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
1, 1, 0,
];
var texcoord = [
0, 0,
1, 0,
0, 1,
1, 1,
]
var color = [
255, 0, 0, 255,
0, 255, 0, 255,
0, 0, 255, 255,
255, 255, 255, 255,
];
var stride = 24; // position + texcoord + rgba8
var typedArrayWithPackedData = new ArrayBuffer(stride * 4);
var floatView = new Float32Array(typedArrayWithPackedData);
var uint8View = new Uint8Array(typedArrayWithPackedData);
var floatAdd = 1;
var uint8Add = stride - 4;
var floatOffset = 0;
var uint8Offset = stride - 4;
var positionOffset = 0;
var texcoordOffset = 0;
var colorOffset = 0;
for (var ii = 0; ii < 4; ++ii) {
floatView[floatOffset++] = position[positionOffset++];
floatView[floatOffset++] = position[positionOffset++];
floatView[floatOffset++] = position[positionOffset++];
floatView[floatOffset++] = texcoord[texcoordOffset++];
floatView[floatOffset++] = texcoord[texcoordOffset++];
floatOffset += floatAdd;
uint8View[uint8Offset++] = color[colorOffset++];
uint8View[uint8Offset++] = color[colorOffset++];
uint8View[uint8Offset++] = color[colorOffset++];
uint8View[uint8Offset++] = color[colorOffset++];
uint8Offset += uint8Add;
}
var packedBuffer = twgl.createBufferFromTypedArray(
gl, typedArrayWithPackedData);
var typedArrayWithIndices = new Uint16Array([0, 1, 2, 2, 1, 3]);
var indexBuffer = twgl.createBufferFromTypedArray(
gl, typedArrayWithIndices, gl.ELEMENT_ARRAY_BUFFER);
var handMadeBufferInfo = {
numElements: 6, // or whatever
indices: indexBuffer, // remove if no indices
elementType: gl.UNSIGNED_SHORT, // remove if no indices
attribs: {
position: { buffer: packedBuffer, numComponents: 3, type: gl.FLOAT, stride: stride, offset: 0, },
texcoord: { buffer: packedBuffer, numComponents: 2, type: gl.FLOAT, stride: stride, offset: 12, },
color: { buffer: packedBuffer, numComponents: 4, type: gl.UNSIGNED_BYTE, stride: stride, offset: 20, normalize: true, },
},
};
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// make a texture with a circle in it
var canvas2d = document.createElement("canvas");
canvas2d.width = 64;
canvas2d.height = 64;
var ctx = canvas2d.getContext("2d");
ctx.fillStyle = "#fff";
ctx.beginPath();
ctx.arc(32, 32, 30, 0, Math.PI * 2, false);
ctx.fill();
var uniforms = {
u_texture: twgl.createTexture(gl, { src: canvas2d }),
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, handMadeBufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, handMadeBufferInfo);
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<script id="vs" type="notjs">
attribute vec4 position;
attribute vec2 texcoord;
attribute vec4 color;
varying vec2 v_texcoord;
varying vec4 v_color;
void main() {
v_texcoord = texcoord;
v_color = color;
gl_Position = position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
uniform sampler2D u_texture;
varying vec2 v_texcoord;
varying vec4 v_color;
void main() {
gl_FragColor = texture2D(u_texture, v_texcoord) * v_color;
}
</script>
<canvas id="c"></canvas>
Замечания: twgl.createBufferFromTypedArray
был только недавно выставлен в версии 0.0.37
Не совсем понятно, как это может быть проще. Если вы хотите, чтобы twgl упаковал данные для вас, неясно, в чем суть. Это действительно намного быстрее, чтобы сделать? Может быть, twgl должен поддерживать Vertex Array Objects?
Если бы вы упаковали его самостоятельно, вам все равно пришлось бы предоставить ему ту же информацию, что и выше, просто чтобы twgl превратил ее в BufferInfo
не похоже, что это сэкономит вам много времени.