【图形基础篇】04 # GPU与渲染管线:如何用WebGL绘制最简单的几何图形?

简介: 【图形基础篇】04 # GPU与渲染管线:如何用WebGL绘制最简单的几何图形?

说明

【跟月影学可视化】学习笔记。




图形系统是如何绘图的?

一个通用计算机图形系统主要包括 6 个部分,分别是:


  1. 输入设备
  2. 中央处理单元:首先,数据经过 CPU 处理,成为具有特定结构的几何信息。
  3. 图形处理单元:然后,这些信息会被送到 GPU 中进行处理。
  4. 存储器
  5. 帧缓存:光栅信息会输出到帧缓存中
  6. 输出设备


756711f5da154f6097f59b4b752de892.png

光栅(Raster):几乎所有的现代图形系统都是基于光栅来绘制图形的,光栅就是指构成图像的像素阵列。

像素(Pixel):一个像素对应图像上的一个点,它通常保存图像上的某个具体位置的颜色等信息。

帧缓存(Frame Buffer):在绘图过程中,像素信息被存放于帧缓存中,帧缓存是一块内存地址。

CPU(Central Processing Unit):中央处理单元,负责逻辑计算。

GPU(Graphics Processing Unit):图形处理单元,负责图形计算。



渲染管线(RenderPipelines)

在 GPU 中要经过两个步骤生成光栅信息:


   对给定的数据结合绘图的场景要素(例如相机、光源、遮挡物体等等)进行计算,最终将图形变为屏幕空间的 2D 坐标。


   为屏幕空间的每个像素点进行着色,把最终完成的图形输出到显示设备上。


这整个过程是一步一步进行的,前一步的输出就是后一步的输入,我们把这个过程叫做渲染管线(RenderPipelines)。



GPU 是什么?

GPU 是由大量的小型处理单元构成的,它可能远远没有 CPU 那么强大,但胜在数量众多,可以保证每个单元处理一个简单的任务。


每处理一个像素点就相当于完成了一个简单的任务,而一个图片应用又是由成千上万个像素点组成的,要处理这么多的小任务,比起使用若干个强大的 CPU,使用更小、更多的处理单元,是一种更好的处理方式。



WebGL绘图流程


1311a0d4aab64a769f89e8b4caa9dbbe.png



如何用 WebGL 绘制三角形?


浏览器提供的 WebGL API 是 OpenGL ES 的 JavaScript 绑定版本,它赋予了开发者操作 GPU 的能力。

绘制步骤:


  1. 创建 WebGL 上下文
  2. 创建 WebGL 程序(WebGL Program)
  3. 将数据存入缓冲区
  4. 将缓冲区数据读取到 GPU
  5. GPU 执行 WebGL 程序,输出结果


步骤一:创建 WebGL 上下文

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');



步骤二:创建 WebGL 程序

WebGL 程序是一个 WebGLProgram 对象,它是给 GPU 最终运行着色器的程序,而不是我们正在写的三角形的 JavaScript 程序。


1、编写两个着色器(Shader)

WebGL 是以顶点和图元来描述图形几何信息的。


   顶点就是几何图形的顶点


   图元是 WebGL 可直接处理的图形单元,由 WebGL 的绘图模式决定,有点、线、三角形等等。


   注意:图元是 WebGL 可以直接处理的图形单元,所以其他非图元的图形最终必须要转换为图元才可以被 WebGL 处理。


WebGL 绘制一个图形的过程,一般需要用到两段着色器


   顶点着色器(Vertex Shader):负责处理图形的顶点信息


   片元着色器(Fragment Shader):负责处理图形光栅化后的像素信息


顶点着色器的作用:


   通过 gl_Position 设置顶点


   向片元着色器传递数据:通过 varying 变量传给片元着色器,根据片元着色器的像素坐标与顶点像素坐标的相对位置做线性插值。

const vertex = `
    attribute vec2 position;
    void main() {
        gl_PointSize = 1.0;
        gl_Position = vec4(position, 1.0, 1.0);
    }
`;
const fragment = `
    precision mediump float;
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }    
`;


