WebGL - 初相识 - 着色器

前言

书接上回,这次会着重聊一聊上一篇文章中最后的例子中所用到的 WebGL 着色器,至于示例代码就不再复制了,可以通过上面的链接去回顾一下。

着色器

着色器就是让开发者自己编写一段程序代码(GLSL),用来替代固定渲染管线来处理图像的渲染。

在 WebGL 中,着色器分为两种:顶点着色器 和 片元着色器。

想要创建一个着色器还是有点麻烦的,需要使用 GLSL 编写顶点着色器源码,然后使用 WebGL 上下文对象 WebGLRenderingContext 也就是 canvas.getContext('webgl') ,去创建一个顶点着色器类型的实例,创建完实例后还需要进行源码绑定,最后还需要编译着色器才行。

实际上有更多其他类型着色器,例如:几何着色器和计算着色器,但是这几类着色器并不包含在标准规范中,因此 WebGL 不直接支持这些着色器,但是可以通过扩展机制,在特定的设备和浏览器中使用,当然前提是需要确保设备和浏览器支持所需的功能。

顶点着色器

初步可以理解为:坐标位置、大小等

顶点着色器是用于对三维模型的顶点进行处理和变换的程序,它在图形渲染管线的早期阶段运行,主要负责的任务是将输入的顶点坐标和其他属性(如法向量、纹理坐标等)转换成屏幕坐标,并进行一些其他的操作,如光照计算、变形、筛选等,还可以根据需要对顶点属性进行插值计算,将结果传递给下一个阶段的图形渲染管线。

片元着色器

初步可以理解为:颜色、皮肤等

片元着色器是一个计算和处理每个像素的小程序,也被称为像素着色器。它接收由顶点着色器传递的数据,如顶点的颜色、法线或纹理坐标等。片元着色器根据给定的光照模型、纹理等信息,计算每个像素的最终颜色。它可以根据各种算法和技术,实现逼真的光照效果、纹理映射、阴影和特殊效果等。

创建顶点着色器

获取上下文的方法在本中后续的例子中也会省略掉!

在 WebGL 上下文对象中,可以使用 createShader 方法来创建着色器,该方法接收一个参数 type ,也就是着色器类型,参数 typectx.VERTEX_SHADERctx.FRAGMENT_SHADER 中的一个(ctx 指的是 WebGL 上下文对象),其中 ctx.VERTEX_SHADER 代表顶点着色器类型,ctx.FRAGMENT_SHADER 代表片元着色器类型。

javascript 复制代码
// 获取上下文的方法在本中后续的例子中也会省略掉!
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('webgl')

// 创建着色器
const vertexShader = ctx.createShader(ctx.VERTEX_SHADER) // 顶点着色器
const fragmentShader = ctx.createShader(ctx.FRAGMENT_SHADER) // 片元着色器

指定着色器源码

光创建了着色器实例还不够的,还需对着色器实例设置其程序代码。

需要使用 shaderSource 方法来设置着色器的 GLSL 程序代码,该方法接收两个入参 shader, source,其中 shader 是着色器实例,source 是 GLSL 程序代码字符串。

这里稍微介绍一下 GLSL ,GLSL(OpenGL Shading Language)是用于编写着色器代码的语言,它类似于C语言。

GLSL 是一种强类型语言,支持的数据类型有 int、float、bool以及矢量类型(vec2、vec3、vec4);矢量类型表示具有多个分量的值,比如 vec3 表示具有3个浮点分量的矢量。

GLSL 提供了一些内置的特殊变量和函数,用于访问着色器程序的输入和输出,以及执行常见的数学和图形操作。例如,gl_Position 表示顶点着色器的输出位置、gl_PointSize 表示绘制点的大小、gl_FragColor 表示片元着色器的输出颜色。

