基本图形
基本图形的绘制和顶点的绘制差不多,只需要设置gl.drawArrays()的mode参数对应的值,其他图形都是在基本图形上构成的。
gl.drawArrays(mode, first, count)
mode的可选参数详解
基本图形 | mode参数 | 描述 |
---|---|---|
点 | gl.POINTS | 一系列点,绘制在v0,v1,v2…处 |
线段 | gl.LINES | 一系列单独的线段,绘制在(v0,v1)、(v2,v3)、(v4,v5)…处,如果点的个数是奇数,最后一个点将被忽略 |
线条 | gl.LINE_STRIP | 一系列连接的线段,被绘制在(v0,v1)、(v1,v2)、(v2,v3)…处,第1个点是第一条线段的起点,第2点是第1条线段的终点和第2条线段的起点…最后一个点是最后一条线段的终点 |
回路线条 | gl.LINE_LOOP | 一系列连接的线段。与gl.LINE_STRIP绘制的线段相比,增加了一条从最后一个点到第1个点的线段。线段被绘制在(v0,v1)、(v1,v2)…(vn,v0)处,其中vn是最后一个点 |
三角形 | gl.TRIANGLES | 一系列单独的三角形,绘制在(v0,v1,v2),(v3,v4,v5)…处,如果点的个数不是三的整数倍,余下的点将被忽略 |
三角带 | gl.TRIANGLE_STRIP | 一些了带状的三角形,前三个点构成了第1个三角形,从第2个点开始的又三个点构成第2个三角形 (该三角形与前一个三角形共享一条边)。这些三角形被绘制在(v0,v1,v2)、(v2,v1,v3)、(v2,v3,v4)…处,按照逆时针绘制 |
三角扇面 | gl.TRIANGLE_FAN | 一系列三角形组成的类似于扇形的图形,前三个点构成了第1个三角形,第4个点和前一个三角形的最后一条边 组成了接下来的一个三角形。这些三角形被绘制在(v0,v1,v2)、(v0,v2,v3)、(v0,v3,v4)…处 |
第2个三角形是(v2,v1,v3)而不是(v1,v2,v3),这是为了保证第2个三角形的绘制也是按照逆时针的顺序执行。
图形示例:
示例代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>基本图形</title>
<script type="text/javascript" src="js/lib/webgl-debug.js" ></script>
<script type="text/javascript" src="js/lib/webgl-utils.js" ></script>
<script type="text/javascript" src="js/lib/cuon-utils.js" ></script>
</head>
<body>
<canvas id='canvas' width="600" height="600">该浏览器不支持WebGL!</canvas>
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec4 a_Position;
void main(){
gl_Position=a_Position;
//gl_PointSize=5.0;//绘制基本图形时,点的大小无用
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
void main(){
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}
</script>
<script>
(function main(){
var canvas=document.getElementById("canvas");
var vShader=document.getElementById("vertexShader").textContent;
var fShader=document.getElementById("fragmentShader").textContent;
var gl=getWebGLContext(canvas);
if(!gl){
console.log("该浏览器不支持WebGL!");
return ;
}
if(!initShaders(gl,vShader,fShader)){
console.log('初始化着色器失败!');
return ;
}
//初始化顶点缓冲区,设置顶点位置
var n=initVertexBuffer(gl);
if(n<0){
console.log('无法获取顶点相关信息!');
return ;
}
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
//gl.drawArrays(gl.POINTS,0,n);
//绘制三角形
gl.drawArrays(gl.TRIANGLES,0,n);
}());
function initVertexBuffer(gl){
var vertices=new Float32Array([0.0,0.5,-0.5,-0.5,0.5,-0.5]);
console.log(vertices.length);
console.log(vertices.BYTES_PER_ELEMENT);
var n=3;//顶点数
//创建缓冲区对象
var vertexBuffer=gl.createBuffer();
if(!vertexBuffer){
console.log("缓冲区创建失败!");
return -1;
}
//将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
//向缓冲区对象写入数据
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
//获取attribute变量的存储位置
var a_Position=gl.getAttribLocation(gl.program,'a_Position');
if(a_Position<0){
console.log('无法获取变量的存储位置!');
return ;
}
//将缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);
//将链接a_Position的变量分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);
return n;
}
</script>
</body>
</html>
基本变换
基本变换就是基于每个顶点变换,旋转和缩放本质上还是点的平移。
1.平移
平移就是对应坐标x,y,z相加减
//顶点着色器代码
<script id="vShader" type="x-shader/x-vertex">
attribute vec4 a_Position;
uniform vec4 u_Translation; //平移变量,用uniform修饰,当shader运行后不会改变的数据
void main(){
gl_Position=a_Position+u_Translation;
}
</script>
<script>
//rgba(0-1)和rgba(0-255)之间转换乘除255
(function main(){
let canvas=document.getElementById("myCanvas");
let gl=getWebGLContext(canvas);
if(!gl){
console.log("该浏览器不支持WebGL!");
return;
}
let vShader=document.getElementById("vShader").textContent.trim();
let fShader=document.getElementById("fShader").textContent.trim();
if(!initShaders(gl,vShader,fShader)){
console.log("着色器初始化失败!");
return;
}
let a_Position=gl.getAttribLocation(gl.program,"a_Position");
let u_Translation=gl.getUniformLocation(gl.program,"u_Translation");
if(a_Position<0 || u_Translation<0){
console.log("无法获取变量的存储位置");
return;
}
//向上平移0.2,向右平移0.3
gl.uniform4f(u_Translation,0.3,0.2,0.0,0.0);
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP,0,initVertexBuffer());
function initVertexBuffer(){
let vertices=new Float32Array([-0.4,0.4,-0.4,-0.4,0.4,0.4,0.4,-0.4]);
let num=vertices.length/2;
//创建缓冲区对象
let vertexBuffer=gl.createBuffer();
if(!vertexBuffer){
console.log("缓冲区对象创建失败");
return;
}
//将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
//向缓冲区对象写入数据
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
//将缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);
//将链接a_position变量与分配给他的缓冲区对象
gl.enableVertexAttribArray(a_Position);
return num;
}
})();
</script>
2.旋转
基本旋转推到过程(绕z轴旋转为例)
<script id="vShader" type="x-shader/x-vertex">
attribute vec4 a_Position;
uniform float u_SinB,u_CosB;//声明存储变换角度值得变量
void main(){
gl_Position.x=a_Position.x*u_CosB-a_Position.y*u_SinB;
gl_Position.y=a_Position.y*u_CosB+a_Position.x*u_SinB;
gl_Position.z=a_Position.z;
gl_Position.w=1.0;
}
</script>
//使用旋转角度求出三角函数值,传递到顶点着色器
let angle=45.0;
let radin=Math.PI/180.0*angle;//转为弧度制
let sinB=Math.sin(radin);
let cosB=Math.cos(radin);
//获取变量地址
let u_SinB=gl.getUniformLocation(gl.program,"u_SinB");
let u_CosB=gl.getUniformLocation(gl.program,"u_CosB");
//赋值
gl.uniform1f(u_SinB,sinB);
gl.uniform1f(u_CosB,cosB);
3.缩放
缩放直接改变齐次坐标:(x,y,z,w)中w的值,也就是顶点中第四个分量,齐次坐标和三维坐标的关系在第二节有描述,w>1.0,图形缩小,w<1.0图形放大,且w必须大于等于0;
attribute vec4 a_Position;
uniform float u_SinB,u_CosB,u_ScaleW;
void main(){
gl_Position.x=a_Position.x*u_CosB-a_Position.y*u_SinB;
gl_Position.y=a_Position.y*u_CosB+a_Position.x*u_SinB;
gl_Position.z=a_Position.z;
gl_Position.w=u_ScaleW;//设置缩放程度
}
let u_ScaleW=gl.getUniformLocation(gl.program,"u_ScaleW");
gl.uniform1f(u_ScaleW,1.5);