目录
1 前言2 新建html页面3 着色器介绍3.1 顶点着色器、片元着色器与光栅化的概念3.2 声明顶点着色器3.3 声明片元着色器 4 坐标系(右手系)介绍5 着色器初始化5.1 给一个画布canvas5.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
的初始化过程,代码并不复杂,希望读者仔细体会,回见~