【WebGL】fbo双pass案例

双pass渲染案例(离线渲染一个三角面,然后渲染到一个占满屏幕的矩阵上)

离线渲染如何需要开启深度测试的话,需要额外操作,这里不展开

js 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL 2 Offline Rendering and Texture Display</title>
</head>

<body>
    <canvas id="glCanvas" width="800" height="600"></canvas>
    <script>
        // 将 WebGL 初始化和渲染逻辑封装到一个函数中
        function initWebGL() {
            // 获取 canvas 元素
            const canvas = document.getElementById('glCanvas');
            // 获取 WebGL 2 上下文
            const gl = canvas.getContext('webgl2');

            // 如果无法获取 WebGL 2 上下文,给出提示并结束函数
            if (!gl) {
                alert('无法初始化 WebGL 2,你的浏览器可能不支持。');
                return;
            }

            // 离线渲染的着色器代码
            const offlineVertexShaderSource = `#version 300 es
                in vec2 a_position;
                void main() {
                    gl_Position = vec4(a_position, 0.0, 1.0);
                }
            `;

            const offlineFragmentShaderSource = `#version 300 es
                precision mediump float;
                out vec4 fragColor;
                void main() {
                    fragColor = vec4(1.0, 0.0, 0.0, 1.0);
                }
            `;

            // 最终渲染到屏幕的着色器代码
            const finalVertexShaderSource = `#version 300 es
                in vec2 a_position;
                in vec2 a_texCoord;
                out vec2 v_texCoord;
                void main() {
                    gl_Position = vec4(a_position, 0.0, 1.0);
                    v_texCoord = a_texCoord;
                }
            `;

            const finalFragmentShaderSource = `#version 300 es
                precision mediump float;
                in vec2 v_texCoord;
                uniform sampler2D u_texture;
                out vec4 fragColor;
                void main() {
                    fragColor = texture(u_texture, v_texCoord);
                }
            `;

            // 创建着色器函数
            function createShader(gl, type, source) {
                const shader = gl.createShader(type);
                gl.shaderSource(shader, source);
                gl.compileShader(shader);
                const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
                if (success) {
                    return shader;
                }
                console.log(gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
            }

            // 创建着色器程序函数
            function createProgram(gl, vertexShader, fragmentShader) {
                const program = gl.createProgram();
                gl.attachShader(program, vertexShader);
                gl.attachShader(program, fragmentShader);
                gl.linkProgram(program);
                const success = gl.getProgramParameter(program, gl.LINK_STATUS);
                if (success) {
                    return program;
                }
                console.log(gl.getProgramInfoLog(program));
                gl.deleteProgram(program);
            }

            // 创建离线渲染的着色器程序
            const offlineVertexShader = createShader(gl, gl.VERTEX_SHADER, offlineVertexShaderSource);
            const offlineFragmentShader = createShader(gl, gl.FRAGMENT_SHADER, offlineFragmentShaderSource);
            const offlineProgram = createProgram(gl, offlineVertexShader, offlineFragmentShader);

            // 创建最终渲染的着色器程序
            const finalVertexShader = createShader(gl, gl.VERTEX_SHADER, finalVertexShaderSource);
            const finalFragmentShader = createShader(gl, gl.FRAGMENT_SHADER, finalFragmentShaderSource);
            const finalProgram = createProgram(gl, finalVertexShader, finalFragmentShader);

            // 离线渲染的顶点数据
            const offlinePositions = [
                -0.5, -0.5,
                0.5, -0.5,
                0.0, 0.5
            ];

            // 创建离线渲染的顶点缓冲区
            const offlinePositionBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, offlinePositionBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(offlinePositions), gl.STATIC_DRAW);

            // 获取离线渲染的顶点属性位置
            const offlinePositionAttributeLocation = gl.getAttribLocation(offlineProgram, 'a_position');
            gl.enableVertexAttribArray(offlinePositionAttributeLocation);
            gl.vertexAttribPointer(offlinePositionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

            // 创建帧缓冲区对象(FBO)
            const framebuffer = gl.createFramebuffer();
            gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

            // 创建纹理对象
            const texture = gl.createTexture();
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

            // 将纹理附加到帧缓冲区
            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);

            // 检查帧缓冲区是否完整
            if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
                console.error('帧缓冲区不完整');
            }

            // 离线渲染
            gl.useProgram(offlineProgram);
            gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
            gl.viewport(0, 0, canvas.width, canvas.height);
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);
            gl.drawArrays(gl.TRIANGLES, 0, 3);

            // 最终渲染到屏幕的顶点数据和纹理坐标
            const finalPositions = [
                -1.0, -1.0,
                1.0, -1.0,
                -1.0, 1.0,
                -1.0, 1.0,
                1.0, -1.0,
                1.0, 1.0
            ];

            const finalTexCoords = [
                0.0, 0.0,
                1.0, 0.0,
                0.0, 1.0,
                0.0, 1.0,
                1.0, 0.0,
                1.0, 1.0
            ];

            // 创建最终渲染的顶点缓冲区和纹理坐标缓冲区
            const finalPositionBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, finalPositionBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(finalPositions), gl.STATIC_DRAW);

            const finalTexCoordBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, finalTexCoordBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(finalTexCoords), gl.STATIC_DRAW);

            // 获取最终渲染的顶点属性位置和纹理坐标属性位置
            const finalPositionAttributeLocation = gl.getAttribLocation(finalProgram, 'a_position');
            gl.enableVertexAttribArray(finalPositionAttributeLocation);
            gl.vertexAttribPointer(finalPositionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

            const finalTexCoordAttributeLocation = gl.getAttribLocation(finalProgram, 'a_texCoord');
            gl.enableVertexAttribArray(finalTexCoordAttributeLocation);
            gl.vertexAttribPointer(finalTexCoordAttributeLocation, 2, gl.FLOAT, false, 0, 0);

            // 获取最终渲染的纹理采样器位置
            const textureUniformLocation = gl.getUniformLocation(finalProgram, 'u_texture');

            // 最终渲染到屏幕
            gl.useProgram(finalProgram);
            gl.bindFramebuffer(gl.FRAMEBUFFER, null);
            gl.viewport(0, 0, canvas.width, canvas.height);
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, texture);
            gl.uniform1i(textureUniformLocation, 0);
            gl.drawArrays(gl.TRIANGLES, 0, 6);
        }

        // 调用封装好的函数来初始化和渲染 WebGL
        initWebGL();
    </script>
</body>

</html>
相关推荐
WeiXiao_Hyy7 小时前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡7 小时前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone7 小时前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09017 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农7 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king8 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳8 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵9 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星9 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_9 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js