2、创建成 shader 对象

const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertex);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragment);
gl.compileShader(fragmentShader);


3、创建 WebGLProgram 对象

将两个 shader 关联到 WebGL 程序,将 WebGLProgram 对象链接到 WebGL 上下文对象上。

const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);


4、通过 useProgram 选择启用 WebGLProgram 对象

gl.useProgram(program);



步骤三:将数据存入缓冲区


1、WebGL 的坐标系

WebGL 的坐标系是一个三维空间坐标系,坐标原点是(0,0,0)。其中,x 轴朝右,y 轴朝上,z 轴朝外。这是一个右手坐标系。


78612b4741214b0e808a891860af2827.png


左手右手对比图

d613754adfa04219a62e33d1f25865ad.png


2、定义三角形的三个顶点

比如要绘制下面这个二维的三角形,三个顶点分别如下:


5f0de6b2ae444eb0b9031a84b3ccc9e1.png


WebGL 使用的数据需要用类型数组定义,默认格式是 Float32Array。

Float32Array 是 JavaScript 的一种类型化数组(TypedArray),JavaScript 通常用类型化数组来处理二进制缓冲区。


const points = new Float32Array([
    -1, -1,
    0, 1,
    1, -1,
]);



3、将数据写入 WebGL 的缓冲区

  1. 创建一个缓存对象
  2. 将它绑定为当前操作对象
  3. 再把当前的数据写入缓存对象


const bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);


步骤四:将缓冲区数据读取到 GPU

将 buffer 的数据绑定给顶点着色器的 position 变量

// 获取顶点着色器中的position变量的地址
const vPosition = gl.getAttribLocation(program, 'position');
// 给变量设置长度和类型
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
// 激活这个变量
gl.enableVertexAttribArray(vPosition);



步骤五:执行着色器程序完成绘制

调用绘图指令,就可以执行着色器程序来完成绘制


// 将当前画布的内容清除
gl.clear(gl.COLOR_BUFFER_BIT);
// 传入三角形图元、顶点偏移量和顶点数量进行绘制
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);


完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>如何用WebGL绘制最简单的几何图形</title>
    <style>
        canvas {
            border: 1px dashed salmon;
        }
    </style>
</head>
<body>
    <canvas width="240" height="240"></canvas>
    <script>
        // 获取 webgl 上下文
        const canvas = document.querySelector('canvas');
        const gl = canvas.getContext('webgl');
        // 顶点着色器代码片段:attribute 表示声明变量,vec2 是变量的类型,它表示一个二维向量,position 是变量名。
        const vertex = `
            attribute vec2 position;
            void main() {
                gl_PointSize = 1.0;
                gl_Position = vec4(position, 1.0, 1.0);
            }
        `;
        // 片元着色器代码片段:gl_FragColor 的值来定义和改变图形的颜色,RGBA 色值表示的四维向量数据
        // rgba(250,128,114,1) vec4(250/255, 128/255, 114/255, 1)
        const fragment = `
            precision mediump float;
            void main() {
                gl_FragColor = vec4(0.9803921568627451, 0.5019607843137255, 0.4470588235294118, 1);
            }    
        `;
        // 将着色器代码片段创建成 shader 对象
        const vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, vertex);
        gl.compileShader(vertexShader);
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader, fragment);
        gl.compileShader(fragmentShader);
        // 创建 WebGLProgram 对象
        const program = gl.createProgram();
        // 将两个 shader 关联到 WebGL 程序
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        // 将 WebGLProgram 对象链接到 WebGL 上下文对象上
        gl.linkProgram(program);
        // 通过 useProgram 选择启用 WebGLProgram 对象
        gl.useProgram(program);
        // 定义三角形的三个顶点
        const points = new Float32Array([
            -1, -1,
            0, 1,
            1, -1,
        ]);
        console.log("points---->", points)
        // 创建一个缓存对象
        const bufferId = gl.createBuffer();
        // 将它绑定为当前操作对象
        gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
        // 再把当前的数据写入缓存对象
        gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
        // 获取顶点着色器中的position变量的地址
        const vPosition = gl.getAttribLocation(program, 'position');
        console.log("vPosition---->", vPosition)
        // 给变量设置长度和类型
        gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
        // 激活这个变量
        gl.enableVertexAttribArray(vPosition);
        // 将当前画布的内容清除
        gl.clear(gl.COLOR_BUFFER_BIT);
        // 传入三角形图元、顶点偏移量和顶点数量进行绘制
        gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);
    </script>
