目录
- 1 前言
- 2 新建html页面
- 3 着色器介绍
- 3.1 顶点着色器、片元着色器与光栅化的概念
- 3.2 声明顶点着色器
- 3.3 声明片元着色器
- 4 坐标系(右手系)介绍
- 5 着色器初始化
- 5.1 给一个画布canvas
- 5.2 获取WebGL对象
- 5.3 创建着色器对象
- 5.4 获取着色器对象的源
- 5.5 绑定着色器的源
- 5.6 编译着色器
- 5.7 创建并关联项目
- 6 绘制
- 6.1 声明点的位置、大小和颜色
- 6.2 绘制
- 6.3 完整代码
- 7 总结
1 前言
上一篇中我们对WebGL
进行了简单的介绍,从本篇开始,正式进入实战。那么我们第一步需要做什么呢?当然是环境的搭建,以及Shader
的初始化。废话不多说,咱们直接开整。
2 新建html页面
其实搭建WebGL
的环境十分简单,因为WebGL
在在浏览里运行的,因此只需要新建一个html
页面就行了。
3 着色器介绍
3.1 顶点着色器、片元着色器与光栅化的概念
那么什么是顶点着色器?什么是片元着色器?什么叫做光栅化?这三个概念对我们学习WebGL
还是很重要的,在学习WebGL
的过程中,我曾经常困惑于片元、光栅化的概念,现在我们就用一张图来解释下。假设我们要在屏幕上画一个三角形。
如图所示,v1 v2 v3
就叫做顶点,三角形内部的一个个红色的点,就叫做片元,也叫片段,其实它的意思就是一个个像素。注意像素应该是密密麻麻占满了整个三角形,这里为了示意只画出来了少部分。屏幕是什么?屏幕是一种光栅设备,因此把任何一种图形,不论是二维三维的,画在屏幕上,就叫做光栅化。光栅化的概念就这么简单。看过很多其他教程,只说光栅化,不说光栅化是什么意思,很令人困惑。
3.2 声明顶点着色器
声明顶点着色器很简单,只需要写一个script
标签,注意type
<script id="vertex-shader" type="x-shader/x-vertex">
</script>
3.3 声明片元着色器
声明片元着色器也很简单,只需要写一个script
标签,同样注意type
<script id="vertex-shader" type="x-shader/x-fragment">
</script>
4 坐标系(右手系)介绍
现在我们来做一个最简单的例子,画一个点,这个点的坐标分别是x=0.5,y=0.5,z=0
。在此之前我们先明确一下WebGL
中的坐标系:X轴向右,Y轴向上,Z轴向外
。右手握拳,四指从X
到Y
转动,大拇指的方向就是Z
轴的方向。很明显,WebGL
中默认是右手系。因为z=0
,因此这个点在xy
所形成的平面内。
5 着色器初始化
初始化着色也很简单,我们先给出步骤,然后一步步来说明
- 创建着色器对象
- 获取着色器对象的源代码
- 绑定着色器的源
- 编译着色器
- 创建并关联项目
5.1 给一个画布canvas
<canvas id="canvas" width="1080" height="720"></canvas>
5.2 获取WebGL对象
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");
5.3 创建着色器对象
//创建着色器对象
let vertexShader = gl.createShader(gl.VERTEX_SHADER);
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
5.4 获取着色器对象的源
//获取着色器对象的源
let vertexSource = document.getElementById("vertex-shader").innerText;
let fragmentSource = document.getElementById("fragment-shader").innerText;
因为这里我们要用的innerText,也就是script标签里的文本,因此也可以不把文本写在script标签里,而是直接手写字符串,这样的不好处就是没有智能提示,比如:
let vertexSource = “…”
let fragmentSource = “…”
5.5 绑定着色器的源
//绑定着色器的源
gl.shaderSource(vertexShader,vertexSource);
gl.shaderSource(fragmentShader,fragmentSource);
5.6 编译着色器
//编译着色器
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
5.7 创建并关联项目
//创建并关联项目
let program = gl.createProgram();
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
6 绘制
现在我们的准备工作已经完事了,可以开始绘制了。首先需要补齐script
标签的内容
6.1 声明点的位置、大小和颜色
<script id="vertex-shader" type="x-shader/x-vertex">
//声明一个点,vec2表示2维向量
attribute vec2 aPos;
void main(){
//点的大小10像素
gl_PointSize = 10.0;
//点的位置,将vec2补齐为vec4
gl_Position = vec4(aPos,0.0,1.0);
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
void main(){
//点的颜色,rgba形式,红色
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
</script>
6.2 绘制
//绘制
let aPos = gl.getAttribLocation(program,"aPos");
//设置顶点的值,该顶点是用二维坐标表示的,vertexAttrib2f表示vertex中的attribute属性,2个float值
gl.vertexAttrib2f(aPos,0.5,0.5);
//绘制点,从第0个点开始,绘制两个
gl.drawArrays(gl.POINTS,0,2);
改为x=0,y=0看看效果,点回到了正中间。
6.3 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#canvas{
border: 1px solid #ccc;
}
</style>
</head>
<body>
<canvas id="canvas" width="1080" height="720"></canvas>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec2 aPos;
void main(){
gl_PointSize = 10.0;
gl_Position = vec4(aPos,0.0,1.0);
//gl_Position = aPos;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
void main(){
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
</script>
<script>
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");
//创建着色器对象
let vertexShader = gl.createShader(gl.VERTEX_SHADER);
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
//获取着色器对象的源
let vertexSource = document.getElementById("vertex-shader").innerText;
let fragmentSource = document.getElementById("fragment-shader").innerText;
//绑定着色器的源
gl.shaderSource(vertexShader,vertexSource);
gl.shaderSource(fragmentShader,fragmentSource);
//编译着色器
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
console.log(gl.getShaderInfoLog(vertexShader));
//创建并关联项目
let program = gl.createProgram();
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
//绘制
let aPos = gl.getAttribLocation(program,"aPos");
//设置顶点的值,该顶点是用二维坐标表示的
gl.vertexAttrib2f(aPos,0.0,0.0);
gl.drawArrays(gl.POINTS,0,2);
</script>
</body>
</html>
7 总结
本篇博文中我们梳理了WebGL中整个的绘制流程,右手坐标系的指向,顶点着色器、片元着色器、光栅化等概念的含义,并以一个最简单的示例,点绘制来演示Shader
的初始化过程,代码并不复杂,希望读者仔细体会,回见~