PhiloGL学习(2)——骚年,让我们荡起双桨

时间:2023-09-06 17:25:09

前言

上一篇文章中简单介绍了PhiloGL框架如何上手、GLSL语言以及简单的绘制一个方块(见PhiloGL学习(1)——场景创建及二维方块加载)。本文很简单,我们一起来让这个方块动起来。

一、 原理分析

以上一篇文章为基础,其中的html部分不需要修改,js部分仅做简单修改。本文主要操作的是camera。

想让一个物体动起来与现实情况一致,要么是调整自身姿态要么是调整自身位置。调整姿态是为旋转,调整位置是为移动,在PhiloGL中即为调整对象的position或者rotation。当然还有一种情况是你绕着一个物体转或者你冲着物体移动,这就牵涉到相对运动了,任何东西你只要深入思考一下就能上升到哲学问题。

骚年,有了思路就干起来吧!

二、 实现动画

2.1 创建对象

上一篇文章中我们采用为各种变量赋值的方式创建了一个方块,对于习惯面向对象编程的我来说比较喜欢将所有东西看成类,那么物体这个东西当然可以抽象成一个类。是的,PhiloGL为我们准备了这么一个类。我们就可以使用下述方式创建一个对象:

var square = new PhiloGL.O3D.Model({
    vertices: [ 1,  1, 0,
      -1,  1, 0,
      1, -1, 0,
      -1, -1, 0],
    
    colors: [0.9, 0.9, 1, 1,
      0.5, 0.5, 1, 1,
      0.5, 0.5, 1, 1,
      0.2, 0.5, 1, 1]
});

很简单,为Model对象传入vertices和colors即可,vertices即为上一篇文章中的aVertexPosition变量值,colors即为上一篇文章中的aVertexColor。

2.2 加载对象

理解了对象就是不同数据的集合之后一切就会变的简单,只需要将对象的属性替换上一篇文章中的值即可。

其实绘制一个对象主要是设置GLSL中的颜色和位置。那么主要就是进行setBuffers设置。

program.setBuffers({
  'aVertexPosition': {
    value: square.vertices,
    size: 3
  },
  'aVertexColor': {
    value: square.colors,
    size: 4
  }
});

这与上一篇文章中设置的setBuffers稍微不同,去除了attribute项,而是将内容直接写成了key,这样就相当于直接设置GLSL attribute变量中的此值,注意此种方法只能设置当前单一对象。

上一篇文章中使用camera.view.$translate(0, 0, -5)来设置物体的位置,有了上述对象的概念之后我们可以直接使用下述方式来设置对象的位置和旋转角度:

square.position.set(0, 0, -7);
square.rotation.set(0, 0, 0);

但是我们仍要将此对象的状态与Camera结合以进行正确的三维到二维的投影。

首先,将对象的状态与Camera的view结合:

var view = new PhiloGL.Mat4
view.mulMat42(camera.view, square.matrix);

此段代码完成的工作是将camera.view与square.matrix进行乘积操作,其实这与$translate操作基本一致。

然后将得到的view传给uMVMatrix参数即可:

program.setUniform('uMVMatrix', view);
program.setUniform('uPMatrix', camera.projection);

其他的与上一篇文章一致,将显示的代码封装成如下几个函数:

function setupElement(elem) {
    elem.update();
    view.mulMat42(camera.view, elem.matrix);
    program.setBuffers({
      'aVertexPosition': {
        value: elem.vertices,
        size: 3
      },
      'aVertexColor': {
        value: elem.colors,
        size: 4
      }
    });
    program.setUniform('uMVMatrix', view);
    program.setUniform('uPMatrix', camera.projection);
} function drawScene() {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
    square.position.set(x, y, -7);
    square.rotation.set(xRotation, yRotation, 0);
    setupElement(square);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}

其中elem.update()函数表示重新计算对象的状态,这与后面要介绍的动画关系比较密切。

2.3 骚年,让我们荡起双桨(动起来)

写到此,一切都已经很明了了,只需要加入类似time的循环操作改变square.position.set和square.rotation.set的值,这样即可让对象在场景中移动起来。

PhiloGL提供了PhiloGL.Fx.requestAnimationFrame(callback)函数来设置动画,callback为回调函数,查看此函数的源码不难看出,其调用了setTimeout函数,并且时间是1000/60,即每毫秒执行一次。

这样我们首先设置变量来记录对象的位置即姿态,每循环一次按照业务逻辑来改变x、y、z或旋转角度:

function animate() {
    xRotation += 0.01;
    yRotation -= 0.01;
    
    if (x >= 3)
      xSpeed = -0.01;
    else if (x <= -3)
      xSpeed = 0.01;
    if (y >= 3)
      ySpeed = -0.01;
    else if (y <= -3)
      ySpeed = 0.01;
    
    x += xSpeed;
    y += ySpeed;
}

然后设置循环,在循环中执行重绘对象及改变状态:

function tick() {
    animate();
    drawScene();
    PhiloGL.Fx.requestAnimationFrame(tick);
}

onLoad中调用tick函数即可,这样我们的方块就会边旋转边移动。让我们荡起双桨~~~~~~

三、 总结

本文简单介绍了如何让我们的方块荡起来,下一篇文章介绍如何通过键盘和鼠标来控制我们的对象和场景。