</body>
</html>


92065e291c0f4f0ba4b5c97a9c4f8a23.png



相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
目录
相关文章
|
8月前
|
视频直播 芯片 异构计算
山东布谷科技直播系统源码热点分析:不同芯片实现高质量编码与渲染视频的GPU加速功能
总而言之,对于直播系统源码来说,GPU加速功能是提升实时图像质量和观看体验的重要手段,是不可或缺的重要功能技术之一。
山东布谷科技直播系统源码热点分析:不同芯片实现高质量编码与渲染视频的GPU加速功能
|
缓存 算法 Java
Android硬件加速(二)-RenderThread与OpenGL GPU渲染
Android硬件加速(二)-RenderThread与OpenGL GPU渲染
1005 0
Android硬件加速(二)-RenderThread与OpenGL GPU渲染
|
Android开发 开发者 异构计算
【Android 性能优化】布局渲染优化 ( GPU 过度绘制优化总结 | CPU 渲染过程 | Layout Inspector 工具 | View Tree 分析 | 布局组件层级分析 )(二)
【Android 性能优化】布局渲染优化 ( GPU 过度绘制优化总结 | CPU 渲染过程 | Layout Inspector 工具 | View Tree 分析 | 布局组件层级分析 )(二)
226 0
【Android 性能优化】布局渲染优化 ( GPU 过度绘制优化总结 | CPU 渲染过程 | Layout Inspector 工具 | View Tree 分析 | 布局组件层级分析 )(二)
|
Android开发 开发者 异构计算
【Android 性能优化】布局渲染优化 ( GPU 过度绘制优化总结 | CPU 渲染过程 | Layout Inspector 工具 | View Tree 分析 | 布局组件层级分析 )(一)
【Android 性能优化】布局渲染优化 ( GPU 过度绘制优化总结 | CPU 渲染过程 | Layout Inspector 工具 | View Tree 分析 | 布局组件层级分析 )(一)
369 0
【Android 性能优化】布局渲染优化 ( GPU 过度绘制优化总结 | CPU 渲染过程 | Layout Inspector 工具 | View Tree 分析 | 布局组件层级分析 )(一)
|
Android开发 异构计算
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(二)
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(二)
155 0
|
前端开发 Android开发 开发者
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)
320 0
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)
|
XML 存储 Android开发
【Android 性能优化】布局渲染优化 ( CPU 与 GPU 架构分析 | 安卓布局显示流程 | 视觉与帧率分析 | 渲染超时卡顿分析 | 渲染过程与优化 )
【Android 性能优化】布局渲染优化 ( CPU 与 GPU 架构分析 | 安卓布局显示流程 | 视觉与帧率分析 | 渲染超时卡顿分析 | 渲染过程与优化 )
372 0
【Android 性能优化】布局渲染优化 ( CPU 与 GPU 架构分析 | 安卓布局显示流程 | 视觉与帧率分析 | 渲染超时卡顿分析 | 渲染过程与优化 )
|
编解码 JavaScript Linux
Sublime Text 4 首个稳定版终于来了:支持 GPU 渲染、兼容旧版本、Python API 升级
Sublime Text 4 首个稳定版终于来了:支持 GPU 渲染、兼容旧版本、Python API 升级
Sublime Text 4 首个稳定版终于来了:支持 GPU 渲染、兼容旧版本、Python API 升级
|
3月前
|
人工智能 机器人 Serverless
魔搭大模型一键部署到阿里云函数计算,GPU 闲置计费功能可大幅降低开销
魔搭大模型一键部署到阿里云函数计算,GPU 闲置计费功能可大幅降低开销
583 2