【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>
相关推荐
摘星编程19 分钟前
React Native + OpenHarmony:UniversalLink通用链接
javascript·react native·react.js
qq_1777673739 分钟前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
烬头882142 分钟前
React Native鸿蒙跨平台应用实现了onCategoryPress等核心函数,用于处理用户交互和状态更新,通过计算已支出和剩余预算
前端·javascript·react native·react.js·ecmascript·交互·harmonyos
程序员清洒2 小时前
Flutter for OpenHarmony:Text — 文本显示与样式控制
开发语言·javascript·flutter
雨季6663 小时前
Flutter 三端应用实战:OpenHarmony 简易“动态内边距调节器”交互模式深度解析
javascript·flutter·ui·交互·dart
天人合一peng3 小时前
Unity中button 和toggle监听事件函数有无参数
前端·unity·游戏引擎
会飞的战斗鸡3 小时前
JS中的链表(含leetcode例题)
javascript·leetcode·链表
方也_arkling4 小时前
别名路径联想提示。@/统一文件路径的配置
前端·javascript
毕设源码-朱学姐4 小时前
【开题答辩全过程】以 基于web教师继续教育系统的设计与实现为例,包含答辩的问题和答案
前端
qq_177767374 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos