初识WebGL 2.0

3,778 阅读6分钟

随着OpenGL ES 版本的发展,WebGL 的版本也由原先的 WebGL1.0 升级为WbGu WebGL2.0是一种 3D绘图标准,这种绘图技术标准允许把JavaScript 和OpenGL ES 3.0结合在一起。通过增加 OpenGL ES 30的一个JavasScript绑定,WebGL2.0可以为HTML5提供硬件3D加速淀染.这样 Web开发人员就可以借助系统显卡在浏览器里更流畅地展示场景和模型了,还能创建复杂的导航和数据视觉化。

webGL 2.0标准已出现在 Mozil Firefox、Apple Safari及开发者预览版 Google Ch等浏览器中,这项技术支持 web开发人员借助系统显示芯片在浏览器中展示各种3D模型和场景。随着HTML5 的兴起,WebGL2.0的前景不可估量。

2.1.1 WebGL 2.0简介

WebGL 2.0和3D图形规范OpenGL、通用计算规范 OpenCL都来自Khronos Grop,同样免费开放。WebGL2.0标准工作组的成员包括AMD、爱立信、Google、Mozilla、英伟达及Opera等,这些成员与Khronos公司通力合作,创建了一种多平台环境可用的WebGL 2.0标准。

webGL2.0完美地解决了现有的 Web 交互式三维动画的 3个问题。

 通过 HTML 脚本本身实现 Web 交互式三维动画的制作,无须任何特定浏览器的支持。 利用底层图形硬件的加速功能进行 3D 图形渲染,效率很高。 通过统一、标准、跨平台的OpenGL ES接口来实现,免去了开发人员多次学习利编程接口的麻烦。 webGL 目前有两个版本的标准,具体情况如下。 WebGL1.0,其提供的是JavaScript与OpenGL ES 2.0的绑定,目前除了微软的IE之外,大部分浏览器都能很好地支持它。 WebGL2.0。其提供的是 JavaSeripx与OpeGL ES 30的绑定,日前已经发展完善.除了微软的IE之外,大部分浏览器都能很好地支持它。 随着HTML5的兴起,大量优秀的网页涌现出来。作为HTML5 官方的Web 3D解决方案, WebGL 2.0立刻受到无数开发人员的追捧。由于其以网页形式进行展示。所以可以不受平台的限制,这也省去了在各种平台上移植的步骤。 随着微信平台兼容性的快速发展,进一步降低 WebGL 2.0的推广成本。微信平台中,只需要单击项目所在链接即可运行,操作步骤十分简便。也省去了传统游戏安装客户端的麻烦,同时保证了项目代码不被泄露。相信在不久的将来,WebGL 2.0将会凸显出更大的优势和能力。

2.1.2 WebGL 2.0 效果展示

2.1.1 节介绍了WebGL 2.0的基本知识,相信读者已经对其有了一定的了解。随着HTML.5标准的不断完善.为HTML5 Cmvas 提供硬件 3D 加速渲染的 webGL2.0已经被越来按多的开发人员所接受。市面上采用 WebGL 2.0 的网络游戏如雨后春笋般涌现出来。下而的几幅图(见图2-1、图2-2)就是作者看到的使用 WebGL2.0技术制作的精美网页截图。

                        图2-1 纹理贴图立方体

图片1.png

                            图2-2行星动画

图片2.png

从图2.1、图2-2 中可以看出,使用WebGL2.0技术准染出的3D场景与直按使用OpenGL ES技术在移动设备上开发出的场景效果基本是一致的。读者通过对前面章节的学习。再站合本章内容便可在 Web 端开发出与移动端一样绚丽流畅的3D场景。

2.2初识 WebGL2.0 应用

2.1节简单介绍了3D绘图标准 WebGL20.相信读者已经对webGL2.0的发展历程和作用有了一定的了解。上面的介绍偏重基础,读者无法深人学习具体编程技巧。为了使者读者保持学习热情,在实践中提升编程能力,本章将给出一个 WebGL 2.0 的基础案例并对相关的运行步骤进行详细介绍。

esxuj-jhfe2.gif

图片3.png

上面demo的代码构成

GLUtil.js

//初始化WebGL Canvas的方法
function initWebGLCanvas(canvasName) {
	canvas = document.getElementById(canvasName); //获取Canvas对象
	//antialias:Boolean类型,指示是否执行抗锯齿。
	var context = canvas.getContext('webgl2', {
		antialias: true
	}); //获取GL上下文
	return context; //返回GL上下文对象
}
//加载单个着色器的方法
function loadSingleShader(ctx, shaderScript) {
	if(shaderScript.type == "vertex") { //若为顶点着色器
		var shaderType = ctx.VERTEX_SHADER; //顶点着色器类型
	} else if(shaderScript.type == "fragment") { //若为片元着色器
		var shaderType = ctx.FRAGMENT_SHADER; //片元着色器类型 
	} else { //否则打印错误信息
		console.log("*** Error: shader script of undefined type '" + shaderScript.type + "'");
		return null;
	}
	//根据类型创建着色器程序
	var shader = ctx.createShader(shaderType);
	//加载着色器脚本
	ctx.shaderSource(shader, shaderScript.text);
	//编译着色器
	ctx.compileShader(shader);
	//检查编译状态
	var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
	if(!compiled && !ctx.isContextLost()) { //若编译出错
		var error = ctx.getShaderInfoLog(shader); //获取错误信息
		console.log("*** Error compiling shader :" + error); //打印错误信息
		ctx.deleteShader(shader); //删除着色器程序
		return null; //返回空
	}
	return shader; //返回着色器程序
}

