1.body中定义canvas元素 onload()function
引入的js
<script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>
<script type="text/javascript" src="webgl-utils.js"></script>
声明onload()
<body onload="webGLStart()">
<canvas id="tooth-canvas" style="border: none" width="500" height="500"></canvas>
</body>
2.onload预加载函数
function webGLStart() {
var canvas = document.getElementById("tooth-canvas");
//插入GL
initGL(canvas);
//插入shader
initShaders();
//插入buffer数据
initBuffers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// This is the function that needs to be called regularly; it updates the scene’s animation state
// (eg. the triangle has moved from being 81 degrees rotated to 82 degrees) draws the scene,
// and also arranges for itself to be called again in an appropriate time
// . It’s the next function up in the file, so let’s look at it next.function tick() {
// requestAnimFrame(tick);
//函数需要经常被调用,它更新scene的动画状态(比如,三角形从81度旋转到82度)绘制scene 同时准备被随时调用
tick();
}
3.插入GL
function initGL(canvas) {
try {
//获取上下文固定语句 否则会报错。
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WegGL");
}
}
4.插入shader
1.定义shader
(1)fragment shader
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
</script>
(2)vertex shader
vertet attribute uniform varying 三种变量的声明:
http://blog.csdn.net/me_badman/article/details/56272803
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
//model view矩阵 projection矩阵(投影矩阵)
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
void main(void) {
//准备好模型 视图坐标变换,投影坐标变换的各个矩阵。再具体一点,就是准备好各种坐标变换的矩阵,然后
//相乘。将最终得到的矩阵传给WebGL的顶点着色器。
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
</script>
2.gl中获取shader
//获取shader
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
//shaderSource
gl.shaderSource(shader, str);
//完成getShader()
gl.compileShader(shader);
//没有完成
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
//打印出错误信息
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
3.插入shader
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
//给shaderProgram连接shader
gl.attachShader(shaderProgram,vertexShader);
gl.attachShader(shaderProgram,fragmentShader);
//gl连接program
gl.linkProgram(shaderProgram);
if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)){
alert("Could not initialise shaders");
}
//使用Program
gl.useProgram(shaderProgram);
//声明progarm 的position和color属性 =gl.getAttribLocation(shaderProgram, vertex - shader的aVertexPosition aVertexColor)属性
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
5.插入buffer数据
主函数
//三角形position
var triangleVertexPositionBuffer;
//三角形color
var triangleVertexColorBuffer;
//四边形position
var squareVertexPositionBuffer;
//四边形color
var squareVertexColorBuffer;
function initBuffers() {
//创建gl的buffer空间
triangleVertexPositionBuffer = gl.createBuffer();
//给gl绑定buffer
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0, 1.0, 0.0, //顶点
-1.0, -1.0, 0.0, //左下角
1.0, -1.0, 0.0 //右下角
];
//bufferData(1.array,vertices顶点数据,gl.STATIC_DRAW)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//列和行
triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.numItems = 3;
triangleVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
var colors = [
//rgba a:透明度 opacity
1.0, 0.0, 0.0, 1.0, //红
0.0, 1.0, 0.0, 1.0, //绿
0.0, 0.0, 1.0, 1.0, //蓝
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
//列和行
triangleVertexColorBuffer.itemSize = 4;
triangleVertexColorBuffer.numItems = 3;
squareVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
squareVertexPositionBuffer.itemSize = 3;
squareVertexPositionBuffer.numItems = 4;
squareVertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);
colors = []
for (var i=0; i < 4; i++) {
colors = colors.concat([0.5, 0.5, 1.0, 1.0]);
}
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
squareVertexColorBuffer.itemSize = 4;
squareVertexColorBuffer.numItems = 4;
}
6.绘制scene和animotion
1.tick()函数
function tick() {
//requestAnimFrame is a function in some Google-provided code that we’re including
// into this web page with a <script> tag at the top, webgl-utils.js.
// It gives us a browser-independent way of asking the browser to call us back next time it wants to repaint the
// WebGL scene — for example, next time the computer’s display is refreshing itself.
//requestAnimFrame是一个函数在页面中包含了 <script> webgl-utils.js标签的Google-provided代码
//独立于浏览器 要求浏览器返回下次WebGL的场景 支持所有浏览器
requestAnimFrame(tick);
drawScene();
animate();
}
2.在drawScene之前 定义一些变量、方法
var mvMatrix = mat4.create();//创建一个model-view 4*4矩阵
var mvMatrixStack = [];//创建一个栈放入mv copy矩阵
var pMatrix = mat4.create();//4*4矩阵
function mvPushMatrix() {
var copy = mat4.create();//创建一个4*4矩阵
mat4.set(mvMatrix, copy);//Sets the values of this matrix to those of the specified matrix.
//将mv矩阵值赋予新的copy矩阵中
mvMatrixStack.push(copy);//将copy的矩阵放到栈中
}
function mvPopMatrix() {
if (mvMatrixStack.length == 0) {
throw "Invalid popMatrix!";
}
mvMatrix = mvMatrixStack.pop();//取出栈顶的元素
}
//设置全局的矩阵 在这里 将shaderProgram的值给mv矩阵和p矩阵
function setMatrixUniforms() {
//将创建的pMatrix矩阵给 设置的shaderProgram.pMatrixUniform全局矩阵
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
//红色的旋转度数
function degToRad(degrees) {
return degrees * Math.PI / 180;
}
//定义两个变量(三角形度数和四边形度数) matrix根据其值 旋转(rotate)
var rTri = 0;
var rSquare = 0;
3.drawScene
function drawScene() {
//gl以(0,0)开始整个canvas的大小
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
//clear表示要清除的缓冲区 color depth 清楚颜色和深度缓冲区
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//透视投影
//mat4.perspective=function(a,b,c,d,e){a=c*Math.tan(a*Math.PI/360);b=a*b;return // mat4.frustum(-b,b,-a,a,c,d,e)}
//mat4.frustum=function(a,b,c,d,e,g,f){
// f||(f=mat4.create());
// var h=b-a,i=d-c,j=g-e;
// f[0]=e*2/h;f[1]=0;f[2]=0;f[3]=0;f[4]=0;f[5]=e*2/i;f[6]=0;f[7]=0;
// f[8]=(b+a)/h;f[9]=(d+c)/i;f[10]=-(g+e)/j;f[11]=-1;f[12]=0;f[13]=0;f[14]=-(g*e*2)/j;f[15]=0;return f}
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
// mvPushMatrix puts the matrix onto a stack, and mvPopMatrix gets rid of the current matrix,
// takes one from the top of the stack, and restores it.
// Using a stack means that we can have any number of bits of nested drawing code,
// each of which manipulates the model-view matrix and then restores it afterwards.
// So once we’ve finished drawing our rotated triangle,
// we restore the model-view matrix with mvPopMatrix so that this code:
// mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);
// mvPushMatrix 将mvmatrix copy并放到栈上,mvPopMatrix摆脱当前矩阵,从栈顶获取出
// mvPushMatrix()放入栈之后进行旋转 绑定等操作 结束后mvPopMatrix从栈顶取出
//变换坐标原点 tarnslate(mvMatrix,[x,y,scale])
mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);
mvPushMatrix();
//改变当前状态时,model-view矩阵根据rTri度数旋转
//degToRad(degree) 是将角度转换为弧度。
//第一个参数 mv矩阵 第二个参数 弧度(角度) 第三个参数旋转围绕的垂直轴(y轴)
mat4.rotate(mvMatrix, degToRad(rTri), [0, 1, 0]);
//triangleVertexPositionBuffer顶点position的buffer
//triangleVertexColorBuffer顶点color的buffer
//绑定buffer中vertexPositionAttribute的数据并传给shaderProgram.vertexPositionAttribute shaderProgram.vertexColorAttribute
//即给vertex-shader中的aVertexPosition aVertexColor赋值
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, triangleVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
//设置全局矩阵 shaderProgram.pMatrixUniform shaderProgram.pMatrixUniform
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
mvPopMatrix();
mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
mvPushMatrix();
//改变当前状态时,model-view矩阵根据rSquare
mat4.rotate(mvMatrix, degToRad(rSquare), [0, 1, 0]);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);
gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, squareVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
mvPopMatrix();
}
4.根据animate函数改变定义的角度的值
var lastTime = 0;
//根据时间改变 角度
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
rTri += (90 * elapsed) / 1000.0;
rSquare += (75 * elapsed) / 1000.0;
}
lastTime = timeNow;
}