为什么在调用 bindBufferRange() 之前取消绑定 gl.UNIFORM_BUFFER? [英] Why unbind gl.UNIFORM_BUFFER before calling bindBufferRange()?

查看:45
本文介绍了为什么在调用 bindBufferRange() 之前取消绑定 gl.UNIFORM_BUFFER?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从一些不同的例子来看,似乎将数据上传到缓冲区,用作统一缓冲区,执行以下顺序:

From looking at some different examples in the wild, it seems that uploading data to a buffer, for use as a uniform buffer, does the following sequence:

  1. bindBuffer()
  2. bufferData()
  3. bindBuffer() - 为 null,即解除绑定"
  4. bindBufferRange()

第 3 步的目的是什么?

What is the purpose of step 3?

推荐答案

你不需要按照这个顺序来做.

You don’t need to do it in that order.

最简单的例子:

'use strict';

const vs = `#version 300 es
void main() {
  gl_PointSize = 128.0;
  gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision mediump float;

uniform Color {
  vec4 u_color;
};

out vec4 outColor;

void main() {
  outColor = u_color;
}
`;

const gl = document.querySelector('canvas').getContext('webgl2');
if (!gl) alert('need webgl2');
const program = twgl.createProgram(gl, [vs, fs]);

const color = new Float32Array([1, 0.5, 0.7, 1]);
const buffer = gl.createBuffer();

// there's only 1 so I believe it's safe to guess index 0
const uniformBlockIndex = 0;
const uniformBlockBinding = 0;
gl.uniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);


// at render time
gl.useProgram(program);

// for each block
{
  const uniformBlockBufferOffset = 0;
  const uniformBlockBufferOffsetByteLength = 16;  // 4 floats
  gl.bindBufferRange(gl.UNIFORM_BUFFER, uniformBlockBinding, buffer, uniformBlockBufferOffset, uniformBlockBufferOffsetByteLength);

  // set the data
  gl.bufferData(gl.UNIFORM_BUFFER, color, gl.DYNAMIC_DRAW);
}


gl.drawArrays(gl.POINTS, 0, 1);

<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

如果你想看一个复杂的例子,你可以深入研究这个例子.它在程序创建时查询有关统一缓冲区的所有数据.有多少,他们的名字是什么,他们使用什么制服,这些制服的类型是什么.当您调用 twgl.createProgramInfo 时会发生这种情况,您可以 查看内部,看到信息是在createUniformBlockSpecFromProgram

If you’d like to see a complex example you can dig through this example. It queries all the data about uniform buffers when the program is created. How many there are, what their names are, which uniforms they use, what the types of those uniforms are. This happens when you call twgl.createProgramInfo which you can look inside and see that info is created in createUniformBlockSpecFromProgram

然后,使用块规范,您可以通过调用 twgl.createUniformBlockInfo

Then later, using the block spec, you can create a typedarray with premade views into that array for all the uniforms by calling twgl.createUniformBlockInfo

const ubi = twgl.createUniformBlockInfo(...)

您可以直接使用

ubi.uniforms.nameOfUniform.set(newValue)

但这会很脆弱,因为在调试时块可能会被优化,所以你可以使用不那么脆弱的

but that would be brittle since blocks may get optimized out while debugging so instead you can use the less brittle

twgl.setBlockUniforms(ubi, {nameOfUniform: newValue});

当您确实希望将 typedarray 中的数据上传到 GPU 时,您调用

When you actually want the data in the typedarray to get uploaded to the GPU you call

twgl.setUniformBlock(...);

两者都将统一块绑定到其分配的绑定并将数据上传到 GPU.

Which both binds the uniform block to its assigned binding AND uploads the data to the GPU.

如果你只是想绑定一个现有的块(不需要上传新数据)那么

If you just want to bind an existing block (no need to upload new data) then

twgl.bindUniformBlock(gl, programInfo, ubi);

模式与您在示例中看到的一样

The pattern though is as you see in the example

  1. bindBufferRange
  2. 缓冲数据

bindBufferRange 已经绑定了缓冲区,所以我们可以使用该绑定来上传数据.

bindBufferRange already binds the buffer so we can just use that binding to upload the data.

测试(非 twgl)

'use strict';

const vs = `#version 300 es
void main() {
  gl_PointSize = 128.0;
  gl_Position = vec4(0, 0, 0, 1);
}
`;
const fs = `#version 300 es
precision mediump float;

uniform Color1 {
  vec4 u_color1;
};
uniform Color2 {
  vec4 u_color2;
};

out vec4 outColor;

void main() {
  outColor = u_color1 + u_color2;
}
`;

const gl = document.querySelector('canvas').getContext('webgl2');
if (!gl) alert('need webgl2');
const program = twgl.createProgram(gl, [vs, fs]);

const color1 = new Float32Array([1, 0, 0, 1]);
const buffer1 = gl.createBuffer();
const color2 = new Float32Array([0, 0, 1, 1]);
const buffer2 = gl.createBuffer();

// there's only 2 and they are the same format so we don't really
// care which is which to see the results.
const uniformBlockIndex = 0;
const uniformBlockBinding = 0;
gl.uniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
gl.uniformBlockBinding(program, uniformBlockIndex + 1, uniformBlockBinding + 1);


// at render time
gl.useProgram(program);

{
  const uniformBlockBufferOffset = 0;
  const uniformBlockBufferOffsetByteLength = 16;  // 4 floats
  gl.bindBufferRange(gl.UNIFORM_BUFFER, uniformBlockBinding, buffer1, uniformBlockBufferOffset, uniformBlockBufferOffsetByteLength);

  // set the data
  gl.bufferData(gl.UNIFORM_BUFFER, color1, gl.DYNAMIC_DRAW);
  
  
  gl.bindBufferRange(gl.UNIFORM_BUFFER, uniformBlockBinding + 1, buffer2, uniformBlockBufferOffset, uniformBlockBufferOffsetByteLength);

  // set the data
  gl.bufferData(gl.UNIFORM_BUFFER, color2, gl.DYNAMIC_DRAW);
}


gl.drawArrays(gl.POINTS, 0, 1);

<canvas></canvas>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

上面的例子显示 bindBufferRange 做了两件事.

The example above shows bindBufferRange does 2 things.

  1. 它将缓冲区绑定到 UNIFORM_BUFFER 绑定点
  2. 它将缓冲区的一部分绑定到统一缓冲区索引.

我们知道它有效,因为结果是紫色的.如果它不起作用,它将是红色或蓝色

We know it worked because the result is purple. If it didn’t work it would either be red or blue

来自与 bindBufferRange

每个目标代表一个缓冲对象绑定点的索引数组,以及作为单个通用绑定点,可供其他缓冲区对象操作函数使用

Each target represents an indexed array of buffer object binding points, as well as a single general binding point that can be used by other buffer object manipulation functions

这篇关于为什么在调用 bindBufferRange() 之前取消绑定 gl.UNIFORM_BUFFER?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