使用 WebGL 渲染全屏四边形

Dud*_*Dud 3 framebuffer webgl

我有一个用于渲染场景的帧缓冲区,现在我想将其渲染为“全屏”四边形。我如何设置我的相机以及我应该在我的顶点着色器中放入什么以便将帧缓冲区的纹理渲染到整个屏幕。

我试过像这样创建一个全屏四边形

var gl = this.gl;
var quad_vertex_buffer = gl.createBuffer();
var quad_vertex_buffer_data = new Float32Array([ 
    -1.0, -1.0, 0.0,
     1.0, -1.0, 0.0,
    -1.0,  1.0, 0.0,
    -1.0,  1.0, 0.0,
     1.0, -1.0, 0.0,
     1.0,  1.0, 0.0]);
gl.bufferData(quad_vertex_buffer, quad_vertex_buffer_data, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, quad_vertex_buffer);
gl.vertexAttribPointer(this.shaderProgram.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
//gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.drawArrays(gl.TRIANGLES,0, 6);
Run Code Online (Sandbox Code Playgroud)

但它仍然使一切变黑。我可以遵循任何想法或示例/教程?

gma*_*man 5

为什么需要相机来渲染全屏四边形?渲染全屏四边形几乎是在 WebGL 中可以做的最简单的事情。给定您已经设置的缓冲区,只需使用这样的着色器

顶点着色器:

attribute vec4 v_position;

void main() {
  gl_Position = v_position;
}     
Run Code Online (Sandbox Code Playgroud)

片段着色器:

precision mediump float;

void main() {
   gl_FragColor = vec4(0,1,0,1); // green
}
Run Code Online (Sandbox Code Playgroud)

你应该得到一个绿屏。

但代码中存在一些错误。在尝试将数据放入缓冲区之前,您需要绑定缓冲区。您需要通过绑定点引用缓冲区,而不是缓冲区对象。

旧的(不正确)

gl.bufferData(quad_vertex_buffer, quad_vertex_buffer_data, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, quad_vertex_buffer);
Run Code Online (Sandbox Code Playgroud)

新的(正确的)

gl.bindBuffer(gl.ARRAY_BUFFER, quad_vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, quad_vertex_buffer_data, gl.STATIC_DRAW);
Run Code Online (Sandbox Code Playgroud)

例子:

attribute vec4 v_position;

void main() {
  gl_Position = v_position;
}     
Run Code Online (Sandbox Code Playgroud)
precision mediump float;

void main() {
   gl_FragColor = vec4(0,1,0,1); // green
}
Run Code Online (Sandbox Code Playgroud)

另一个例子用一个简单的模式来显示它的工作原理

gl.bufferData(quad_vertex_buffer, quad_vertex_buffer_data, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, quad_vertex_buffer);
Run Code Online (Sandbox Code Playgroud)
gl.bindBuffer(gl.ARRAY_BUFFER, quad_vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, quad_vertex_buffer_data, gl.STATIC_DRAW);
Run Code Online (Sandbox Code Playgroud)

我建议你阅读一些WebGL 教程


gla*_*ert 5

一旦你学会了如何使用顶点缓冲区和着色器,这真的没什么大不了的。然后你可以很容易地编写一个实用函数来完成它。如果您正在寻找参考,这是我通常使用的一个:

drawFullScreenQuad : function(shaderProgram) {

    if (!shaderProgram)
    {
        utils.warning("Missing the shader program!");
        return;
    }

    // Only created once
    if (this.screenQuadVBO == null)
    {
        var verts = [
            // First triangle:
             1.0,  1.0,
            -1.0,  1.0,
            -1.0, -1.0,
            // Second triangle:
            -1.0, -1.0,
             1.0, -1.0,
             1.0,  1.0
        ];
        this.screenQuadVBO = this.gl.createBuffer();
        this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.screenQuadVBO);
        this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(verts), this.gl.STATIC_DRAW);
    }

    // Bind:
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.screenQuadVBO);
    this.gl.enableVertexAttribArray(shaderProgram.vertexAttributes.vertexPositionNDC);
    this.gl.vertexAttribPointer(shaderProgram.vertexAttributes.vertexPositionNDC, 2, this.gl.FLOAT, false, 0, 0);

    // Draw 6 vertexes => 2 triangles:
    this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);

    // Cleanup:
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);
},
Run Code Online (Sandbox Code Playgroud)

然后你可以像我一样在顶点着色器中即时计算纹理坐标:

顶点着色器:

precision lowp float;

// xy = vertex position in normalized device coordinates ([-1,+1] range).
attribute vec2 vertexPositionNDC;

varying vec2 vTexCoords;

const vec2 scale = vec2(0.5, 0.5);

void main()
{
    vTexCoords  = vertexPositionNDC * scale + scale; // scale vertex attribute to [0,1] range
    gl_Position = vec4(vertexPositionNDC, 0.0, 1.0);
}
Run Code Online (Sandbox Code Playgroud)

片段着色器:

precision mediump float;

uniform sampler2D colorMap;
varying vec2 vTexCoords;

void main()
{
    gl_FragColor = texture2D(colorMap, vTexCoords);
}
Run Code Online (Sandbox Code Playgroud)

需要注意的重点是标准化设备坐标 (NDC) 中的顶点,因此您只需传递 [-1,1] 范围内的顶点并将它们直接转发到,gl_Position而无需乘以投影矩阵。