webgl(一)浅浅入门

428 阅读3分钟

一堆废话的前言

2024年五一过后,在掘金上无意看到 alphardex的一篇文章,# SU7,启动!尝试还原了 SU7 网页的炫酷特效,实现的效果真的很炫酷,了解了一个新的名词shader

在这之前,对webgl并没有深入学习,用过canvas,但是不多。对3D更是不了解,仅仅知道一丢丢关于vtk和一些医疗影像的处理和使用。但这也是在已经封装的基础上去用。

顺着shader这个词,在掘金上找到了大神古柳,一系列手把手带你入门shader,整体看下来,觉得shader魅力四射。但是在使用shader上,不仅仅需要创造力,还需要一些知识基础。

跟着古柳大佬的教程指导,找到了b站up主进华的threejs的入门课程,跟着课程,一步步的了解threejs。但是这个系列看完后(断断续续花了两个多星期),发现要用shader还是需要去了解一些数学几何知识,webgl还是得学。

由于本人除了上班的时间,几乎都在家里带娃,晚上娃睡了,刷刷小视频,就到了深夜。的确是很颓,很废.

初代的90后大姨(特指八青妹),已经被碾压在了沙滩上。但是内心对可视化还是很向往的。最大的动力和野心就是,下次幼儿园家长开放日的时候,想在幼儿们面前秀一波。

第一步:安装插件

就像上学前先买书包和笔一样,那用vscode来写webgl需要准备点啥呢? 哎,等等,不是先讲原理之类的吗?不好意思,八青妹讲不好,可看寒璃讲解的,很棒!也是八青妹学习的偶像大佬。

学习webgl就少不了编写shader程序,shader程序使用GLSL(OpenGL Shading Language)编写。 例如在vertexShader.js中的代码如下:

let vertexShader =`
  attribute vec3 a_position;
    void main() {
        gl_Position = vec4(a_position, 1.0);
    }
`
export default vertexShader;

在backtick内容区域的代码是无高亮的,这怎么能忍? 在vscode编辑器中安装插件comment-tagged-templates,在vertexShader.js里面添加注释/*glsl*/

let vertexShader = /*glsl*/`
  attribute vec3 a_position;
    void main() {
        gl_Position = vec4(a_position, 1.0);
    }
`
export default vertexShader;

但是重启后代码块并没有高亮显示。

原因很简单,没有安装glsl语言的插件库!安装插件库GLSL Syntax for VS Code,这样comment-tagged-templates读取/*glsl*/注释后,就能按照GLSL Syntax for VS Code的高亮规则来进行高亮了。

image.png

第二步:将基础的代码块分文件区分

准备四个js文件,一个做主要展示的app.js,一个是vertexShader.js,一个是fragmentShader.js,一个是initShaders.js。

image.png

当然还要准备一个html! 绘制一个底色为蓝色的400x400画布,画一个红点。

该案例为最简单的webgl案例了。其中有如何将顶点着色器和片元着色器进行关联之类的等等,我也不是很明白,所以建议,后面都用封装好的。只需要更改着色器里面的内容,而如何关联的用函数封装下吧。

也就是上述代码片段中Create Shaders和Create Program进行整合下

export default function initShaders(gl, vertexSource, fragmentSource) {
}

/**
 * Create Shades
 */
function createShader(gl, type, source) {
}

/**
 * Create Program
 */
function createProgram(gl, vertexShader, fragmentShader) {
    let program = gl.createProgram()
    if (!program) return null

    gl.attachShader(program, vertexShader)
    gl.attachShader(program, fragmentShader)

    gl.linkProgram(program)
    // link prgram result
    let linked = gl.getProgramParameter(program, gl.LINK_STATUS)
    if (linked) {
        return program
    } else {
        let error = gl.getProgramInfoLog(program)
        console.log('link program error: ' + error)
        gl.deleteProgram(program)
        gl.deleteShader(vertexShader)
        gl.deleteShader(fragmentShader)
        return null
    }
}

在原来的js中引入上述js文件


import initShaders from './initShaders.js'

let canvas = document.getElementById('webgl')
let gl = canvas.getContext('webgl')

// vertexShader, fragmentShader
let vertexShader = `
void main() {
    gl_Position = vec4(0.0, 0.5, 0.0, 1.0);
    gl_PointSize = 10.0;
}
`
let fragmentShader = `
    void main() {
        gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
    }
`
initShaders(gl, vertexShader, fragmentShader)

// 清空canvas画布
gl.clearColor(0.5, 0.5, 0.5, 1.0) // rgba()
gl.clear(gl.COLOR_BUFFER_BIT)

// 画一个点
gl.drawArrays(gl.POINTS, 0, 1)