WebGL2简单实例

一、主代码

<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>

1、引入工具函数

        此代码显示一个三角形,在网页首先引入本地几个文 件:

        Triangles.js   三角形绘制 对象 

        GLUtil.js :    GL工具函数

        LoadShaderUtil.js   着色器装载函数  

        Matrix.js    矩阵基础函数

        MatrixState.js: 矩阵状态

2、 启动函数 start()

        代码启动函数为start(),具体流程为:

        1、获取初始化的WebGL句柄

        2、检测获取WebGL句柄的结果,若失败返回

        3、设置视口

        4、设置屏幕背景

        5、初始化变换矩阵

        6、设置摄像机

        7、开启深度检测

        8、加载着色器程序

        9、定时绘制画面

3、渲染函数drawFrame()

绘制一 帧画面的方法drawFrame()流程如下:

        1、检测绘制对象是否加载,若未加载则返回 

        2、清除着色缓冲与深度缓冲

        3、保护现场

        4、执行旋转

        5、绘制物体 

        6、恢复现场

        7、修改旋转角度 

二、GL工具函数( GLUtil)

//初始化WebGL Canvas的方法
function initWebGLCanvas(canvasName) {
    canvas = document.getElementById(canvasName);//获取Canvas对象
    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;//返回着色器程序
}
				

此工具函数 包含三个函数,分别是:

        initWebGLCanvas   初始化WebGL Canvas的方法

        loadSingleShader    加载单个着色器的方法

        loadShaderSerial    加载链接顶点、片元着色器的方法

三、色器装载函数( LoadShaderUtil)

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请求
}


        shaderObject    声明shaderObject类

        processLoadShader   处理着色器脚本内容的回调函数

        loadShaderFile    从服务器加载着色器脚本的函数

四、 矩阵状态(MatrixState)

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;
	}
}

此矩阵状态类,定义了四个矩阵:

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

成员函数如下所示:

        setInitStack   初始化矩阵的方法

        pushMatrix  保护变换矩阵,当前矩阵入栈

        popMatrix  恢复变换矩阵,当前矩阵出栈

        translate   执行平移变换

        rotate  执行旋转变换

        scale   执行缩放变换

        setCamera   设置摄像机

        setProjectFrustum  设置透视投影参数

        setProjectOrtho  设置正交投影参数

        getFinalMatrix   获取具体物体的总变换矩阵

        getMMatrix     获取具体物体的变换矩阵

五 、三角形绘制 对象(Triangles)

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

		//立方体顶点
		// 3.0,3.0,3.0,
		// 3.0,-3.0,3.0,
		// -3.0,3.0,3.0,

		// -3.0,3.0,3.0,
		// 3.0,-3.0,3.0,
		// -3.0,-3.0,3.0,
        //
		// 3.0,3.0,3.0,
		// 3.0,-3.0,-3.0,
		// 3.0,3.0,-3.0,
        //
		// 3.0,3.0,3.0,
		// 3.0,-3.0,3.0,
		// 3.0,-3.0,-3.0,
        //
		// -3.0,3.0,3.0,
		// -3.0,-3.0,-3.0,
		// -3.0,3.0,-3.0,
        //
		// -3.0,3.0,3.0,
		// -3.0,-3.0,3.0,
		// -3.0,-3.0,-3.0,
        //
		// 3.0,3.0,-3.0,
		// 3.0,-3.0,-3.0,
		// -3.0,3.0,-3.0,
        //
		// -3.0,3.0,-3.0,
		// 3.0,-3.0,-3.0,
		// -3.0,-3.0,-3.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

		//立方体顶点颜色
		// 1.0,0.0,1.0,1.0,					//初始化顶点颜色数据
		// 1.0,0.0,0.0,1.0,
		// 1.0,0.0,0.0,1.0,

		// 1.0,1.0,1.0,1.0,					//初始化顶点颜色数据
		// 0.0,0.0,1.0,1.0,
		// 0.0,1.0,0.0,1.0,
        //
		// 1.0,1.0,1.0,1.0,					//初始化顶点颜色数据
		// 0.0,0.0,1.0,1.0,
		// 0.0,1.0,0.0,1.0,
        //
		// 1.0,1.0,1.0,1.0,					//初始化顶点颜色数据
		// 0.0,0.0,1.0,1.0,
		// 0.0,1.0,0.0,1.0,
        //
		// 1.0,1.0,1.0,1.0,					//初始化顶点颜色数据
		// 0.0,0.0,1.0,1.0,
		// 0.0,1.0,0.0,1.0,
        //
		// 1.0,1.0,1.0,1.0,					//初始化顶点颜色数据
		// 0.0,0.0,1.0,1.0,
		// 0.0,1.0,0.0,1.0,
        //
		// 1.0,1.0,1.0,1.0,					//初始化顶点颜色数据
		// 0.0,0.0,1.0,1.0,
		// 0.0,1.0,0.0,1.0,
        //
		// 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);		//用顶点法绘制物体
	}
}

绘制 对象 具体流程 如下:

缓冲 区初始化: 

        1、定义顶点数据,送数据至顶点坐标数据缓冲

        2、定义颜色数据、送数据至颜色数据缓冲

        3、初始化着色器程序

绘制 方法drawSelf(ms)

        1、指定使用某套着色器程序

         2、获取总变换矩阵,将总变换矩阵送入渲染管线

         3、启用顶点坐标数据数组,绑定顶点坐标数据缓冲,给管线指定顶点坐标数据

         4、启用颜色坐标数据数组,绑定颜色坐标数据缓冲,给管线指定颜色坐标数据

         5、用顶点法绘制物体

六、 着色器

顶点着色器

#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;//将接收的颜色传递给片元着色器
}

片段着色器

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值