实现两个三维模型的独立运动,包括每个模型的转向、前进后退、缩放功能。此处方向均以运动模型作为参考,模型正面方向为前进,相反方向为后退,绕动物中轴线转向。
完整代码已在传送门给出,效果图如下:
html文件:
首先,在html文件中定义了顶点着色器和片元着色器:
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform mat4 viewMatrix;
uniform mat4 modelViewMatrix;
void main()
{
fColor = vColor;
gl_Position = viewMatrix * modelViewMatrix * vPosition;
gl_Position.z = -gl_Position.z;
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 fColor;
void
main()
{
gl_FragColor = fColor;
}
</script>
在顶点着色器中,viewMatrix矩阵为视图矩阵,用于调整视线的方向;modelViewMatrix矩阵为模型视图矩阵,用于控制模型的方向。
js文件
在js文件中,首先做好准备工作,声明了一系列全局变量,以供后续的使用。此处给出了海绵宝宝身体各部位(立方体)的长宽高大小。值得一提的是,这里我们可以看到两个变量,direct和direct2,它们用于记录两个模型的正面方向,用于模型执行前进后退操作时确定方向。
var canvas;
var gl;
var ms = 180; // 画圆的面数
// 海绵宝宝
var points = []; // 顶点容器
var colors = []; // 颜色容器
var vColor, vPosition;
var cBuffer, vBuffer; // 海绵宝宝的buffer
var numVertices = 36*9 + ms*3*2*3 + 12; // 海绵宝宝顶点个数
var modelViewMatrix = mat4(); // 当前变换矩阵
var modelViewMatrixLoc; // shader变量
var CubeTx = 0, CubeTy = 0, CubeTz = 0; //海绵宝宝平移量
var CubeRotateAngle = 0; //海绵宝宝旋转角度
var scalePercent = 0.5; // 缩放比例
var direct = vec4( 0.0, 0.0, 1.0, 1.0 ); // 当前正面方向
// 粉色海绵宝宝
var points2 = []; // 顶点容器
var colors2 = []; // 颜色容器
var vColor2, vPosition2;
var cBuffer2, vBuffer2; // 粉色海绵宝宝的buffer
var numVertices2 = 36*9 + ms*3*2*3 + 12; // 粉色海绵宝宝顶点个数
var CubeTx2 = 0, CubeTy2 = 0, CubeTz2 = 0; // 粉色海绵宝宝平移量
var CubeRotateAngle2 = 0; // 粉色海绵宝宝旋转角度
var scalePercent2 = 0.5; // 缩放比例
var direct2 = vec4( 0.0, 0.0, 1.0, 1.0 ); // 当前正面方向
var viewMatrixLoc; // 视图矩阵的存储地址
var viewMatrix; // 当前视图矩阵
var viewIndex = 0; // 视图编号
var body = vec3( 0.4, 0.45, 0.2 );
var cloth = vec3( 0.4, 0.05, 0.2 );
var pants = vec3( 0.4, 0.1, 0.2 );
var leg = vec3( 0.06, 0.25, 0.05 );
var shoe = vec3( 0.12, 0.05, 0.05 );
// 所有的备选颜色
var chooseColors = [
vec4(1.0, 0.96, 0.30, 1.0), // 黄色
vec4(1.0, 1.0, 1.0, 1.0), // 白色
vec4(0.51, 0.33, 0.24, 1.0), // 褐色
vec4(0.0, 0.0, 0.0, 1.0), // 黑色
vec4(0.96, 0.64, 0.66, 1.0) // 粉色
];
下面进入页面加载完成后的init()函数部分。按照常规,此处获取了着色器中各个变量的地址、创建绑定缓冲区,做了一些初始化工作。
第9行:setPoints()函数的内容将在后续给出,此函数就是分别设置了两个模型的所有顶点位置及颜色,写入两个模型的points[]和colors[]数组中。由于此段代码比较长,将在最后给出。
第16-21行:设置了默认的照相机方向。lookAt()三个参数分别为:视点方向,视线方向,上方向。
canvas = document.getElementById( "gl-canvas" );
gl = WebGLUtils.setupWebGL( canvas, null );
if ( !gl ) {
alert( "WebGL isn't available" ); }
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clearColor( 0.91, 0.92, 0.93, 1.0 ); // 灰色背景色
setPoints(); // 设置所有顶点位置及颜色
gl.enable(gl.DEPTH_TEST); // 消除隐藏面
// 初始化着色器
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
gl.useProgram( program );
// 获取viewMatrix变量的存储地址
viewMatrixLoc = gl.getUniformLocation(program, 'viewMatrix');
// 设置视点、视线和上方向
viewMatrix = lookAt(vec3(0, 0, 0), vec3(0, 0, 0), vec3(0, 1, 0));
// 将视图矩阵传递给viewMatrix变量
gl.uniformMatrix4fv(viewMatrixLoc, false, flatten(viewMatrix));
// 创建缓冲区,并向缓冲区写入立方体每个面的颜色信息
cBuffer = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
gl.bufferData( gl.ARRAY_BUFFER, flatten(colors), gl.STATIC_DRAW );
//获取着色器中vColor变量,并向其传递数据
vColor = gl.getAttribLocation( program, "vColor" );
gl.enableVertexAttribArray( vColor );
cBuffer2 = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer2 );
gl.bufferData( gl.ARRAY_BUFFER, flatten(colors2