vertexAttribPointer的作用是什么?

10
我正在使用JavaScript和WebGL编写游戏引擎。为了测试它,我编写了一个绘制立方体的程序。为了使该程序正常工作,在调用bind buffers之后但在调用draw triangles之前必须调用vertexAttribPointer。我想知道这个方法究竟做了什么,以及为什么我必须按这个顺序调用这些方法?
我最好的猜测是它初始化属性,但如果是这样,我不明白为什么必须在客户端调用它。
我在下面包含了一些源代码。所有代码都是用TypeScript编写的。完整代码请参见github.com/dkellycollins/nemesis 设置着色器:
var cubeShader = new shaderProgram();
cubeShader.addShader(shaders.colorVertexShader);
cubeShader.addShader(shaders.colorFragmentShader);
cubeShader.init();
cubeShader.enableAttrib("position", 3, 4 * (3 + 3), 0);
cubeShader.enableAttrib("color", 3, 4 * (3 + 3), 3 * 4);

着色器程序:

class shaderProgram {
    constructor() {
        this.Id = gl.createProgram();
    }

    public Id;

    public addShader(shader:WebGLShader[]):void {
        if(shader instanceof Array) {
            shader.forEach(s => {
                gl.attachShader(this.Id, s);
            });
        } else {
            gl.attachShader(this.Id, shader);
        }
    }

    public init():void {
        gl.linkProgram(this.Id);
    }

    public setActive() {
        gl.useProgram(this.Id);
    }

    public enableAttrib(attribName: string, index: number, stride:number, offset: number) {
        var attrib = gl.getAttribLocation(this.Id, attribName);
        gl.enableVertexAttribArray(attrib);
        gl.vertexAttribPointer(attrib, index, gl.FLOAT, false, stride, offset);
    }

    public setFloatAttrib(attribName:string, value:number) {
        var attrib = gl.getAttribLocation(this.Id, attribName);
        gl.vertexAttrib1f(attrib, value);
    }

    public setMatrix(uniName: string, value: number[]) {
        var uniform = gl.getUniformLocation(this.Id, uniName);
        gl.uniformMatrix4fv(uniform, false, value);
    }
}

渲染立方体:

public render():void {
    gl.drawElements(gl.TRIANGLES, this._triangles, gl.UNSIGNED_SHORT, 0);
}

顶点着色器源代码:

attribute vec3 position; //the position of the point
uniform mat4 Pmatrix;
uniform mat4 Vmatrix;
uniform mat4 Mmatrix;
attribute vec3 color; //the color of the point
varying vec3 vColor;
void main(void) { //pre-built function
    gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.); //0. is the z, and 1 is w
    vColor=color;
}
2个回答

15

它告诉WebGL如何解释数据:

gl.vertexAttribPointer(attrib, index, gl.FLOAT, false, stride, offset);
这意味着:对于属性attrib,有index个类型为gl.FLOAT的组件在此调用时位于绑定到gl.ARRAY_BUFFER上的数组缓冲区中。它们从offset开始,相隔stride,并且not被标准化处理。 客户端可以自由设置其数据,只要其符合上述描述即可。

那么为什么必须对属性进行这样的操作呢?Uniforms不需要这样做。WebGL难道不能仅从属性是vec3这一事实中确定索引、偏移和步幅吗?还是我漏掉了什么? - dkellycollins
1
它无法确定步幅(这完全取决于程序员如何交错数据,尽管有默认的0值用于紧密打包),有些人使用半精度、整数或短整型存储数据(缓冲区只存储字节序列,没有类型信息)。 - ratchet freak
我现在明白了。我没有意识到所有属性都从数组缓冲区获取数据。谢谢你的帮助! - dkellycollins
6
为了明确,可能会有多个ARRAY_BUFFER,每个属性都可以引用不同的缓冲区。该属性从哪个缓冲区获取数据取决于在调用特定属性的vertexAttribPointer时,哪个缓冲区被绑定到ARRAY_BUFFER绑定点上。 - gman

2
根据这个WebGl2基础教程,这是必要的,以指定如何提取数据。另外:

gl.vertexAttribPointer的一个隐藏部分是它将当前ARRAY_BUFFER绑定到属性上。换句话说,现在该属性已绑定到positionBuffer。这意味着我们可以自由地将其他东西绑定到ARRAY_BUFFER绑定点。该属性将继续使用positionBuffer。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接