//加载链接顶点、片元着色器的方法
function loadShaderSerial(gl, vshader, fshader) {
	//加载顶点着色器
	var vertexShader = loadSingleShader(gl, vshader);
	//加载片元着色器
	var fragmentShader = loadSingleShader(gl, fshader);
	//创建着色器程序
	var program = gl.createProgram();
	//将顶点着色器和片元着色器挂接到着色器程序
	gl.attachShader(program, vertexShader); //将顶点着色器添加到着色器程序中
	gl.attachShader(program, fragmentShader); //将片元着色器添加到着色器程序中
	//链接着色器程序
	gl.linkProgram(program);
	//检查链接是否成功
	var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
	if(!linked && !gl.isContextLost()) {   //若链接不成功
		//获取并在控制台打印错误信息
		var error = gl.getProgramInfoLog(program); //获取错误信息
		console.log("Error in program linking:" + error); //打印错误信息
		gl.deleteProgram(program); //删除着色器程序
		gl.deleteProgram(fragmentShader); //删除片元着色器
		gl.deleteProgram(vertexShader); //删除顶点着色器
		return null; //返回空
	}
	gl.useProgram(program); //
	gl.enable(gl.DEPTH_TEST); //打开深度检测
	return program; //返回着色器程序
}

LoadShaderUtil.js

function shaderObject(typeIn,textIn)//声明shaderObject类
{
	this.type=typeIn;//初始化type成员变量
	this.text=textIn;//初始化text成员变量
}
var shaderStrArray=["a","a"];//存储着色器
var shaderNumberCount=0;     //数组索引值
var shaderTypeName=["vertex","fragment"];//着色器名称数组
function processLoadShader(req,index)//处理着色器脚本内容的回调函数
{
	if (req.readyState == 4) //若状态为4
	{
		var shaderStr = req.responseText;//获取响应文本
        shaderStrArray[shaderNumberCount]=new shaderObject(shaderTypeName[shaderNumberCount],shaderStr);//顶点着色器脚本内容
        shaderNumberCount++;
		if(shaderNumberCount>1)//如果着色器内容不为空
		{
            shaderProgArray[index]=loadShaderSerial(gl,shaderStrArray[0], shaderStrArray[1]);//加载着色器
		}
	}
}
//加载着色器的方法
function loadShaderFile(url,index)//从服务器加载着色器脚本的函数
{
	var req = new XMLHttpRequest();//创建XMLHttpRequest对象
	req.onreadystatechange = function () //设置响应回调函数
	{ processLoadShader(req,index) };//调用processLoadShader处理响应
	req.open("GET", url, true);//用GET方式打开指定URL
	req.responseType = "text";//设置响应类型
	req.send(null);//发送HTTP请求
}



Matrix.js

作者针对项目开发封装的工具类,加密了,后面通过学习自行尝试封装。

var _0xa434=["\x73\x71\x72\x74","\x50\x49","\x73\x69\x6E","\x63\x6F\x73","\x6C\x65\x66\x74\x20\x3D\x3D\x20\x72\x69\x67\x68\x74","\x74\x6F\x70\x20\x3D\x3D\x20\x62\x6F\x74\x74\x6F\x6D","\x6E\x65\x61\x72\x20\x3D\x3D\x20\x66\x61\x72","\x6E\x65\x61\x72\x20\x3C\x3D\x20\x30\x2E\x30\x66","\x66\x61\x72\x20\x3C\x3D\x20\x30\x2E\x30\x66","\x62\x6F\x74\x74\x6F\x6D\x20\x3D\x3D\x20\x74\x6F\x70"];
function multiplyMM(_0x847fx2,_0x847fx3,_0x847fx4,_0x847fx5,_0x847fx6,_0x847fx7){ml= new Array(16);mr= new Array(16);for(i=0;i<16;i++){ml[i]=_0x847fx4[i];mr[i]=_0x847fx6[i];} ;_0x847fx2[0+_0x847fx3]=ml[0+_0x847fx5]*mr[0+_0x847fx7]+ml[4+_0x847fx5]*mr[1+_0x847fx7]+ml[8+_0x847fx5]*mr[2+_0x847fx7]+ml[12+_0x847fx5]*mr[3+_0x847fx7];_0x847fx2[1+_0x847fx3]=ml[1+_0x847fx5]*mr[0+_0x847fx7]+ml[5+_0x847fx5]*mr[1+_0x847fx7]+ml[9+_0x847fx5]*mr[2+_0x847fx7]+ml[13+_0x847fx5]*mr[3+_0x847fx7];_0x847fx2[2+_0x847fx3]=ml[2+_0x847fx5]*mr[0+_0x847fx7]+ml[6+_0x847fx5]*mr[1+_0x847fx7]+ml[10+_0x847fx5]*mr[2+_0x847fx7]+ml[14+_0x847fx5]*mr[3+_0x847fx7];_0x847fx2[3+_0x847fx3]=ml[3+_0x847fx5]*mr[0+_0x847fx7]+ml[7+_0x847fx5]*mr[1+_0x847fx7]+ml[11+_0x847fx5]*mr[2+_0x847fx7]+ml[15+_0x847fx5]*mr[3+_0x847fx7];_0x847fx2[4+_0x847fx3]=ml[0+_0x847fx5]*mr[4+_0x847fx7]+ml[4+_0x847fx5]*mr[5+_0x847fx7]+ml[8+_0x847fx5]*mr[6+_0x847fx7]+ml[12+_0x847fx5]*mr[7+_0x847fx7];_0x847fx2[5+_0x847fx3]=ml[1+_0x847fx5]*mr[4+_0x847fx7]+ml[5+_0x847fx5]*mr[5+_0x847fx7]+ml[9+_0x847fx5]*mr[6+_0x847fx7]+ml[13+_0x847fx5]*mr[7+_0x847fx7];_0x847fx2[6+_0x847fx3]=ml[2+_0x847fx5]*mr[4+_0x847fx7]+ml[6+_0x847fx5]*mr[5+_0x847fx7]+ml[10+_0x847fx5]*mr[6+_0x847fx7]+ml[14+_0x847fx5]*mr[7+_0x847fx7];_0x847fx2[7+_0x847fx3]=ml[3+_0x847fx5]*mr[4+_0x847fx7]+ml[7+_0x847fx5]*mr[5+_0x847fx7]+ml[11+_0x847fx5]*mr[6+_0x847fx7]+ml[15+_0x847fx5]*mr[7+_0x847fx7];_0x847fx2[8+_0x847fx3]=ml[0+_0x847fx5]*mr[8+_0x847fx7]+ml[4+_0x847fx5]*mr[9+_0x847fx7]+ml[8+_0x847fx5]*mr[10+_0x847fx7]+ml[12+_0x847fx5]*mr[11+_0x847fx7];_0x847fx2[9+_0x847fx3]=ml[1+_0x847fx5]*mr[8+_0x847fx7]+ml[5+_0x847fx5]*mr[9+_0x847fx7]+ml[9+_0x847fx5]*mr[10+_0x847fx7]+ml[13+_0x847fx5]*mr[11+_0x847fx7];_0x847fx2[10+_0x847fx3]=ml[2+_0x847fx5]*mr[8+_0x847fx7]+ml[6+_0x847fx5]*mr[9+_0x847fx7]+ml[10+_0x847fx5]*mr[10+_0x847fx7]+ml[14+_0x847fx5]*mr[11+_0x847fx7];_0x847fx2[11+_0x847fx3]=ml[3+_0x847fx5]*mr[8+_0x847fx7]+ml[7+_0x847fx5]*mr[9+_0x847fx7]+ml[11+_0x847fx5]*mr[10+_0x847fx7]+ml[15+_0x847fx5]*mr[11+_0x847fx7];_0x847fx2[12+_0x847fx3]=ml[0+_0x847fx5]*mr[12+_0x847fx7]+ml[4+_0x847fx5]*mr[13+_0x847fx7]+ml[8+_0x847fx5]*mr[14+_0x847fx7]+ml[12+_0x847fx5]*mr[15+_0x847fx7];_0x847fx2[13+_0x847fx3]=ml[1+_0x847fx5]*mr[12+_0x847fx7]+ml[5+_0x847fx5]*mr[13+_0x847fx7]+ml[9+_0x847fx5]*mr[14+_0x847fx7]+ml[13+_0x847fx5]*mr[15+_0x847fx7];_0x847fx2[14+_0x847fx3]=ml[2+_0x847fx5]*mr[12+_0x847fx7]+ml[6+_0x847fx5]*mr[13+_0x847fx7]+ml[10+_0x847fx5]*mr[14+_0x847fx7]+ml[14+_0x847fx5]*mr[15+_0x847fx7];_0x847fx2[15+_0x847fx3]=ml[3+_0x847fx5]*mr[12+_0x847fx7]+ml[7+_0x847fx5]*mr[13+_0x847fx7]+ml[11+_0x847fx5]*mr[14+_0x847fx7]+ml[15+_0x847fx5]*mr[15+_0x847fx7];} ;
function multiplyMV(_0x847fx9,_0x847fxa,_0x847fx4,_0x847fxb,_0x847fxc,_0x847fxd){var _0x847fxe= new Array(16);var _0x847fxf= new Array(4);for(i=0;i<16;i++){_0x847fxe[i]=_0x847fx4[i];} ;_0x847fxf[0]=_0x847fxc[0];_0x847fxf[1]=_0x847fxc[1];_0x847fxf[2]=_0x847fxc[2];_0x847fxf[3]=_0x847fxc[3];_0x847fx9[0+_0x847fxa]=_0x847fxe[0+_0x847fxb]*_0x847fxf[0+_0x847fxd]+_0x847fxe[4+_0x847fxb]*_0x847fxf[1+_0x847fxd]+_0x847fxe[8+_0x847fxb]*_0x847fxf[2+_0x847fxd]+_0x847fxe[12+_0x847fxb]*_0x847fxf[3+_0x847fxd];_0x847fx9[1+_0x847fxa]=_0x847fxe[1+_0x847fxb]*_0x847fxf[0+_0x847fxd]+_0x847fxe[5+_0x847fxb]*_0x847fxf[1+_0x847fxd]+_0x847fxe[9+_0x847fxb]*_0x847fxf[2+_0x847fxd]+_0x847fxe[13+_0x847fxb]*_0x847fxf[3+_0x847fxd];_0x847fx9[2+_0x847fxa]=_0x847fxe[2+_0x847fxb]*_0x847fxf[0+_0x847fxd]+_0x847fxe[6+_0x847fxb]*_0x847fxf[1+_0x847fxd]+_0x847fxe[10+_0x847fxb]*_0x847fxf[2+_0x847fxd]+_0x847fxe[14+_0x847fxb]*_0x847fxf[3+_0x847fxd];_0x847fx9[3+_0x847fxa]=_0x847fxe[3+_0x847fxb]*_0x847fxf[0+_0x847fxd]+_0x847fxe[7+_0x847fxb]*_0x847fxf[1+_0x847fxd]+_0x847fxe[11+_0x847fxb]*_0x847fxf[2+_0x847fxd]+_0x847fxe[15+_0x847fxb]*_0x847fxf[3+_0x847fxd];} ;
function setIdentityM(_0x847fx11,_0x847fx12){for(i=0;i<16;i++){_0x847fx11[i]=0;} ;_0x847fx11[0]=1;_0x847fx11[5]=1;_0x847fx11[10]=1;_0x847fx11[15]=1;} ;
function translateM(_0x847fx14,_0x847fx15,_0x847fx16,_0x847fx17,_0x847fx18){for(i=0;i<4;i++){mi=_0x847fx15+i;_0x847fx14[12+mi]+=_0x847fx14[mi]*_0x847fx16+_0x847fx14[4+mi]*_0x847fx17+_0x847fx14[8+mi]*_0x847fx18;} ;} ;
function length(_0x847fx16,_0x847fx17,_0x847fx18){return Math[_0xa434[0]](_0x847fx16*_0x847fx16+_0x847fx17*_0x847fx17+_0x847fx18*_0x847fx18);} ;
function setRotateM(_0x847fx1b,_0x847fx1c,_0x847fx1d,_0x847fx16,_0x847fx17,_0x847fx18){_0x847fx1b[_0x847fx1c+3]=0;_0x847fx1b[_0x847fx1c+7]=0;_0x847fx1b[_0x847fx1c+11]=0;_0x847fx1b[_0x847fx1c+12]=0;_0x847fx1b[_0x847fx1c+13]=0;_0x847fx1b[_0x847fx1c+14]=0;_0x847fx1b[_0x847fx1c+15]=1;_0x847fx1d*=(Math[_0xa434[1]]/180.0);s=Math[_0xa434[2]](_0x847fx1d);c=Math[_0xa434[3]](_0x847fx1d);if(1.0==_0x847fx16&&0.0==_0x847fx17&&0.0==_0x847fx18){_0x847fx1b[_0x847fx1c+5]=c;_0x847fx1b[_0x847fx1c+10]=c;_0x847fx1b[_0x847fx1c+6]=s;_0x847fx1b[_0x847fx1c+9]=-s;_0x847fx1b[_0x847fx1c+1]=0;_0x847fx1b[_0x847fx1c+2]=0;_0x847fx1b[_0x847fx1c+4]=0;_0x847fx1b[_0x847fx1c+8]=0;_0x847fx1b[_0x847fx1c+0]=1;} else {if(0.0==_0x847fx16&&1.0==_0x847fx17&&0.0==_0x847fx18){_0x847fx1b[_0x847fx1c+0]=c;_0x847fx1b[_0x847fx1c+10]=c;_0x847fx1b[_0x847fx1c+8]=s;_0x847fx1b[_0x847fx1c+2]=-s;_0x847fx1b[_0x847fx1c+1]=0;_0x847fx1b[_0x847fx1c+4]=0;_0x847fx1b[_0x847fx1c+6]=0;_0x847fx1b[_0x847fx1c+9]=0;_0x847fx1b[_0x847fx1c+5]=1;} else {if(0.0==_0x847fx16&&0.0==_0x847fx17&&1.0==_0x847fx18){_0x847fx1b[_0x847fx1c+0]=c;_0x847fx1b[_0x847fx1c+5]=c;_0x847fx1b[_0x847fx1c+1]=s;_0x847fx1b[_0x847fx1c+4]=-s;_0x847fx1b[_0x847fx1c+2]=0;_0x847fx1b[_0x847fx1c+6]=0;_0x847fx1b[_0x847fx1c+8]=0;_0x847fx1b[_0x847fx1c+9]=0;_0x847fx1b[_0x847fx1c+10]=1;} else {len=length(_0x847fx16,_0x847fx17,_0x847fx18);if(1.0!=len){recipLen=1.0/len;_0x847fx16*=recipLen;_0x847fx17*=recipLen;_0x847fx18*=recipLen;} ;nc=1.0-c;xy=_0x847fx16*_0x847fx17;yz=_0x847fx17*_0x847fx18;zx=_0x847fx18*_0x847fx16;xs=_0x847fx16*s;ys=_0x847fx17*s;zs=_0x847fx18*s;_0x847fx1b[_0x847fx1c+0]=_0x847fx16*_0x847fx16*nc+c;_0x847fx1b[_0x847fx1c+4]=xy*nc-zs;_0x847fx1b[_0x847fx1c+8]=zx*nc+ys;_0x847fx1b[_0x847fx1c+1]=xy*nc+zs;_0x847fx1b[_0x847fx1c+5]=_0x847fx17*_0x847fx17*nc+c;_0x847fx1b[_0x847fx1c+9]=yz*nc-xs;_0x847fx1b[_0x847fx1c+2]=zx*nc-ys;_0x847fx1b[_0x847fx1c+6]=yz*nc+xs;_0x847fx1b[_0x847fx1c+10]=_0x847fx18*_0x847fx18*nc+c;} ;} ;} ;} ;
function rotateM(_0x847fx14,_0x847fx15,_0x847fx1d,_0x847fx16,_0x847fx17,_0x847fx18){rm= new Array(16);setRotateM(rm,0,_0x847fx1d,_0x847fx16,_0x847fx17,_0x847fx18);rem= new Array(16);multiplyMM(rem,0,_0x847fx14,0,rm,0);for(i=0;i<16;i++){_0x847fx14[i]=rem[i];} ;} ;
function scaleM(_0x847fx14,_0x847fx15,_0x847fx16,_0x847fx17,_0x847fx18){for(i=0;i<4;i++){mi=_0x847fx15+i;_0x847fx14[mi]*=_0x847fx16;_0x847fx14[4+mi]*=_0x847fx17;_0x847fx14[8+mi]*=_0x847fx18;} ;} ;
function frustumM(_0x847fx14,_0x847fx21,_0x847fx22,_0x847fx23,_0x847fx24,_0x847fx25,_0x847fx26,_0x847fx27){if(_0x847fx22==_0x847fx23){alert(_0xa434[4]);} ;if(_0x847fx25==_0x847fx24){alert(_0xa434[5]);} ;if(_0x847fx26==_0x847fx27){alert(_0xa434[6]);} ;if(_0x847fx26<=0.0){alert(_0xa434[7]);} ;if(_0x847fx27<=0.0){alert(_0xa434[8]);} ;r_width=1.0/(_0x847fx23-_0x847fx22);r_height=1.0/(_0x847fx25-_0x847fx24);r_depth=1.0/(_0x847fx26-_0x847fx27);x=2.0*(_0x847fx26*r_width);y=2.0*(_0x847fx26*r_height);A=2.0*((_0x847fx23+_0x847fx22)*r_width);B=(_0x847fx25+_0x847fx24)*r_height;C=(_0x847fx27+_0x847fx26)*r_depth;D=2.0*(_0x847fx27*_0x847fx26*r_depth);_0x847fx14[_0x847fx21+0]=x;_0x847fx14[_0x847fx21+5]=y;_0x847fx14[_0x847fx21+8]=A;_0x847fx14[_0x847fx21+9]=B;_0x847fx14[_0x847fx21+10]=C;_0x847fx14[_0x847fx21+14]=D;_0x847fx14[_0x847fx21+11]=-1.0;_0x847fx14[_0x847fx21+1]=0.0;_0x847fx14[_0x847fx21+2]=0.0;_0x847fx14[_0x847fx21+3]=0.0;_0x847fx14[_0x847fx21+4]=0.0;_0x847fx14[_0x847fx21+6]=0.0;_0x847fx14[_0x847fx21+7]=0.0;_0x847fx14[_0x847fx21+12]=0.0;_0x847fx14[_0x847fx21+13]=0.0;_0x847fx14[_0x847fx21+15]=0.0;} ;
function orthoM(_0x847fx14,_0x847fx15,_0x847fx22,_0x847fx23,_0x847fx24,_0x847fx25,_0x847fx26,_0x847fx27){if(_0x847fx22==_0x847fx23){alert(_0xa434[4]);} ;if(_0x847fx24==_0x847fx25){alert(_0xa434[9]);} ;if(_0x847fx26==_0x847fx27){alert(_0xa434[6]);} ;r_width=1.0/(_0x847fx23-_0x847fx22);r_height=1.0/(_0x847fx25-_0x847fx24);r_depth=1.0/(_0x847fx27-_0x847fx26);x=2.0*(r_width);y=2.0*(r_height);z=-2.0*(r_depth);tx=-(_0x847fx23+_0x847fx22)*r_width;ty=-(_0x847fx25+_0x847fx24)*r_height;tz=-(_0x847fx27+_0x847fx26)*r_depth;_0x847fx14[_0x847fx15+0]=x;_0x847fx14[_0x847fx15+5]=y;_0x847fx14[_0x847fx15+10]=z;_0x847fx14[_0x847fx15+12]=tx;_0x847fx14[_0x847fx15+13]=ty;_0x847fx14[_0x847fx15+14]=tz;_0x847fx14[_0x847fx15+15]=1.0;_0x847fx14[_0x847fx15+1]=0.0;_0x847fx14[_0x847fx15+2]=0.0;_0x847fx14[_0x847fx15+3]=0.0;_0x847fx14[_0x847fx15+4]=0.0;_0x847fx14[_0x847fx15+6]=0.0;_0x847fx14[_0x847fx15+7]=0.0;_0x847fx14[_0x847fx15+8]=0.0;_0x847fx14[_0x847fx15+9]=0.0;_0x847fx14[_0x847fx15+11]=0.0;} ;
function transposeM(_0x847fx2a,_0x847fx2b,_0x847fx14,_0x847fx15){for(i=0;i<4;i++){mBase=i*4+_0x847fx15;_0x847fx2a[i+_0x847fx2b]=_0x847fx14[mBase];_0x847fx2a[i+4+_0x847fx2b]=_0x847fx14[mBase+1];_0x847fx2a[i+8+_0x847fx2b]=_0x847fx14[mBase+2];_0x847fx2a[i+12+_0x847fx2b]=_0x847fx14[mBase+3];} ;} ;
function setLookAtM(_0x847fx1b,_0x847fx1c,_0x847fx2d,_0x847fx2e,_0x847fx2f,_0x847fx30,_0x847fx31,_0x847fx32,_0x847fx33,_0x847fx34,_0x847fx35){fx=_0x847fx30-_0x847fx2d;fy=_0x847fx31-_0x847fx2e;fz=_0x847fx32-_0x847fx2f;rlf=1.0/length(fx,fy,fz);fx*=rlf;fy*=rlf;fz*=rlf;sx=fy*_0x847fx35-fz*_0x847fx34;sy=fz*_0x847fx33-fx*_0x847fx35;sz=fx*_0x847fx34-fy*_0x847fx33;rls=1.0/length(sx,sy,sz);sx*=rls;sy*=rls;sz*=rls;ux=sy*fz-sz*fy;uy=sz*fx-sx*fz;uz=sx*fy-sy*fx;_0x847fx1b[_0x847fx1c+0]=sx;_0x847fx1b[_0x847fx1c+1]=ux;_0x847fx1b[_0x847fx1c+2]=-fx;_0x847fx1b[_0x847fx1c+3]=0.0;_0x847fx1b[_0x847fx1c+4]=sy;_0x847fx1b[_0x847fx1c+5]=uy;_0x847fx1b[_0x847fx1c+6]=-fy;_0x847fx1b[_0x847fx1c+7]=0.0;_0x847fx1b[_0x847fx1c+8]=sz;_0x847fx1b[_0x847fx1c+9]=uz;_0x847fx1b[_0x847fx1c+10]=-fz;_0x847fx1b[_0x847fx1c+11]=0.0;_0x847fx1b[_0x847fx1c+12]=0.0;_0x847fx1b[_0x847fx1c+13]=0.0;_0x847fx1b[_0x847fx1c+14]=0.0;_0x847fx1b[_0x847fx1c+15]=1.0;translateM(_0x847fx1b,_0x847fx1c,-_0x847fx2d,-_0x847fx2e,-_0x847fx2f);} ;
function invertM(_0x847fx37,_0x847fx38,_0x847fx14,_0x847fx15){src= new Array(16);transposeM(src,0,_0x847fx14,_0x847fx15);tmp= new Array(12);tmp[0]=src[10]*src[15];tmp[1]=src[11]*src[14];tmp[2]=src[9]*src[15];tmp[3]=src[11]*src[13];tmp[4]=src[9]*src[14];tmp[5]=src[10]*src[13];tmp[6]=src[8]*src[15];tmp[7]=src[11]*src[12];tmp[8]=src[8]*src[14];tmp[9]=src[10]*src[12];tmp[10]=src[8]*src[13];tmp[11]=src[9]*src[12];dst= new Array(16);dst[0]=tmp[0]*src[5]+tmp[3]*src[6]+tmp[4]*src[7];dst[0]-=tmp[1]*src[5]+tmp[2]*src[6]+tmp[5]*src[7];dst[1]=tmp[1]*src[4]+tmp[6]*src[6]+tmp[9]*src[7];dst[1]-=tmp[0]*src[4]+tmp[7]*src[6]+tmp[8]*src[7];dst[2]=tmp[2]*src[4]+tmp[7]*src[5]+tmp[10]*src[7];dst[2]-=tmp[3]*src[4]+tmp[6]*src[5]+tmp[11]*src[7];dst[3]=tmp[5]*src[4]+tmp[8]*src[5]+tmp[11]*src[6];dst[3]-=tmp[4]*src[4]+tmp[9]*src[5]+tmp[10]*src[6];dst[4]=tmp[1]*src[1]+tmp[2]*src[2]+tmp[5]*src[3];dst[4]-=tmp[0]*src[1]+tmp[3]*src[2]+tmp[4]*src[3];dst[5]=tmp[0]*src[0]+tmp[7]*src[2]+tmp[8]*src[3];dst[5]-=tmp[1]*src[0]+tmp[6]*src[2]+tmp[9]*src[3];dst[6]=tmp[3]*src[0]+tmp[6]*src[1]+tmp[11]*src[3];dst[6]-=tmp[2]*src[0]+tmp[7]*src[1]+tmp[10]*src[3];dst[7]=tmp[4]*src[0]+tmp[9]*src[1]+tmp[10]*src[2];dst[7]-=tmp[5]*src[0]+tmp[8]*src[1]+tmp[11]*src[2];tmp[0]=src[2]*src[7];tmp[1]=src[3]*src[6];tmp[2]=src[1]*src[7];tmp[3]=src[3]*src[5];tmp[4]=src[1]*src[6];tmp[5]=src[2]*src[5];tmp[6]=src[0]*src[7];tmp[7]=src[3]*src[4];tmp[8]=src[0]*src[6];tmp[9]=src[2]*src[4];tmp[10]=src[0]*src[5];tmp[11]=src[1]*src[4];dst[8]=tmp[0]*src[13]+tmp[3]*src[14]+tmp[4]*src[15];dst[8]-=tmp[1]*src[13]+tmp[2]*src[14]+tmp[5]*src[15];dst[9]=tmp[1]*src[12]+tmp[6]*src[14]+tmp[9]*src[15];dst[9]-=tmp[0]*src[12]+tmp[7]*src[14]+tmp[8]*src[15];dst[10]=tmp[2]*src[12]+tmp[7]*src[13]+tmp[10]*src[15];dst[10]-=tmp[3]*src[12]+tmp[6]*src[13]+tmp[11]*src[15];dst[11]=tmp[5]*src[12]+tmp[8]*src[13]+tmp[11]*src[14];dst[11]-=tmp[4]*src[12]+tmp[9]*src[13]+tmp[10]*src[14];dst[12]=tmp[2]*src[10]+tmp[5]*src[11]+tmp[1]*src[9];dst[12]-=tmp[4]*src[11]+tmp[0]*src[9]+tmp[3]*src[10];dst[13]=tmp[8]*src[11]+tmp[0]*src[8]+tmp[7]*src[10];dst[13]-=tmp[6]*src[10]+tmp[9]*src[11]+tmp[1]*src[8];dst[14]=tmp[6]*src[9]+tmp[11]*src[11]+tmp[3]*src[8];dst[14]-=tmp[10]*src[11]+tmp[2]*src[8]+tmp[7]*src[9];dst[15]=tmp[10]*src[10]+tmp[4]*src[8]+tmp[9]*src[9];dst[15]-=tmp[8]*src[9]+tmp[11]*src[10]+tmp[5]*src[8];det=src[0]*dst[0]+src[1]*dst[1]+src[2]*dst[2]+src[3]*dst[3];if(det==0.0){return false;} ;det=1/det;for(j=0;j<16;j++){_0x847fx37[j+_0x847fx38]=dst[j]*det;} ;return true;} ;

