webgl入门-基础三角形绘制

背景

最近工作上频繁接触webgl,因为不熟悉每每看到shader中的语法总感觉脑袋大,所以打算开始从零学习一下webgl,文章只做记录学习历程,那就直接开始吧!

开始

可以配合着这个文章食用。

我还是对webgl有一些概念的,说一下我的理解就是用来对图元进行光栅化的程序,首先说光栅化是什么,我的理解是将看到的东西画到屏幕上,那这个过程会经历什么比如画一个三角形,首先我要确定三角形画在哪里也就是顶点的位置,然后确认顶点后填充颜色,颜色其实就是一个个像素组成的,gpu做的就是将一个个gpu渲染上颜色这个过程叫光栅化。

ok,总结一下,一个webgl着色器程序,它需要有两部分组成:

  1. 顶点着色器(VertexShader)
  2. 片元着色器(FragmentShader)

好,以上两个着色器即可组成一个着色器程序。

代码实践

着色器创建流程

  1. 首先获取webgl的上下文
  2. 编写顶点和片元着色器代码
  3. 实例创建顶点和片元shader
  4. 创建着色器程序Program,并注入两个shader

下面代码不包含glsl代码

javascript 复制代码
function initWebgl() {
    const canvas = document.getElementById('canvas');
    const gl = canvas.getContext('webgl');
    // 平面空间大小
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    // 清空画布
    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT);

    return gl;
}
const gl = initWebgl();

// 创建着色器方法,输入参数:渲染上下文,着色器类型,数据源
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);
}

const vertexShaderSource = document.querySelector('#vertex-shader-2d').text;
const fragmentShaderSource = document.querySelector('#fragment-shader-2d').text;

const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

// 创建着色器程序
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 program = createProgram(gl, vertexShader, fragmentShader);

至此准备工作已做好

数据传递流程

现在我想画一个三角形就需要用到顶点着色器,传递给它三个顶点的位置

  1. 首先先寻找要赋值的顶点着色器变量
  2. 创建一个缓冲区
  3. 再创建一个buffer,绑定在缓冲区中
  4. 将数据写入buffer
  5. enableVertexAttribArray:开启属性,这时变量和缓冲区建立好链接了
  6. vertexAttribPointer:规定数据如何读取

代码体现

javascript 复制代码
// 找出顶点着色器中a_position变量
// 这要注意:寻找属性值位置(和全局属性位置)应该在初始化的时候完成,而不是在渲染循环中。
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
// 创建一个缓冲
const positionBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 三个顶点坐标
const positions = [0, 0, 0, 0.5, 0.7, 0];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

// 告诉gl是用那个着色器程序
gl.useProgram(program);

// 启用属性
gl.enableVertexAttribArray(positionAttributeLocation);

// 告诉属性怎么从positionBuffer中读取数据 (ARRAY_BUFFER)
const size = 2; // 每次迭代运行提取两个单位数据
const type = gl.FLOAT; // 每个单位的数据类型是32位浮点型
const normalize = false; // 不需要归一化数据
const stride = 0; // 0 = 移动单位数量 * 每个单位占用内存(sizeof(type))
// 每次迭代运行运动多少内存到下一个数据开始点
const offset = 0; // 从缓冲起始位置开始读取
gl.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);

附一些语法规则定义:

开始绘制

需要制定绘制规则,因为gl不知道你是要画三个点还是一个三角形,还有程序执行次数。

代码体现

javascript 复制代码
// 设置图元类型为三角形
const primitiveType = gl.TRIANGLES;
const drawArraysOffset = 0;
// 程序执行次数
const count = 3;
gl.drawArrays(primitiveType, drawArraysOffset, count);

在顶点绘制完成后,gl能够知道哪些像素是需要通过片元着色器进行上色的,至此基础的三角形绘制完毕!

ok,总结一下

一个基础的着色器程序主要流程是:

  1. 创建webgl上下文
  2. 创建顶点着色器和片元着色器组成一个完整的着色器程序
  3. 数据传递,今天的demo只进行了顶点数据传递
  4. 执行着色器程序(可配置执行规则)

本人对数据传递有些模糊,特画了个流程图清晰一下

附文章:

https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-fundamentals.html

相关推荐
_oP_i1 天前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
新中地GIS开发老师2 天前
WebGIS和WebGL的基本概念介绍和差异对比
学习·arcgis·webgl
_oP_i3 天前
Unity 中使用 WebGL 构建并运行时使用的图片必须使用web服务器上的
前端·unity·webgl
flying robot6 天前
Three.js简化 WebGL 的使用
webgl
小彭努力中6 天前
114. 精灵模型标注场景(贴图)
前端·3d·webgl·贴图
小彭努力中6 天前
109. 工厂光源(环境贴图和环境光)
前端·深度学习·3d·webgl·贴图
小彭努力中7 天前
112. gui辅助调节光源阴影
前端·深度学习·3d·webgl
refineiks8 天前
three.js绘制宽度大于1的线,并动态新增顶点
3d·图形渲染·webgl
小彭努力中9 天前
102. 管道漫游案例
前端·3d·webgl
小彭努力中9 天前
107. 阴影范围.shadow.camera
前端·深度学习·3d·webgl