WebGL 读书笔记 vertax,fragment

1. 基础

WebGL中有两种基本着色器:

  • 顶点着色器

    • 顶点着色器用来描述顶点特性,如位置、颜色。顶点是指二维或者三维空间中的一个点,比如二维或者三位图形的端点或交点。
    • 主要用来控制点的位置和大小
    • GL内置变量

      • vec4 gl_Position 表示顶点位置
      • float gl_PointSize 表示点的尺寸(像素数)
  • 片元着色器(也称片段着色器)

    • 可以理解为,为顶点着色器定义出来的区域进行颜色渲染填充。如果没有定义片元着色器,那么将由GPU自行进行差值填充
    • 内置变量

      • vec4 gl_FragColor 指定片元颜色,RGBA格式。
  • 归一化

绘制流程: 顶点着色器标记坐标-> 片元着色器标记颜色-> gl.drawArrays进行渲染

1.1 内部变量

1.1.1 attribute(存储限定符) 声明变量

  • attributeuniform 都是用来定义openGL中可与JS进行通讯交互的变量
  • 但是 attribute 被JS用来传输与顶点相关的数据。
  • uniform 变量传输的是对于所有顶点相同的数据或者与顶点无关的数据。
  • WebGL函数命名遵循 <基本函数名><参数个数><参数类型>进行。

    • vertexArrtib1f 传递1个值
    • vertexArrtib2f 传递2个值
    • vertexArrtib3f 传递3个值
    • vertexArrtib4f 传递4个值
    • f表示浮点数 i表示整数
"use strict";

var vertexShaderSource = `#version 300 es
// 1. 在顶点着色器中声明attribute变量
// an attribute is an input (in) to a vertex shader.
// It will receive data from a buffer
in vec4 a_position;

// all shaders have a main function
void main() {
 // 2. 将attribute变量赋值给gl_Position
  // gl_Position is a special variable a vertex shader
  // is responsible for setting
  gl_Position = a_position;
}
`;

var fragmentShaderSource = `#version 300 es

// fragment shaders don't have a default precision so we need
// to pick one. highp is a good default. It means "high precision"
precision highp float;

// we need to declare an output for the fragment shader
out vec4 outColor;

void main() {
  // Just set the output to a constant redish-purple
  outColor = vec4(1, 0, 0.5, 1);
}
`;

function createShader(gl, type, source) {
  var shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
  if (success) {
    return shader;
  }

  console.log(gl.getShaderInfoLog(shader));  // eslint-disable-line
  gl.deleteShader(shader);
  return undefined;
}

function createProgram(gl, vertexShader, fragmentShader) {
  var program = gl.createProgram();
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);
  var success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (success) {
    return program;
  }

  console.log(gl.getProgramInfoLog(program));  // eslint-disable-line
  gl.deleteProgram(program);
  return undefined;
}

function main() {
  // Get A WebGL context
  var canvas = document.querySelector("#c");
  var gl = canvas.getContext("webgl2");
  if (!gl) {
    return;
  }

  // create GLSL shaders, upload the GLSL source, compile the shaders
  var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
  var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

  // Link the two shaders into a program
  var program = createProgram(gl, vertexShader, fragmentShader);

  // look up where the vertex data needs to go.
  // 3. 获取attribute变量存储位置
  var positionAttributeLocation = gl.getAttribLocation(program, "a_position");

  // Create a buffer and put three 2d clip space points in it
  var positionBuffer = gl.createBuffer();

  // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
  // 4. 将JS中的顶点位置坐标信息传输给webgl
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

  var positions = [
    0, 0,
    0, 0.5,
    0.7, 0,
  ];
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

  // Create a vertex array object (attribute state)
  var vao = gl.createVertexArray();

  // and make it the one we're currently working with
  gl.bindVertexArray(vao);

  // Turn on the attribute
  gl.enableVertexAttribArray(positionAttributeLocation);

  // Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
  var size = 2;          // 2 components per iteration
  var type = gl.FLOAT;   // the data is 32bit floats
  var normalize = false; // don't normalize the data
  var stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
  var offset = 0;        // start at the beginning of the buffer
  gl.vertexAttribPointer(
      positionAttributeLocation, size, type, normalize, stride, offset);

  webglUtils.resizeCanvasToDisplaySize(gl.canvas);

  // Tell WebGL how to convert from clip space to pixels
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

  // Clear the canvas
  gl.clearColor(0, 0, 0, 0);
  gl.clear(gl.COLOR_BUFFER_BIT);

  // Tell it to use our program (pair of shaders)
  gl.useProgram(program);

  // Bind the attribute/buffer set we want.
  gl.bindVertexArray(vao);

  // draw
  var primitiveType = gl.TRIANGLES;
  var offset = 0;
  var count = 3;
  gl.drawArrays(primitiveType, offset, count);
}

main();

1.1.2 uniform 声明变量

  • 用来传输那些与顶点相关或者其他无关的数据。
  • js使用 gl.uniform4f() 向webgl传递数据,并且4f的格式规范跟之前的定义相同。

1.1.3 varying 声明变量

  • varying 是用于 vertex(顶点着色器)fragment shader(片元着色器) 之间做数据传递用的。
  • 如果顶点着色器中有类型和命名相同的 varying 变量,那么顶点着色器赋给该变量的值就会被自动传入片元着色器。
  • 一般vertex shader修改 varying 变量的值,然后 fragment shader 使用该 varying 变量的值。
  • 因此 varying 变量在 vertexfragment shader 二者之间的声明必须是一致的。application不能使用此变量。
let VSHADER_SOURCE =   
"attribute vec4 a_Position;\n" +  
"attribute float a_PointSize;\n" +  
"attribute vec4 a_Color;\n" +  
"varying vec4 v_Color;\n" +   
// varying 声明  
"uniform mat4 u_ModelMatrix;\n" +  
"void main() {\n" +  
"  gl_Position = u_ModelMatrix * a_Position;\n" +  
"  gl_PointSize = a_PointSize;\n" +  
"  v_Color = a_Color;\n" +  
 // 将颜色赋值给v_Color,用于传递给片元着色器
"}\n"  
let FSHADER_SOURCE =   
"precision mediump float;\n" +  
"uniform vec4 u_FragColor;\n" +  
"varying vec4 v_Color;\n" +   
// 从顶点着色器传送过来的数据 恢复v_Color数据
// 变量名称必须一致
"void main() {\n" +  
"  gl_FragColor = v_Color;\n" +  
"}\n",

varying变量的作用和内插过程

varying变量。只能是float、vec2、vec3、vec4、mat2、mat3、mat4。必须全局。最少支持8个。
顶点着色器中的v_Color在传入片元着色器之前经过了内插过程。WebGL根据我们传入的颜色值,自动计算出所有片元的颜色,赋值给片元着色器中的v_Color

图元装配到光栅化
62252-gn1lyssxta.png

  1. 缓冲区对象中第一个坐标传递给a_Position继而被赋值给gl_Position,赋值后改顶点进入图形装配区,并储存。
  2. 重复执行顶点着色器,将所有坐标点传入并存储在装配区。
  3. 装配图形。根据gl.drawArrays()第一个参数决定如何装配顶点。
  4. 光栅化。将装配好的图元转化为片元(像素)。
  5. 光栅化结束后,逐片元调用片元着色器。每次处理一个片元,计算出该片元颜色,写入颜色缓冲区。直到所有片元被处理完,浏览器显示出结果。

摄影爱好者,全栈工程师,游戏玩家,积木苦手,超穷手办收藏爱好者

发表评论