WebGL 整个运行流程是怎样的?shader 是怎么从内存取到值?

WebGL 的运行流程包括多个阶段,从初始化 WebGL 上下文、设置着色器程序,到加载数据并绘制到屏幕。这里分成两个部分来说明:WebGL 的整体运行流程 和 Shader 是如何从内存取值的。

一、WebGL 整个运行流程

  1. 获取 WebGL 上下文

    首先,通过 <canvas> 元素获取 WebGL 上下文(gl),这提供了 WebGL API 操作的入口。

    javascript 复制代码
    const canvas = document.getElementById('canvas');
    const gl = canvas.getContext('webgl');
  2. 编写并编译着色器 (Shaders)

    WebGL 使用两种着色器:顶点着色器 (Vertex Shader) 和片段着色器 (Fragment Shader)。顶点着色器用于处理顶点数据(如位置和纹理坐标),而片段着色器用于处理每个像素的颜色。

    javascript 复制代码
    const vertexShaderSource = `...`;  // 顶点着色器源码
    const fragmentShaderSource = `...`;  // 片段着色器源码
    
    function createShader(gl, type, source) {
        const shader = gl.createShader(type);
        gl.shaderSource(shader, source);
        gl.compileShader(shader);
        return shader;
    }
    
    const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
    const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
  3. 创建和链接着色器程序 (Shader Program)

    将顶点着色器和片段着色器链接到一个程序对象,这个程序对象将用于后续的绘制。

    javascript 复制代码
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    gl.useProgram(program);
  4. 设置缓冲区和属性指针

    将顶点数据(如位置、颜色或纹理坐标)加载到缓冲区中,并将其绑定到着色器的属性上。使用 gl.vertexAttribPointer() 来指定如何读取这些数据。

    javascript 复制代码
    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
    
    const positionLocation = gl.getAttribLocation(program, 'a_position');
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
  5. 设置 Uniform 变量

    Uniform 变量是全局变量,供顶点和片段着色器共享。常用于传递诸如颜色、纹理、变换矩阵等数据。

    javascript 复制代码
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.uniform1i(gl.getUniformLocation(program, 'u_image'), 0);  // 绑定纹理到片段着色器
  6. 绘制图形

    设置好所有的缓冲区和着色器后,使用 gl.drawArrays() 或 gl.drawElements() 开始绘制。

    javascript 复制代码
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  7. 呈现到屏幕

    绘制命令执行后,WebGL 会自动将渲染结果显示在 <canvas> 上。

二、Shader 如何从内存中取值

Shader 程序是运行在 GPU 上的小程序,在 WebGL 中,数据通过以下两种方式从内存中传递到 Shader 中:

  1. Attribute 变量

    Attribute 变量用于每个顶点的数据(如位置、法线、纹理坐标等)。这些数据通常从 CPU 端的缓冲区传递到 GPU。

    • 顶点数据加载到缓冲区 :通过 gl.bufferData() 将顶点数据上传到 GPU 的缓冲区。
    • 指定数据格式 :通过 gl.vertexAttribPointer() 定义每个顶点数据的布局,例如每个顶点由多少个分量组成、数据类型等。
    • 传递到顶点着色器:顶点着色器通过 Attribute 变量访问这些数据。
    javascript 复制代码
    // 在 JavaScript 中
    const positionLocation = gl.getAttribLocation(program, 'a_position');
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
    
    // 在顶点着色器中
    attribute vec4 a_position;
    void main() {
        gl_Position = a_position;
    }
  2. Uniform 变量

    Uniform 变量是全局的,适用于每个顶点或片段都相同的数据(如颜色、变换矩阵、纹理采样器等)。

    • 设置 Uniform 值 :在 JavaScript 中使用 gl.uniform* 函数设置 Uniform 的值。
    • 传递到着色器:Uniform 变量在着色器中声明后,可以直接使用。
    javascript 复制代码
    // 在 JavaScript 中
    const colorLocation = gl.getUniformLocation(program, 'u_color');
    gl.uniform4f(colorLocation, 1.0, 0.0, 0.0, 1.0); // 设置颜色为红色
    
    // 在片段着色器中
    uniform vec4 u_color;
    void main() {
        gl_FragColor = u_color;
    }

三、数据流的总结

  1. 顶点数据 (Attribute):从 JavaScript 上传到 GPU 缓冲区,并绑定到顶点着色器的 Attribute 变量。
  2. 全局数据 (Uniform):通过 JavaScript 直接传递到着色器,适用于全局常量或纹理等数据。
  3. Shader 内部执行:顶点着色器运行每个顶点,片段着色器运行每个像素,使用传递的数据进行计算。
  4. 最终渲染:着色器的输出最终会写入 GPU 帧缓冲区,并显示到屏幕上。

这些数据传递和处理使得 WebGL 能够高效地在 GPU 上执行复杂的图形操作。

相关推荐
kyriewen1 分钟前
我测了 6 种防请求竞态的写法:只有 1 种真能打
前端·javascript·程序员
孟健4 分钟前
用 WorkBuddy 做个人名片网页,挂上开源设计技能后效果完全不同了
前端·人工智能·ai编程
IT_陈寒8 分钟前
SpringBoot自动配置的坑,这次终于爬出来了
前端·人工智能·后端
LuHang1 小时前
从天地图切换到高德地图:一次真实的底图迁移实战
前端·vue.js·cesium
用户360055579001 小时前
Kestrel_VLLM - 27 · 寄存器常驻与融合发射:两次「少发一次」
前端
前端小万1 小时前
用"道法术器"重构你和 AI 的协作方式
前端·人工智能·程序员
鶴哥只手遮天1 小时前
Angular 22 源码级深度解析-第 06 章 模板指令全解:`ɵɵelementStart`、`ɵɵproperty`、`ɵɵadvance` 与绑定指令
前端·开源·angular.js
像我这样帅的人丶你还2 小时前
我html生成的doc文档为何在手机文档显示不了图片?
前端·javascript
前端双越老师3 小时前
程序员 1v1 访谈系列第十期:纯前端坚持不了多久了
前端·ai编程·全栈
门思科技5 小时前
LoRaWAN 网络排障的五层漏斗:从"上不到云"到"数值不对",每一层该用什么工具证明
前端