MatrixState.js

function MatrixState() {
	this.mProjMatrix = new Array(16); //投影矩阵
	this.mVMatrix = new Array(16); //摄像机矩阵
	this.currMatrix = new Array(16); //基本变换矩阵
	this.mStack = new Array(100); //矩阵栈

	//初始化矩阵的方法
	this.setInitStack = function() {
		this.currMatrix = new Array(16); //创建用于存储矩阵元素的数组
		setIdentityM(this.currMatrix, 0); //将元素填充为单位阵的元素值
	}

	//保护变换矩阵,当前矩阵入栈
	this.pushMatrix = function() {
		this.mStack.push(this.currMatrix.slice(0));
	}

	//恢复变换矩阵,当前矩阵出栈
	this.popMatrix = function() {
		this.currMatrix = this.mStack.pop();
	}

	//执行平移变换
	this.translate = function(x, y, z) //设置沿xyz轴移动
	{
		translateM(this.currMatrix, 0, x, y, z); //将平移变换记录进矩阵
	}

	//执行旋转变换
	this.rotate = function(angle, x, y, z) //设置绕xyz轴移动
	{
		rotateM(this.currMatrix, 0, angle, x, y, z); //将旋转变换记录进矩阵
	}

	//执行缩放变换
	this.scale = function(x, y, z) //设置绕xyz轴移动
	{
		scaleM(this.currMatrix, 0, x, y, z) //将缩放变换记录进矩阵
	}

	//设置摄像机
	this.setCamera = function(
		cx, //摄像机位置x
		cy, //摄像机位置y
		cz, //摄像机位置z
		tx, //摄像机目标点x
		ty, //摄像机目标点y
		tz, //摄像机目标点z
		upx, //摄像机UP向量X分量
		upy, //摄像机UP向量Y分量
		upz //摄像机UP向量Z分量
	) {
		setLookAtM
			(
				this.mVMatrix, 0,
				cx, cy, cz,
				tx, ty, tz,
				upx, upy, upz
			);
	}

	//设置透视投影参数
	this.setProjectFrustum = function(
		left, //near面的left
		right, //near面的right
		bottom, //near面的bottom
		top, //near面的top
		near, //near面距离
		far //far面距离
	) {
		frustumM(this.mProjMatrix, 0, left, right, bottom, top, near, far);
	}

	//设置正交投影参数
	this.setProjectOrtho = function(
		left, //near面的left
		right, //near面的right
		bottom, //near面的bottom
		top, //near面的top
		near, //near面与视点的距离
		far //far面与视点的距离
	) {
		orthoM(this.mProjMatrix, 0, left, right, bottom, top, near, far);
	}

	//获取具体物体的总变换矩阵
	this.getFinalMatrix = function() {
		var mMVPMatrix = new Array(16);
		multiplyMM(mMVPMatrix, 0, this.mVMatrix, 0, this.currMatrix, 0);
		multiplyMM(mMVPMatrix, 0, this.mProjMatrix, 0, mMVPMatrix, 0);
		return mMVPMatrix;
	}

	//获取具体物体的变换矩阵
	this.getMMatrix = function() {
		return this.currMatrix;
	}
}

