lesson1 点的绘制
静态点
<!DOCTYPE html>
<body>
<!-- 顶点着色器源码 -->
<script type="shader-source" id="vertexShader">
void main(){
//声明顶点位置
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
//声明要绘制的点的大小。
gl_PointSize = 10.0;
}
</script>
<!-- 片元着色器源码 -->
<script type="shader-source" id="fragmentShader">
void main(){
//设置像素颜色为红色
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
</script>
<canvas id="canvas"></canvas>
<!-- javascript -->
<script src="./1webgl-helper.js"></script>
<script>
drawPoint('#canvas', '#vertexShader', '#fragmentShader')
</script>
</body>
</html>
var random = Math.random;
function randomColor() {
return {
r: random() * 255,
g: random() * 255,
b: random() * 255,
a: random() * 1
};
}
function drawPoint(canvasSelector, vertexShaderSelector, fragmentShaderSelector, isDynamic) {
// #获取 WebGL 绘图环境
var canvas = document.querySelector(canvasSelector);
var gl = canvas.getContext('webgl') || canvas.getContext("experimental-webgl");
// #创建顶点着色器对象
// ##获取顶点着色器源码
var vertexShaderSource = document.querySelector(vertexShaderSelector).innerHTML;
// ##创建顶点着色器对象
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
// ##将源码分配给顶点着色器对象
gl.shaderSource(vertexShader, vertexShaderSource);
// ##编译顶点着色器程序
gl.compileShader(vertexShader);
// #创建片元着色器
// ##获取片元着色器源码
var fragmentShaderSource = document.querySelector(fragmentShaderSelector).innerHTML;
// ##创建片元着色器程序
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
// ##将源码分配给片元着色器对象
gl.shaderSource(fragmentShader, fragmentShaderSource);
// 编译片元着色器
gl.compileShader(fragmentShader);
// #创建着色器程序
var program = gl.createProgram();
//将顶点着色器挂载在着色器程序上。
gl.attachShader(program, vertexShader);
//将片元着色器挂载在着色器程序上。
gl.attachShader(program, fragmentShader);
//链接着色器程序
gl.linkProgram(program);
// #使用刚创建好的着色器程序。
gl.useProgram(program);
if(isDynamic) {
// 此处省略,虽然是学习记录,担心侵权
}
//#绘制
//设置清空画布颜色为黑色。
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//用上一步设置的清空画布颜色清空画布。
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制点。
gl.drawArrays(gl.POINTS, 0, 1);
}
动态点
<!DOCTYPE html>
<body>
<!-- 顶点着色器源码 -->
<script type="shader-source" id="vertexShader">
precision mediump float;
// 接收点在 canvas 坐标系上的坐标 (x, y)
attribute vec2 a_Position;
// 接收 canvas 的宽高尺寸
attribute vec2 a_Screen_Size;
void main(){
//start 将屏幕坐标系转化为裁剪坐标(裁剪坐标系)
vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0;
position = position * vec2(1.0, -1.0);
gl_Position = vec4(position, 0, 1);
//end 将屏幕坐标系转化为裁剪坐标(裁剪坐标系)
//声明要绘制的点的大小。
gl_PointSize = 10.0;
}
</script>
<!-- 片元着色器源码 -->
<script type="shader-source" id="fragmentShader">
//设置浮点数精度为中等精度
precision mediump float;
//接收 JavaScript 传过来的颜色值(RGBA)。
uniform vec4 u_Color;
void main(){
//将普通的颜色表示转化为 WebGL 需要的表示方式,即将【0-255】转化到【0,1】之间。
vec4 color = u_Color / vec4(255, 255, 255, 1);
gl_FragColor = color;
}
</script>
<canvas id="canvas" width="1000px" height="600px"></canvas>
<!-- javascript -->
<script src="./1webgl-helper.js"></script>
<script>
drawPoint('#canvas', '#vertexShader', '#fragmentShader', true)
</script>
</body>
</html>
api
GLSL
- gl_Position: 内置变量,用来设置顶点坐标。
- gl_PointSize: 内置变量,用来设置顶点大小。
- vec2:2 维向量容器,可以存储 2 个浮点数。
- gl_FragColor: 内置变量,用来设置像素颜色。
- vec4:4 维向量容器,可以存储 4 个浮点数。
- precision:精度设置限定符,使用此限定符设置完精度后,之后所有该数据类型都将沿用该精度,除非单独设置。
- 运算符:向量的对应位置进行运算,得到一个新的向量。 vec * 浮点数: vec2(x, y) * 2.0 = vec(x * 2.0, y * 2.0)。 vec2 * vec2:vec2(x1, y1) * vec2(x2, y2) = vec2(x1 * x2, y1 * y2)。 加减乘除规则基本一致。但是要注意一点,如果参与运算的是两个 vec 向量,那么这两个 vec 的维数必须相同。
JavaScript 程序如何连接着色器程序
createShader:创建着色器对象 shaderSource:提供着色器源码 compileShader:编译着色器对象 createProgram:创建着色器程序 attachShader:绑定着色器对象 linkProgram:链接着色器程序 useProgram:启用着色器程序 JavaScript 如何往着色器中传递数据
JavaScript 如何往着色器中传递数据
getAttribLocation:找到着色器中的 attribute 变量地址。 getUniformLocation:找到着色器中的 uniform 变量地址。 vertexAttrib2f:给 attribute 变量传递两个浮点数。 uniform4f:给uniform变量传递四个浮点数。
WebGL 绘制函数
drawArrays: 用指定的图元进行绘制。
WebGL 图元
gl.POINTS: 将绘制图元类型设置成点图元。
绘制原理
vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0
上面这句代码用来将浏览器窗口坐标转换成裁剪坐标,之后通过透视除法,除以 w 值(此处为 1 )转变成设备坐标(NDC坐标系)。这个算法首先将(x,y) 转化到【0, 1】区间,再将 【0, 1】之间的值乘以 2 转化到 【0, 2】区间,之后再减去 1 ,转化到 【-1, 1】之间的值,即 NDC 坐标。