Glsl 绑定多个统一缓冲区对象

Glsl 绑定多个统一缓冲区对象,glsl,webgl2,Glsl,Webgl2,使用WebGL 2,我们现在可以使用统一缓冲区对象 它们看起来是一个不错的主意,不必为每个程序都附加通用的制服(比如投影矩阵和视图矩阵,它们对渲染的每个对象都是通用的) 我创建了一个助手类,每当我想绑定一个统一的缓冲区对象时,我都会调用它 class UniformBuffer { constructor(gl, data, boundLocation = 0) { this.boundLocation = boundLocation; this.dat

使用WebGL 2,我们现在可以使用统一缓冲区对象

它们看起来是一个不错的主意,不必为每个程序都附加通用的制服(比如投影矩阵和视图矩阵,它们对渲染的每个对象都是通用的)

我创建了一个助手类,每当我想绑定一个统一的缓冲区对象时,我都会调用它

class UniformBuffer {
    constructor(gl, data, boundLocation = 0) {
        this.boundLocation = boundLocation;

        this.data = new Float32Array(data);

        this.buffer = gl.createBuffer();
        gl.bindBuffer(gl.UNIFORM_BUFFER, this.buffer);
        gl.bufferData(gl.UNIFORM_BUFFER, this.data, gl.DYNAMIC_DRAW);
        gl.bindBuffer(gl.UNIFORM_BUFFER, null);
        gl.bindBufferBase(gl.UNIFORM_BUFFER, this.boundLocation, this.buffer);
    }

    update(gl, data, offset = 0) {
        this.data.set(data, offset);

        gl.bindBuffer(gl.UNIFORM_BUFFER, this.buffer);
        gl.bufferSubData(gl.UNIFORM_BUFFER, 0, this.data, 0, null);
        gl.bindBuffer(gl.UNIFORM_BUFFER, null);
        gl.bindBufferBase(gl.UNIFORM_BUFFER, this.boundLocation, this.buffer);
    }
};
这样创建统一缓冲区的想法

const perScene = new UniformBuffer(gl, [
    ...vec4.create(),
    ...vec4.create(),
], 0); // and bind it to bind location 0?

const perObject = new UniformBuffer(gl, [
    ...vec4.create(),
], 1); // and bind it to bind location 1?
for (let i = 0; i < objects.length; i++) {
    perObject.update(gl, [
       ...vec4.fromValues(0, 0, 1, 1),
    ]);
} 
在渲染循环中,然后通过调用

perScene.update(gl, [
    ...vec4.fromValues(1, 0, 0, 1),
], 4); // giving an offset to update only the 2nd color.
然后我将查看场景中的所有对象,我的想法是像这样更新perObject统一缓冲区

const perScene = new UniformBuffer(gl, [
    ...vec4.create(),
    ...vec4.create(),
], 0); // and bind it to bind location 0?

const perObject = new UniformBuffer(gl, [
    ...vec4.create(),
], 1); // and bind it to bind location 1?
for (let i = 0; i < objects.length; i++) {
    perObject.update(gl, [
       ...vec4.fromValues(0, 0, 1, 1),
    ]);
} 
我这里有一个工作片段

class UniformBuffer{
构造函数(总帐,数据,边界位置=0){
this.boundLocation=boundLocation;
this.data=新的Float32Array(数据);
this.buffer=gl.createBuffer();
gl.bindBuffer(gl.UNIFORM\u BUFFER,this.BUFFER);
总账缓冲区数据(总账统一缓冲区、本数据、总账动态绘图);
gl.bindBuffer(gl.UNIFORM\u BUFFER,null);
gl.bindBufferBase(gl.UNIFORM\u BUFFER,this.boundLocation,this.BUFFER);
}
更新(总账、数据、偏移=0){
此.data.set(数据,偏移量);
gl.bindBuffer(gl.UNIFORM\u BUFFER,this.BUFFER);
gl.bufferSubData(gl.UNIFORM_BUFFER,0,this.data,0,null);
gl.bindBuffer(gl.UNIFORM\u BUFFER,null);
gl.bindBufferBase(gl.UNIFORM\u BUFFER,this.boundLocation,this.BUFFER);
}
};
常量顶点=`#版本300 es
均匀渗层{
vec4-1;
vec4-2;
};
均匀排列模型{
vec4-3;
};
在vec3 a_位置;
输出vec3v_颜色;
void main(){
gl_位置=vec4(a_位置,1.0);
v_color=color1.rgb+color2.rgb;//有效
//v_color=color1.rgb+color2.rgb+color3.rgb;//不起作用
}
`;
常量片段=`#版本300 es
高精度浮点;
精度高;
在vec3 v_颜色中;
外显vec4外显色;
void main(){
outColor=vec4(v_color,1.0);
}
`;
常数几何={
位置:[-0.5,-0.5,0,-0.5,0.5,0,0.5,-0.5,0,0.5,0],
指数:[0,2,1,1,2,3],
};
常量renderList=[];
//步骤1(创建画布)
var canvas=document.getElementById(“canvas”);
var gl=canvas.getContext(“webgl2”);
如果(!gl){
log(“没有webgl2好友”);
}
//步骤2(创建程序)
常量v=gl.createShader(gl.VERTEX_着色器);
gl.shaderSource(v,顶点);
总帐编辑主任(五);
常量f=gl.createShader(gl.FRAGMENT\u着色器);
gl.shaderSource(f,片段);
总帐编辑主任(f);
const program=gl.createProgram();
德国劳埃德船级社附件(程序,v);
德国劳埃德船级社附件(程序,f);
总账链接程序(程序);
//步骤3(创建VAO)
const positionAttributeLocation=gl.getAttributeLocation(程序“a_位置”);
const colorUniformLocation=gl.getUniformLocation(程序“颜色”);
const positionsBuffer=gl.createBuffer();
const indicatesbuffer=gl.createBuffer();
const vao=gl.createVertexArray();
bindVertexArray总帐(vao);
//位置和索引
gl.EnableVertexAttributeArray(位置属性位置);
gl.bindBuffer(gl.ARRAY_BUFFER,positionsBuffer);
gl.bufferData(gl.ARRAY\u BUFFER、新Float32Array(geometry.positions)、gl.STATIC\u DRAW);
gl.VertexAttributePointer(位置属性位置,3,gl.FLOAT,false,0,0);
gl.bindBuffer(gl.ARRAY\u BUFFER,null);
gl.bindBuffer(gl.ELEMENT\u ARRAY\u BUFFER,indicatesbuffer);
gl.bufferData(gl.ELEMENT\u ARRAY\u BUFFER、新UINT16阵列(几何体索引)、gl.STATIC\u DRAW);
//步骤4(创建UBO)
//已绑定到位置0
const perScene=新的UniformBuffer(gl[
…vec4.create(),//颜色1
…vec4.create(),//颜色2
], 0);
//绑定到位置1?
const perModel=新的UniformBuffer(gl[
…vec4.create(),//颜色3
], 3);
//步骤5(添加实例)
for(设i=0;i<1;i++){
renderList.push({
id:我,
vao:vao,
节目:节目,,
颜色:[0,1,1],
});
}
//第6步(抽签)
gl.clearColor(0,0,0,0);
总帐启用(总帐深度测试);
总图视口(0,0,canvas.width,canvas.height);
perScene.更新(德国劳埃德船级社[
…vec4.fromValues(1,0,0,1),
…vec4.fromValues(0,1,0,1),
]);
for(设i=0;i
画布{
背景色:黑色;
}

因此,您做错的第一件事就是没有调用
gl.getUniformBlockIndex
。就像uniform一样,您必须查询每个块的位置或索引

第二件事是块统一是间接的一级,您需要调用
gl.uniformBlockBinding(program,uniformblockdex,uniformBufferIndex)

uniformblockdex
是从
gl.getuniformblockdex
获得的索引<代码>uniformBufferIndex
类似于纹理单元。存在N个统一的缓冲区索引。您可以从
0
MAX\u UNIFORM\u buffer\u BINDINGS-1
选择任何缓冲区索引

如果您有一个程序使用块A、B,另一个程序使用块A和C,则此间接寻址会有所帮助。在这种情况下,块A可能在两个程序中具有不同的索引,但您让它从相同的uniformBufferIndex中提取其值

请注意,此状态为每个程序状态,因此,如果您计划对同一统一块始终使用相同的统一缓冲区索引,则可以在初始化时设置它

把它说得更清楚。你有一个着色器程序。它有状态

var someProgram = {
  uniforms: {
    projectionMatrix: [1, 0, 0, 0, 0, ... ],  // etc
  },
  uniformBlockIndcies[  // one per uniform block
    0, 
    0,
    0,
  ],
  ...
}
接下来是全局状态的统一缓冲区索引

glState = {
  textureUnits: [ ... ],
  uniformBuffers: [ null, null, null ..., ], 
};
告诉程序每个统一缓冲区块使用哪个统一缓冲区索引与
gl.uniformBlockBinding
。然后使用
gl.bindBufferBase
gl.bind将缓冲区绑定到该索引