webGL学习笔记(一)

94 阅读4分钟

一、 最短的教程

<body onload="main()">
  <canvas id="glcanvas" width="640" height="480">
    你的浏览器似乎不支持或者禁用了 HTML5 <code>&lt;canvas&gt;</code> 元素。
  </canvas>
</body
// 从这里开始
function main() {
  // 获取canvas画布
  const canvas = document.querySelector("#glcanvas");
  // 初始化 WebGL 上下文
  const gl = canvas.getContext("webgl");

  // 确认 WebGL 支持性
  if (!gl) {
    alert("无法初始化 WebGL,你的浏览器、操作系统或硬件等可能不支持 WebGL。");
    return;
  }

  // 使用完全不透明的黑色清除所有图像
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  // 用上面指定的颜色清除缓冲区
  gl.clear(gl.COLOR_BUFFER_BIT);
}
  • clearColor(r,g,b,a) 参数:红、绿、蓝、透明度,其定义域 [0,1];(注意一下定义域范围)
  • 一旦指定了背景色,背景色就会驻存在 WebGL 系统中,在下一次调用 gl.clearColor()之前不会改变。换句话说,如果将来什么时候还想用同一个颜色清空绘图区,没必要再指定一次背景色。

二、着色器

1. 顶点着色器

顶点着色器的内置变量

类型和变量名描述
vec4 gl_Position表示顶点位置
vec4 gl_PointSize表示顶点的尺寸(像素数)

注意: gl_Position 必须被赋值,否则着色器无法正常工作; gl_PointSize 并不是必须的,若不赋值默认是1.0

齐次坐标:gl_Position:(x,y,z,w), 第四个分量w是齐次坐标。

  • 齐次坐标(x,y, z, w)等价于三维坐标(x/w, y/x, z/w)。如果w=1, 可以将其当作三维坐标使用。
  • w必须大于等于0
  • w趋近0, 那么他所表示的点将趋近无穷远,所以在齐次坐标可以有无穷的概念。
  • 齐次坐标存在,使得用矩阵乘法来描述顶点变换成为可能,三维图形系统在计算过程中,通常用齐次坐标来表示顶点的三维坐标。

2. 片元着色器

片元着色器的内置变量webgl学习笔记

类型和变量名描述
vec4 gl_FragColor指定片元颜色(RGBA格式)

3. 绘制操作

类型和变量名描述
vec4 gl_drawArrays(mode, first,count)执行顶点着色器,按照mode参数指定方式绘制图形
  • mode: 指定绘制的万式,可接收以下常量符号:g1.POINTS,g1.LINES,g1.LINE_STRIP,g1.LINE_LOOP, g1.TRIANGLES,g1.TRIANGLE_STRIP,g1.TRIANGLE_FAN
  • first: 指定从哪个顶点开始绘制(整型数)
  • count: 指定绘制需要多少个顶点

调用gl.drawArrays() 时, 顶点着色器将被执行 count 次,每次处理一个顶点。

4. WebGL 坐标系

4.1 canvas坐标系

image.png

4.2 webGL坐标系

image.png

5. attribute 变量 和 uniform 变量

  • attribute: 传输和顶点相关的数据 (被用来从外部向内部顶点着色器内传输数据,只有顶点着色器能使用他)
  • uniform:与顶点无关的数据

5.1 attribute 获取和赋值

5.1.1 获取 attribute 变量的存储位置
类型和变量名描述
gl.getAttribLocation(program, name)获取由name参数指定的attribute 变量的存储地址
5.1.2 attribute 变量赋值
类型和变量名描述
gl.vertexAttrib3f(location, v0, v1, v2)获取由name参数指定的attribute 变量的存储地址

同族函数:
g1.vertexAttrib1f(location,v0)
g1.vertexAttrib2f(location,v0,v1)
g1.vertexAttrib3f(1ocation,v0,v1,v2)
g1.vertexAttrib4f(location,v0,v1,v2,v3)

5.2 uniform 获取和赋值

只有顶点着色器才能使用attribute变量,使用片元着色器时,你就需要使用uniform变量。或者,你可以使用varying变量。

5.2.1 获取 uniform 变量的存储位置
类型和变量名描述
gl.getUniformLocation(program, name)获取由name参数指定的 uniform 变量的存储地址
5.2.2 uniform 变量 赋值
类型和变量名描述
gl.uniform4f (program, v0, v1, v2, v3, v4)将数据(v0, v1, v2, v3) 传输给由 location 参数指定的uniform变量

同族函数:
g1.uniform1f(location,v0)
g1.uniform2f(location,v0,v1) g1.uniform3f(location,v0,v1,v2)
g1.uniform4f(location,v0,v1,v2,v3)

三、通过鼠标点击绘点

// ClickedPints.js (c) 2012 matsuda
// Vertex shader program
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  gl_PointSize = 10.0;\n' +
  '}\n';

// Fragment shader program
var FSHADER_SOURCE =
  'void main() {\n' +
  '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
  '}\n';

function main() {
  // Retrieve <canvas> element
  var canvas = document.getElementById('webgl');

  // Get the rendering context for WebGL
  var gl = getWebGLContext(canvas);
  if (!gl) {
    console.log('Failed to get the rendering context for WebGL');
    return;
  }

  // Initialize shaders
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }

  // // Get the storage location of a_Position
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  if (a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return;
  }

  // Register function (event handler) to be called on a mouse press
  canvas.onmousedown = function(ev){ click(ev, gl, canvas, a_Position); };

  // Specify the color for clearing <canvas>
  gl.clearColor(0.0, 0.0, 0.0, 1.0);

  // Clear <canvas>
  gl.clear(gl.COLOR_BUFFER_BIT);
}

var g_points = []; // The array for the position of a mouse press
function click(ev, gl, canvas, a_Position) {
  var x = ev.clientX; // x coordinate of a mouse pointer
  var y = ev.clientY; // y coordinate of a mouse pointer
  var rect = ev.target.getBoundingClientRect() ;

  x = ((x - rect.left) - canvas.width/2)/(canvas.width/2);
  y = (canvas.height/2 - (y - rect.top))/(canvas.height/2);
  // Store the coordinates to g_points array
  g_points.push(x); g_points.push(y);

  // Clear <canvas>
  gl.clear(gl.COLOR_BUFFER_BIT);

  var len = g_points.length;
  for(var i = 0; i < len; i += 2) {
    // Pass the position of a point to a_Position variable
    gl.vertexAttrib3f(a_Position, g_points[i], g_points[i+1], 0.0);

    // Draw
    gl.drawArrays(gl.POINTS, 0, 1);
  }
}

webgl 和 canvas 坐标转换可参考文章: juejin.cn/post/706736…