当前位置: 首页 > news >正文

【WebGL】fbo双pass案例

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

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

<!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>

相关文章:

  • 《AI与NLP:开启元宇宙社交互动新纪元》
  • ue5地面上出现preview字样
  • 服务可用性评价指标
  • 第二届粤港澳大湾区数字经济与人工智能国际学术会议(DEAI 2025)
  • C++ MFC添加RichEditControl控件后,程序启动失败
  • 从零搭建微服务项目Pro(第1-1章——Quartz实现定时任务模块)
  • C++:std::thread、条件变量与信号量
  • 【网络】高级IO——Reactor版TCP服务器
  • 【学习笔记】Cadence电子设计全流程(二)原理图库的创建与设计(5-7)
  • 【JT/T 808协议】808 协议开发笔记 ② ( 终端注册 | 终端注册应答 | 字符编码转换网站 )
  • MongoDB应用设计调优
  • 【Leetcode 每日一题 - 扩展】1512. 好数对的数目
  • 鸿蒙NEXT应用App测试-专项测试(DevEco Testing)
  • 【Elasticsearch】同一台服务器部署集群
  • Java IO 设计模式总结
  • Plant Simulation培训教程-机器人3D仿真模块
  • C# AOT技术测试
  • DeepSeek 全面分析报告
  • 大语言模型微调的公开JSON数据
  • 业务流程相关的权威认证和培训有哪些
  • 纽约大学朗格尼医学中心的转型带来哪些启示?
  • 上海“随申兑”服务平台有哪些功能?已归集800余个惠企政策
  • 巴国家安全委员会授权军方自主决定对印反击措施
  • 吴清稳市场稳预期发布会十要点:谈平准基金、股市稳定、公募改革和巴菲特
  • 中国证监会印发《推动公募基金高质量发展行动方案》
  • 上海明后天将迎强风大雨,陆地最大阵风7~9级