您现在的位置:首页 >> 前端 >> 内容

用webgl绘制一个彩色旋转立方体

时间:2017/7/8 11:32:50 点击:

  核心提示:用webgl绘制一个彩色旋转立方体今天给大家分享一个用webgl写的简单的三维场景:转动的交互式彩色立方体,其六个面的颜色都不一样。上次绘制二维彩色矩形时讲到,二维是三维场景的特殊情况,所以由二维向三...

用webgl绘制一个彩色旋转立方体

今天给大家分享一个用webgl写的简单的三维场景:转动的交互式彩色立方体,其六个面的颜色都不一样。

上次绘制二维彩色矩形时讲到,二维是三维场景的特殊情况,所以由二维向三维拓展也并不难,webgl里面提供了画三角形的方法,立方体有6个面,一个面由两个三角形组成,共计需要12个三角形,每个三角形又有3个顶点,故绘制立方体需要36个点,而实际上立方体只有8个顶点,这8个顶点有序组合成6个矩形面,如下图所示:

用webgl绘制一个彩色旋转立方体vczltqW148q+0uLNvA==" height="343" src="/uploadfile/Collfiles/20170706/20170706091609270.png" width="524" />

在程序里面有一个quad(a,b,c,d),表示一个矩形面,例如quad(v0,v1,v2,v3),表示第一个矩形面,其实为两个三角形构成,分别为(v1,v0,v3), (v1, v3,v2),按照这样的顶点索引顺序来画三角形,并最终构成整个立方体。

最终程序运行如下图:在最底下的三个按钮是用于控制立方体绕坐标轴旋转的交互式按钮。

用webgl绘制一个彩色旋转立方体
下面是本例的代码:

cube.js:

/**
 * Created by wjh on 2017/6/27.
 */
"use strict";
var canvas;
var gl;
var points = [];//顶点容器
var colors = [];//颜色容器
var control;
var u_control=[0,0,0];
var xAxis = 0;
var yAxis = 1;
var zAxis = 2;
var axis = 0;
umVertices = 36;//立方体需要12个三角形,共36个顶点

function init(){
    canvas = document.getElementById("cube");
    gl=WebGLUtils.setupWebGL(canvas);
    if(!gl){alert("您的浏览器不支持WebGL!");}

   gl.viewport(0,0,canvas.width,canvas.height);//设置视口大小
    gl.clearColor(0.0,0.0,0.0,1.0);//设置背景颜色
    colorCube();//彩色立方体
    gl.enable(gl.DEPTH_TEST);//消除隐藏面
    //初始化着色器
    var program = initShaders(gl,"v-shader","f-shader");
    gl.useProgram(program);

   //创建缓冲区,并向缓冲区写入立方体每个面的颜色信息
    var cBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW );

   //获取着色器中a_Color变量,并向其传递数据
    var a_Color = gl.getAttribLocation( program, "a_Color" );
    gl.vertexAttribPointer( a_Color, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( a_Color );

   //创建缓冲区,并向缓冲区写入立方体的顶点左边信息
    var vBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(points), gl.STATIC_DRAW );
    //获取着色器中a_Position变量,并向其传递数据
    var a_Position = gl.getAttribLocation(program,"a_Position");
    gl.vertexAttribPointer(a_Position,4,gl.FLOAT,false,0,0);
    gl.enableVertexAttribArray(a_Position);
    //设置正射投影,即盒状空间,获取着色器变量u_Matrix,并传递数据
    var u_Matrix = gl.getUniformLocation(program,"u_Matrix");
    if(!u_Matrix){alert("获取u_Matrix位置失败!")}
    var iMatrix = new Matrix4();
    iMatrix.setOrtho(3,-3,-3,3,5,-5);
    gl.uniformMatrix4fv(u_Matrix,false,iMatrix.elements);
    control = gl.getUniformLocation(program,"u_control");

   //添加窗口监听事件,在窗口底下的三个按钮,用于控制立方体绕坐标轴转动
    document.getElementById( "xButton" ).onclick = function () {
        axis = xAxis;
    };
    document.getElementById( "yButton" ).onclick = function () {
        axis = yAxis;
    };
    document.getElementById( "zButton" ).onclick = function () {
        axis = zAxis;
    };
   render();//执行绘图函数
}
//彩色立方体的顶点索引
function colorCube()
{
    quad( 1, 0, 3, 2 );//第一个面
    quad( 2, 3, 7, 6 );//第二个面
    quad( 3, 0, 4, 7 );//第三个面
    quad( 6, 5, 1, 2 );//第四个面
    quad( 4, 5, 6, 7 );//第五个面
    quad( 5, 4, 0, 1 );//第六个面
}
function quad(a,b,c,d){
    //立方体的八个顶点(x,y,z,a)
    var vertices=[
        vec4( -1.0, -1.0,  1.0, 1.0 ),
        vec4( -1.0,  1.0,  1.0, 1.0 ),
        vec4(  1.0,  1.0,  1.0, 1.0 ),
        vec4(  1.0, -1.0,  1.0, 1.0 ),
        vec4( -1.0, -1.0, -1.0, 1.0 ),
        vec4( -1.0,  1.0, -1.0, 1.0 ),
        vec4(  1.0,  1.0, -1.0, 1.0 ),
        vec4(  1.0, -1.0, -1.0, 1.0 )
    ];
    //立方体面的颜色信息(r,g,b,a)
    var cubeColors = [
        [ 0.0, 0.0, 0.0, 1.0 ],  // 黑
        [ 1.0, 0.0, 0.0, 1.0 ],  // 红
        [ 1.0, 1.0, 0.0, 1.0 ],  // 黄
        [ 0.0, 1.0, 0.0, 1.0 ],  // 绿
        [ 0.0, 0.0, 1.0, 1.0 ],  // 蓝
        [ 1.0, 0.0, 1.0, 1.0 ],  // 品红
        [ 0.0, 1.0, 1.0, 1.0 ],  // 青色
        [ 1.0, 1.0, 1.0, 1.0 ]  //白色
    ];
    var indices = [ a, b, c, a, c, d ];//顶点索引顺序
    //存取顶点余顶点索引信息算法
    for ( var i = 0; i < indices.length; ++i ) {
        points.push( vertices[indices[i]] );
        //quad(1,0,3,2)按照indice的索引,另points.push(vertices[1],vertices[0],
        // vertices[3],vertices[1],vertices[3],vertices[2]);
        //再执行quad()......,直到六个quad()全执行完
        colors.push(cubeColors[a]);
    }

}
//绘制立方体
function render(){
    //清除缓存和深度清除
    gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
    //控制立方体旋转
    u_control[axis] += 2.0;
    //获取顶点着色器中u_control的位置
    gl.uniform3fv(control, u_control);
    //画立方体
    gl.drawArrays(gl.TRIANGLES,0,NumVertices);
    //循环函数,用于无限执行和渲染动画,让立方体一直转动
    requestAnimationFrame(render);
}
window.onload = init;//窗口加载init函数,使立方体最终显示在屏幕上

cube.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>cube</title>
    <!--顶点着色器-->
    <script id="v-shader" type="x-shader/x-vertex">
        attribute vec4 a_Position;
        attribute vec4 a_Color;
        uniform   mat4 u_Matrix;
        uniform   vec3 u_control;
        varying   vec4 v_Color;
        void main()
        {
          vec3 angles = radians(u_control);
          vec3 c = cos(angles);
          vec3 s = sin(angles);
          <!--旋转矩阵-->
          mat4 rx = mat4 (1.0,0.0,0.0,0.0,
                     0.0,c.x,s.x,0.0,
                     0.0,-s.x,c.x,0.0,
                     0.0,0.0,0.0,1.0);
 
          mat4 ry = mat4(c.y,0.0,-s.y,0.0,
                         0.0,1.0, 0.0,0.0,
                         s.y,0.0,c.y,0.0,
                         0.0,0.0,0.0,1.0);
          mat4 rz = mat4(c.z,s.z,0.0,0.0,
                        -s.z,c.z,0.0,0.0,
                         0.0,0.0,1.0,0.0,
                         0.0,0.0,0.0,1.0);
 
 
          gl_Position =  u_Matrix * rz * ry * rx * a_Position;
          gl_Position.z = -gl_Position.z;
          v_Color = a_Color;
        }
    </script>
    <!--片元着色器-->
    <script id="f-shader" type="x-shader/x-fragment">
 
        precision mediump float;
 
        varying vec4 v_Color;
        void main()
        {
          gl_FragColor = v_Color;
        }
    </script>
   <!--调用js文件-->
    <script type="text/javascript" src="../../libs/webgl-utils.js"></script>
    <script type="text/javascript" src="../../libs/MV.js"></script>
    <script type="text/javascript" src="../../libs/initShaders.js"></script>
    <script type="text/javascript" src="../../libs/cuon-matrix.js"></script>
    <script type="text/javascript" src="cube.js"></script>
</head>
<body>
<canvas id="cube" width="618" height="618">
</canvas>
<br/>
<!--在界面添加操作按钮-->
<button id="xButton">Rotate X</button>
<button id="yButton">Rotate Y</button>
<button id="zButton">Rotate Z</button>
</body>
</html>

Tags:用W WE EB BG 
作者:网络 来源:qq_3733898