Triangle.js

function Triangle( //声明绘制用物体对象所属类
	gl, //GL上下文
	programIn //着色器程序id
) {
	//this.vertexData=vertexDataIn;						//初始化顶点坐标数据
	this.vertexData = [
		//三角形顶点
		3.0, 0.0, 0.0,
		0.0, 0.0, 0.0,
		0.0, 3.0, 0.0
	];
	this.vcount = this.vertexData.length / 3; //得到顶点数量
	this.vertexBuffer = gl.createBuffer(); //创建顶点坐标数据缓冲
	gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); //绑定顶点坐标数据缓冲
	//将顶点坐标数据送入缓冲
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.vertexData), gl.STATIC_DRAW);

	this.colorsData = [
		//三角形顶点颜色
		1.0, 1.0, 1.0, 1.0,
		0.0, 0.0, 1.0, 1.0,
		0.0, 1.0, 0.0, 1.0
	];
	this.colorBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); //绑定颜色数据缓冲
	//将颜色数据送入缓冲
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.colorsData), gl.STATIC_DRAW);

	this.program = programIn; //初始化着色器程序id

	this.drawSelf = function(ms) //绘制物体的方法
	{
		gl.useProgram(this.program); //指定使用某套着色器程序
		//获取总变换矩阵引用id
		var uMVPMatrixHandle = gl.getUniformLocation(this.program, "uMVPMatrix");
		//将总变换矩阵送入渲染管线
		gl.uniformMatrix4fv(uMVPMatrixHandle, false, new Float32Array(ms.getFinalMatrix()));

		gl.enableVertexAttribArray(gl.getAttribLocation(this.program, "aPosition")); //启用顶点坐标数据数组
		gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); //绑定顶点坐标数据缓冲
		//给管线指定顶点坐标数据
		gl.vertexAttribPointer(gl.getAttribLocation(this.program, "aPosition"), 3, gl.FLOAT, false, 0, 0);

		gl.enableVertexAttribArray(gl.getAttribLocation(this.program, "aColor")); //启用颜色坐标数据数组
		gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); //绑定颜色坐标数据缓冲
		//给管线指定颜色坐标数据
		gl.vertexAttribPointer(gl.getAttribLocation(this.program, "aColor"), 4, gl.FLOAT, false, 0, 0);

		gl.drawArrays(gl.TRIANGLES, 0, this.vcount); //用顶点法绘制物体
	}
}

