webgl入门-基础三角形绘制

背景

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

开始

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

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

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

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

代码实践

着色器创建流程

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

下面代码不包含glsl代码

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:规定数据如何读取

代码体现

// 找出顶点着色器中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);

附一些语法规则定义:

webgl入门-基础三角形绘制_第1张图片

开始绘制

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

代码体现

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

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

ok,总结一下

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

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

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

webgl入门-基础三角形绘制_第2张图片

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

你可能感兴趣的:(webgl,webgl)