csharp 复制代码
// 顶点着色器
const vertexShaderSource = `
    void main () {
        // 要绘制点的坐标
        // 这里的入参分别代表 x, y, z, w
        // 其中 w 代表的是齐次坐标
        // 下面的参数最终可以理解成 x/w, y/w, z/w
        gl_Position = vec4(0.0, 0.0, 0.0, 1.0); 
        
        // 点的大小
        gl_PointSize = 10.0; 
    }
`

// 片元着色器
const fragmentShaderSource = `
    void main () {
        // 要绘制的颜色信息
        // 这里的入参分别代表 r, g, b, a
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 
    }
`

// 指定着色器的代码
ctx.shaderSource(vertexShader, vertexShaderSource) // 设置顶点着色器源码
ctx.shaderSource(fragmentShader, fragmentShaderSource) // 设置片元着色器源码

编译着色器

接着需要使用 compileShader 方法来对着色器进行编译操作,使其成为 二进制数据,才可以被 WebGLProgram(着色器程序对象) 对象所使用。

compileShader 方法接受一个参数 shader,即着色器对象。

scss 复制代码
// 编译着色器 
ctx.compileShader(vertexShader) 
ctx.compileShader(fragmentShader)

着色器程序对象

还没完,目前着色器仍然无法使用,还需要创建着色器程序对象(WebGLProgram),着色器程序对象由两个着色器组成,分别是顶点着色器和片元着色器。

创建一个着色器程序对象需要使用 createProgram 方法,然后还需要使用 attachShader 方法为其 附加/绑定 上着色器,之后还需要使用 linkProgram 方法将它们连接成一个可用的程序。

createProgram 方法无需入参。
attachShader 方法接收两个参数 program(色器程序对象)、shader(着色器对象)。
linkProgram 方法接收一个参数 program ,即着色器程序对象。

scss 复制代码
// 创建程序对象
const program = ctx.createProgram()

// 绑定着色器
ctx.attachShader(program, vertexShader)
ctx.attachShader(program, fragmentShader)

// 将顶点着色器和片元着色器连接成一个可执行的程序
ctx.linkProgram(program)

绘制

目前我们拥有一个可用的着色器程序对象,那么是否可以直接进行绘制了呢?答案是 不可以

在绘制之前,我们需要使用 useProgram 方法将定义好的着色器程序对象添加到当前的渲染状态中,然后才可以执行 drawArrays 方法进行最终的绘制了。

useProgram 方法接收一个参数 program ,即着色器程序对象。
drawArrays 方法接收三个参数,分别是:mode、first、count;

  • mode 用来指定绘制图元的方式,可能值如下:
    • POINTS(点)
    • LINE_STRIP(线条)
    • LINE_LOOP(线圆)
    • LINES(线段)
    • TRIANGLE_STRIP(三角带)
    • TRIANGLE_FAN(三角扇)
    • TRIANGLES(三角形)
  • first 指定从那个点开始绘制;
  • count 指定绘制需要使用到多少个点;
scss 复制代码
// 将指定的程序对象设置为当前绘制的程序,可以理解为注册的意思?
ctx.useProgram(program)

// 执行绘制 
// 入参分别是 要绘制的基本图元类型、从哪个顶点开始绘制、要绘制的顶点数量
ctx.drawArrays(ctx.POINTS, 0, 1)

总结

到这里我们已经初步的了解到了着色器,知道了如何去创建着色器并且将着色器绘制到当前的画布中。当然整个过程还是挺复杂的,要用到的 API 也还挺多的,不过相信还是难不倒 jym 。

相关推荐
brrdg_sefg1 分钟前
Rust 在前端基建中的使用
前端·rust·状态模式
m0_7482309426 分钟前
Rust赋能前端: 纯血前端将 Table 导出 Excel
前端·rust·excel
qq_5895681034 分钟前
Echarts的高级使用,动画,交互api
前端·javascript·echarts
黑客老陈2 小时前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安2 小时前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy2 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se2 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235612 小时前
web 渗透学习指南——初学者防入狱篇
前端