vtrtex.bns

#version 300 es
uniform mat4 uMVPMatrix; //总变换矩阵
layout (location = 0) in vec3 aPosition;  //顶点位置
layout (location = 1) in vec4 aColor;    //顶点颜色
out  vec4 vColor;  //用于传递给片元着色器的变量

void main()
{
   gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置
   vColor = aColor;//将接收的颜色传递给片元着色器
}

fragment.bns

#version 300 es
precision mediump float;
in  vec4 vColor; //接收从顶点着色器过来的参数
out vec4 fragColor;//输出到的片元颜色
void main()
{
   fragColor = vColor;//给此片元颜色值
}

Sample2_1.html

## <html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<title>Triangle</title>
		<!--标题-->
		<script type="text/javascript" src="js/GLUtil.js"></script>
		<script type="text/javascript" src="js/Matrix.js"></script>
		<script type="text/javascript" src="js/MatrixState.js"></script>
		<script type="text/javascript" src="js/Triangle.js"></script>
		<script type="text/javascript" src="js/LoadShaderUtil.js"></script>
		<script>
			'use strict';
			//GLES上下文
			var gl;
			//变换矩阵管理类对象
			var ms = new MatrixState();
			//要绘制的3D物体
			var ooTri;
			//着色器程序列表,集中管理
			var shaderProgArray = new Array();
			var currentAngle;
			var incAngle;
			var canvas;
			//初始化的方法
			function start() {
				//            //获取3D Canvas
				//            var canvas = document.getElementById('bncanvas');
				//            //获取GL上下文
				//            gl = canvas.getContext('webgl2', { antialias: true });
				gl = initWebGLCanvas("bncanvas");
				if(!gl) //若获取GL上下文失败
				{
					alert("创建GLES上下文失败,不支持webGL2.0!"); //显示错误提示信息
					return;
				}

				//设置视口
				gl.viewport(0, 0, canvas.width, canvas.height);
				//设置屏幕背景色RGBA
				gl.clearColor(0.0, 0.0, 0.0, 1.0);
				//初始化变换矩阵
				ms.setInitStack();
				//设置摄像机
				//            ms.setCamera(0,0,17,0,0,0,0,1,0);//立方体摄像机位置
				ms.setCamera(0, 0, -5, 0, 0, 0, 0, 1, 0); //三角形摄像机位置
				//设置投影参数
				ms.setProjectFrustum(-1.5, 1.5, -1, 1, 1, 100);
				gl.enable(gl.DEPTH_TEST); //开启深度检测

				//加载着色器程序
				loadShaderFile("shader/vtrtex.bns", 0);
				loadShaderFile("shader/fragment.bns", 0);
				//如果着色器已加载完毕
				if(shaderProgArray[0]) {
					ooTri = new Triangle(gl, shaderProgArray[0]); //创建三角形绘制对象
				} else {
					setTimeout(function() {
						ooTri = new Triangle(gl, shaderProgArray[0]);
					}, 90);
					//休息90ms后再执行
				}
				//初始化旋转角度
				currentAngle = 0;
				//初始化角度步进值
				incAngle = 0.4;
				//定时绘制画面
				setInterval("drawFrame();", 16.6);
			}
			//绘制一帧画面的方法
			function drawFrame() {
				if(!ooTri) {
					console.log("加载未完成!"); //提示信息
					return;
				}
				//清除着色缓冲与深度缓冲
				gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
				//保护现场
				ms.pushMatrix();
				//执行旋转,即按哪个轴旋转
				ms.rotate(currentAngle, 0, 1, 0);
				//绘制物体
				ooTri.drawSelf(ms);
				//恢复现场
				ms.popMatrix();
				//修改旋转角度
				currentAngle += incAngle;
				if(currentAngle > 360) //保证角度范围不超过360
					currentAngle -= 360;
			}
		</script>
	</head>

	<body onload="start();">
		<canvas height="800" width="1200" id="bncanvas">
	    若看到这个文字,说明浏览器不支持WebGL!
	</canvas>
	</body>
</html>