Webgl:跨步无效。不会跨过缓冲区中的值
Webgl: Stride not working. Doesn't stride past values in buffer
我正在 webgl 中做一个洛伦兹吸引子,并且正在研究一般的多维奇怪吸引子。我在 webgl 中为此制作了一个粒子系统,在大多数情况下效果很好。粒子系统的工作原理是渲染 gl.POINTS 的 x 和 y 值,同时在同一缓冲区中保持更高的维度以计算它们各自的导数。缓冲区示例:x=buffer[i]、y=buffer[i+1]、z=buffer[i+2]、w=buffer[i+3] 等等。
我注意到当 z 大于 1 时,点消失了。这是我目前无法解决的另一个问题,所以我通过简单地跨过这些值来绕过它,因为 z 不应该是反正是可视化的一部分,但是这个步幅系统不起作用。
我知道另一种解决方案是制作仅包含 x 和 y 值的位置数组的副本,并将其作为二维系统传递到着色器程序中,这很有效!这样做可以消除 "disappearing points" 问题,但由于我希望没有垃圾收集,它会导致大量粒子出现延迟。
这是缓冲区代码:
dims = 3;
drawScene(gl, program, positions) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// positions is array of x,y,z coordinates
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionAttributeLocation);
const size = this.dims;
const type = gl.FLOAT;
const normalize = true;
const stride = 4 * (this.dims-2); // gl.FLOAT=4 bytes, then stride +1 extra per dim above 2
const offset = 0;
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
const primitiveType = gl.POINTS;
const count = positions.length / this.dims;
gl.drawArrays(primitiveType, offset, count);
}
步幅不对。步幅应该只是 dims * 4
如果你只想要 x 和 y 那么大小就是 2.
其他问题
另外你不能标准化浮点数
您应该在初始化时而不是渲染时查找位置
您应该创建一个缓冲区并重新使用它
该代码当前正在每帧创建一个新缓冲区,最终会 运行 内存不足
代码每帧都将原生 JavaScript 数组转换为新的 Float32Array。那也是一个分配。
您应该只创建一个 Float32Array 并更新其中的值
代码可能会通过调用 gl.bufferData
在 WebGL 中为每一帧分配一个新数组。而是调用 gl.bufferSubData
只上传数据
如果您经常更改缓冲区中的数据,您应该将其标记为 gl.DYNAMIC_DRAW
以让 WebGL 知道您计划经常更新它。它可以将其用作性能提示。
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
gl_PointSize = 5.0;
}`;
const fs = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}`;
const prg = twgl.createProgram(gl, [vs, fs]);
const positionAttributeLocation = gl.getAttribLocation(prg, 'a_position');
const dims = 3;
const num = 100;
const positions = new Float32Array(dims * num);
// create the buffer at init time
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// just allocate space
gl.bufferData(gl.ARRAY_BUFFER, positions.byteLength, gl.DYNAMIC_DRAW);
function drawScene(gl, program, positions) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// update positions
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, positions);
gl.enableVertexAttribArray(positionAttributeLocation);
const size = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 4 * dims;
const offset = 0;
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
gl.useProgram(program);
const primitiveType = gl.POINTS;
const count = positions.length / dims;
gl.drawArrays(primitiveType, offset, count);
}
function render(time) {
time *= 0.001;
for (let i = 0; i < num * dims; i += dims) {
const u = i / dims / num;
const a = u * Math.PI * 2 + time;
positions[i ] = Math.sin(a);
positions[i + 1] = Math.cos(a * 1.1);
positions[i + 2] = Math.cos(a * 1.2) * 1.2;
}
drawScene(gl, prg, positions);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas {
border: 1px solid black;
}
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
也更常见的是使用projection matrix and a view matrix来改变canvas代表的space。然后,除了不使用 Z,您还可以选择一个不同的 space 在 canvas 中表示,其中包含您的 Z 范围。
我正在 webgl 中做一个洛伦兹吸引子,并且正在研究一般的多维奇怪吸引子。我在 webgl 中为此制作了一个粒子系统,在大多数情况下效果很好。粒子系统的工作原理是渲染 gl.POINTS 的 x 和 y 值,同时在同一缓冲区中保持更高的维度以计算它们各自的导数。缓冲区示例:x=buffer[i]、y=buffer[i+1]、z=buffer[i+2]、w=buffer[i+3] 等等。
我注意到当 z 大于 1 时,点消失了。这是我目前无法解决的另一个问题,所以我通过简单地跨过这些值来绕过它,因为 z 不应该是反正是可视化的一部分,但是这个步幅系统不起作用。
我知道另一种解决方案是制作仅包含 x 和 y 值的位置数组的副本,并将其作为二维系统传递到着色器程序中,这很有效!这样做可以消除 "disappearing points" 问题,但由于我希望没有垃圾收集,它会导致大量粒子出现延迟。
这是缓冲区代码:
dims = 3;
drawScene(gl, program, positions) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// positions is array of x,y,z coordinates
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionAttributeLocation);
const size = this.dims;
const type = gl.FLOAT;
const normalize = true;
const stride = 4 * (this.dims-2); // gl.FLOAT=4 bytes, then stride +1 extra per dim above 2
const offset = 0;
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
const primitiveType = gl.POINTS;
const count = positions.length / this.dims;
gl.drawArrays(primitiveType, offset, count);
}
步幅不对。步幅应该只是 dims * 4
如果你只想要 x 和 y 那么大小就是 2.
其他问题
另外你不能标准化浮点数
您应该在初始化时而不是渲染时查找位置
您应该创建一个缓冲区并重新使用它
该代码当前正在每帧创建一个新缓冲区,最终会 运行 内存不足
代码每帧都将原生 JavaScript 数组转换为新的 Float32Array。那也是一个分配。
您应该只创建一个 Float32Array 并更新其中的值
代码可能会通过调用
gl.bufferData
在 WebGL 中为每一帧分配一个新数组。而是调用gl.bufferSubData
只上传数据如果您经常更改缓冲区中的数据,您应该将其标记为
gl.DYNAMIC_DRAW
以让 WebGL 知道您计划经常更新它。它可以将其用作性能提示。
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
gl_PointSize = 5.0;
}`;
const fs = `
precision mediump float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}`;
const prg = twgl.createProgram(gl, [vs, fs]);
const positionAttributeLocation = gl.getAttribLocation(prg, 'a_position');
const dims = 3;
const num = 100;
const positions = new Float32Array(dims * num);
// create the buffer at init time
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// just allocate space
gl.bufferData(gl.ARRAY_BUFFER, positions.byteLength, gl.DYNAMIC_DRAW);
function drawScene(gl, program, positions) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// update positions
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, positions);
gl.enableVertexAttribArray(positionAttributeLocation);
const size = 2;
const type = gl.FLOAT;
const normalize = false;
const stride = 4 * dims;
const offset = 0;
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset);
gl.useProgram(program);
const primitiveType = gl.POINTS;
const count = positions.length / dims;
gl.drawArrays(primitiveType, offset, count);
}
function render(time) {
time *= 0.001;
for (let i = 0; i < num * dims; i += dims) {
const u = i / dims / num;
const a = u * Math.PI * 2 + time;
positions[i ] = Math.sin(a);
positions[i + 1] = Math.cos(a * 1.1);
positions[i + 2] = Math.cos(a * 1.2) * 1.2;
}
drawScene(gl, prg, positions);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas {
border: 1px solid black;
}
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
也更常见的是使用projection matrix and a view matrix来改变canvas代表的space。然后,除了不使用 Z,您还可以选择一个不同的 space 在 canvas 中表示,其中包含您的 Z 范围。