Skip to content

wegbl01-绘制流程 #103

@adodo0829

Description

@adodo0829

webgl 绘制流程

渲染管线, 就是绘制流程, 流程包含哪些步骤

基础概念

  • 图元: 基本绘图元素

    • 线
    • 面(三角形)
  • 基本步骤

    • 获取 WebGL 上下文
    • 初始化着色器
    • 设置缓冲区
    • 绘制
      前两个步骤通畅仅需要执行一次,而后面的步骤会随着场景属性变化而执行多次

示例

1.获取 WebGL 上下文

<canvas id="canvas"></canvas>

<script>
  const canvas = document.querySelector("#canvas");
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  //二维画笔
  // const gl=canvas.getContext('2d');
  //三维画笔
  const gl = canvas.getContext("webgl");
  //声明颜色 rgba
  gl.clearColor(1, 1, 0, 1);
  //刷底色
  gl.clear(gl.COLOR_BUFFER_BIT);

  //css颜色
  const rgbaCss = "rgba(255,100,0,1)";
  //正则
  const reg = RegExp(/\((.*)\)/);
  //捕捉数据
  const rgbaStr = reg.exec(rgbaCss)[1];
  //加工数据
  const rgba = rgbaStr.split(",").map((n) => parseInt(n));
  const r = rgba[0] / 255;
  const g = rgba[1] / 255;
  const b = rgba[2] / 255;
  const a = rgba[3];
  //声明颜色 rgba
  gl.clearColor(r, g, b, a);
  //刷底色
  gl.clear(gl.COLOR_BUFFER_BIT);
  //设置视口的大小
  gl.viewport(0, 0, canvas.width, canvas.height);
</script>

2.初始化着色器

// 顶点着色器
const vertexShader = `
// 类型是 vec3,即三元组浮点数向量(3-component floating point vector)
attribute vec3 aPos;
void main(){
    gl_Position = vec4(aPos, 1);
}
`;

// 片段着色器
const fragmentShader = `
void main() {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
`;

function initShaders(gl, vsSource, fsSource) {
  //创建程序对象
  const program = gl.createProgram();
  //建立着色对象
  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
  //把顶点着色对象装进程序对象中
  gl.attachShader(program, vertexShader);
  //把片元着色对象装进程序对象中
  gl.attachShader(program, fragmentShader);
  //连接webgl上下文对象和程序对象
  gl.linkProgram(program);
  //启动程序对象
  gl.useProgram(program);
  //将程序对象挂到上下文对象上
  gl.program = program;
  return true;
}

function createProgram(gl, vsSource, fsSource) {
  //创建程序对象
  const program = gl.createProgram();
  //建立着色对象
  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
  //把顶点着色对象装进程序对象中
  gl.attachShader(program, vertexShader);
  //把片段着色对象装进程序对象中
  gl.attachShader(program, fragmentShader);
  //连接webgl上下文对象和程序对象
  gl.linkProgram(program);
  return program;
}

function loadShader(gl, type, source) {
  //根据着色类型,建立着色器对象
  const shader = gl.createShader(type);
  //将着色器源文件传入着色器对象中
  gl.shaderSource(shader, source);
  //编译着色器对象
  gl.compileShader(shader);
  //返回着色器对象
  return shader;
}

3.设置缓冲区

WebGL 中,缓冲区的作用至关重要,需要绘制的几何体的所有信息都是通过缓冲区来传递给着色器程序的,比如几何体的坐标、颜色等等。
在下面的代码中,我们使用了顶点缓冲区对象(Vertex Buffer Object,VBO),该缓冲区就是用来存放几何体的顶点信息。

function setupBuffer() {
  // 对于一个点来说,它仅包含一个顶点,一个顶点包含 x、y、z 三个坐标值,因此我们定义的 vertex 数组包含三个元素:0、0、0。
  let vertex = [0, 0, 0];

  // 创建缓冲区对象
  let vertexBuffer = gl.createBuffer();

  // WebGL中,使用一个缓冲区前需要对其进行绑定操作,一旦绑定后,后续的缓冲区操作都会在当前绑定的缓冲区上进行,直到我们取消绑定或者绑定了其他的缓冲区对象
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

  // bufferData方法传递数据时使用了Float32Array这个typed array,WebGL不支持直接使用JavaScript的原始数组类型。
  // 使用typed array可以以二进制方式来操作数据,同时也指定了数据的类型。
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertex), gl.STATIC_DRAW);

  let aVertexPosition = gl.getAttribLocation(glProgram, "aPos");
  // 将aPos属性指向当前绑定的顶点缓冲区对象,这样aPos和vertexBuffer对象就关联了
  gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aVertexPosition);
}
void vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);

// index:属性的索引,通过 getAttribLocation 可以获得。你可以理解成属性的地址。
// size:每个顶点包含多少个数值,最简单的情况是三个,即x、y、z三维坐标。
// type:指定缓冲区的数据类型。
// nomalized:和数据转换有关系,一般用false。
// stride:说明数据存储的方式,单位是字节。0表示一个属性的数据是连续存放的,非连续存放的情况我们后面会讲到。
// offset:该属性在每个顶点数据中偏移值,单位是字节并且是type的整数倍。这个值是配合stride一同使用的,0表示从头开始读取

4.绘制

调用 drawArrays 将点绘制到屏幕上

function draw() {
  // drawArrays方法将会使用处于启用状态的包含坐标信息的属性,即本例中的aPos,我们看到它在之前已经被启用并且指向包含顶点信息的VBO
  gl.drawArrays(gl.POINTS, 0, 1);
}

// void drawArrays(GLenum mode, GLint first, GLsizei count)
// mode:绘制模式,gl.POINTS 常量表示点。
// first:第一个元素所在位置,即偏移量,32bit 整型。
// count:绘制的元素个数,即顶点的个数,32bit 整型。

小结

  • 绘制流程(渲染管线)

vertex buffer objects(coordinates(坐标数组)) <=(point to)= { vertex shader(attributes) + fragment shader(fragment buffer) } =(link)=> program

  • 顶点缓冲区对象 Vertex Buffer Objects (VBO)
    顶点缓冲区(后文统一用 VBO 来表示)用来存放几何体坐标,此外和顶点相关的其它信息也会存放在 VBO 中,例如法向量、颜色、纹理坐标。总之和顶点相关的信息都会放在这里

  • 顶点着色器 Vertex Shader
    顶点着色器会针对每个顶点执行。其中的代码是针对一个顶点的数据操作,比如一个顶点的坐标、颜色等等。
    这些信息是通过属性来表示,属性指向相应的 VBO,这样就可以将数据读取进来。

  • 片段着色器 Fragment Shader
    片断着色器负责计算输出到屏幕的像素颜色,在本文的例子中,就是负责给顶点上颜色。
    后面我们会看到更加负责的颜色计算过程,颜色会受到光照、纹理的影响而变化

  • 帧缓冲区 Framebuffer
    帧缓冲区用来存放最终需要显示的位图信息,它包含了一系列的像素点,这些像素点最终会被输出到屏幕上。

  • 绘制修改

// 修改点大小
// 顶点着色器中内置的gl_PointSize变量可以用来修改点尺寸,单位为像素
gl_PointSize = 20.0;

// 修改点颜色
gl_FragColor = vec4(178.0 / 255.0, 105.0 / 255.0, 9.0 / 255.0, 1.0);

// 修改点位置
// 点坐标是在vertex变量中定义的
let vertex = [0.5, 0.5, 0];
// 修改x和y坐标为0.5, 原点为中心, 范围[-1, 1]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions