Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

WebGL(拾陆) 摄像机操作

  小时候坐汽车看到车窗外的景物都向后退就觉得是这个世界在跑,而我是静止的。确实是世界在跑!当我自己创造了一个世界之后才深刻体会到上帝的用心。只要让整个世界都移动就可以得到某个相对不动的物体在运动的效果。这就是我们要做的,也是上帝要做的。
  要让整个世界都移动就意味着要让所有顶点都移动,所以我们应该在顶点着色器中添加一个矩阵作为摄像机的变换矩阵。这个矩阵应该作用于整个世界的所有顶点上。甚至还要作用在一些特殊的参数也要受它影响,比如点光源位置、光线方向、视线方向,等。这些东西可以自己去体会,这篇文章要说的主要是给世界的所有顶点做摄像机变换。咱就直接来看代码吧,首先来对摄像机做个对象化以便使用。
/*摄像机对象化*/
var camera={
  rot:0,x:0,y:0,z:0,move:function(e){
    //移动时需要做朝向计算
    this.x+=Math.sin(-this.rot)*e;
    this.z+=Math.cos(-this.rot)*e;
  },toMatrix:function(){
    var s=Math.sin(this.rot),c=Math.cos(this.rot),x=this.x,z=this.z;
    //先平移,后旋转
    return [
      c,0,-s,0, 0,1,0,0, s,0,c,0, 
      c*x+s*z,this.y,c*z-s*x,1
    ];
  }
};
  这个例子中使用的摄像机操作只是做简单的操作而,只有xz平面上的运动。我懒的处理y坐标,这代码也很容易扩展到y坐标上,我就不添加多余代码了。这个封装摄像机对象的代码中定义了两个方法。move的作用是前后移动,但是由于摄像机是可以旋转的,所以前后的概念也需要根据旋转来计算,所以在move方法中把移动的值也给旋转了。后面的toMatrix方法是从这个对象中取出要传给着色器的矩阵。代码是很简单,但是逻辑就不那么简单了。return的这个矩阵其实是两个矩阵相乘的结果。我们可以把摄像机当作一个刚体,它的操作是平移和旋转,但是关键是平移和旋转的顺序是颠倒的。为什么是颠倒的呢?因为我们做的是让世界运动,而摄像机保持静止。也就是说,摄像机始终在原点位置。当摄像机的角度改变时候,整个世界是绕着摄像机转的,也就是绕着原点转。这就是先平移再旋转的结果。之前的文章也有用过刚体变换矩阵,都是先旋转再平移,那样可以得到自转的效果。而我们现在需要的效果是公转,绕着原点的摄像机公转。所以摄像机变换矩阵是先平移再旋转的。
  这篇文章的例子是使用键盘的方向键来移动摄像机位置,所以我们还需要处理键盘操作的代码。 var LEFT=37,UP=38,RIGHT=39,DOWN=40,KEYS={};
//在KEYS中储存按键状态
document.onkeydown=function(e){KEYS[e.keyCode]=true};
document.onkeyup=function(e){KEYS[e.keyCode]=false};
  这个代码定义KEYS变量来存放键盘状态,这没啥好说的吧?如果有JS基础瞬间就可以理解。接着是绘制的过程 /*绘制相关*/
setInterval(function(){
  //计算按键对摄像机的影响
  if(KEYS[LEFT])camera.rot-=0.02;
  if(KEYS[RIGHT])camera.rot+=0.02;
  if(KEYS[UP])camera.move(0.05);
  if(KEYS[DOWN])camera.move(-0.05);
  //把矩阵放入着色器
  webgl.uniformMatrix4fv(pos,false,camera.toMatrix());
  //绘制
  webgl.drawArrays(webgl.TRIANGLES,0,6);
},16);
  这个代码是根据键盘按键的状态来做摄像机的移动和旋转操作,之后获取矩阵传入着色器。下面是顶点着色器代码 attribute vec3 po;
attribute vec2 mp;
uniform mat4 pos;
uniform mat4 pro;
varying vec2 mp_v;
void main(){
  mp_v=mp;
  gl_Position=pro*pos*vec4(po,1.0);
}

  其实和刚体变换的情况基本一样,摄像机变换也是在投射之前完成的。不过要注意摄像机变换作用的是整个世界,包括光线方向之类的东西都需要做一次摄像机变换才会正确。这个例子中没用光照效果所以没有这个演示,使用时自己得注意下。最后是完整的实例

  WebGL摄像机操作
网名:
34.203.245.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^