如何在Doom3场景中运行多个MD5骨骼动画序列

2. 实现Doom3SceneWithMD5SkeletionApplication类:

  • 成员变量与构造函数

import { mat4, vec3 } from "../common/math/TSM";
import { HttpRequest } from "../common/utils/HttpRequest";
import { MD5SkinedMesh } from "../lib/MD5SkinedMesh";
import { GLMeshBuilder, EVertexLayout } from "../webgl/WebGLMesh";
import { GLTextureCache } from "../webgl/WebGLTextureCache";
import { GLAttribState } from "../webgl/WebGLAttribState";
import { Doom3Application } from "./Doom3Application";
import { CanvasKeyBoardEvent } from "../common/Application";

/* 继承关系:
Application
    WebGLApplication
        CameraApplication
            Doom3Application(第九章实现的Demo)
                Doom3SceneWithMD5SkeletionApplication
*/
export class Doom3SceneWithMD5SkeletionApplication extends Doom3Application{
    public model:MD5SkinedMesh;  // 要运行动画和显示的骨骼动画
    public currAnimId:number = 0; // 一个骨骼动画可以有多个动画序列,本Demo中包括【0:跑,1:出拳】
    public currFrame:number = 0; // 每个动画序列可以有n幅动画帧组成
    public texBuilder:GLMeshBuilder; // 使用纹理绘制器

    public constructor(canvas: HTMLCanvasElement){
        super( canvas); // 调用基类Doom3Application类的构造函数

        // 初始化本类的成员变量
        this.model = new MD5SkinedMesh();
        this.texBuilder = new GLMeshBuilder( this.gl, GLAttribState.POSITION_BIT | GLAttribState.TEXCOORD_BIT, this.program, GLTextureCache.instance.getMust("default"), EVertexLayout.INTERLEAVED );
    }
  • 覆写(override)基类渲染资源加载的async run虚方法

    // 本书在Application这个最顶层的类中实现了一套异步/同步加载的框架流程
    // 覆写基类的async run虚方法,该方法返回Promise<void>类型
    // 因此可以使用await进行等待同步
    public async run (): Promise<void>
    {
        // 1. 使用http从服务器请求MD5的Mesh数据,注意:使用await!!!!
        let response: string = await HttpRequest.loadTextFileAsync( MD5SkinedMesh.path + "suit.md5mesh" );
        this.model.parse(response); // 一旦获得MD5的Mesh数据后,进行词法解析并在内存中生成对应数据结构

        // 2. 然后再从服务器请求获得纹理数据,注意:也使用了await!!!!
        await this.model.loadTextures(this.gl);

        // 3. 再向服务器请求跑的动画序列数据,并且进行解析,生成对应的数据结构
        // 注意:使用await!!!!
        response = await HttpRequest.loadTextFileAsync( MD5SkinedMesh.path + "suit_walk.md5anim");
        this.model.parseAnim(response);

        // 4. 接着再向服务器请求出拳的动画序列,并且进行解析,生成对应的数据结构
        // 注意:使用await!!!!
        response = await HttpRequest.loadTextFileAsync( MD5SkinedMesh.path + "suit_punch.md5anim");
        this.model.parseAnim(response);

        // 记住一定要调用基类的run方法
        // 用来加载Doom3 Proc场景数据
        super.run();
    }
  • 覆写(override)基类的update和onKeyUp虚方法

      // 覆写基类的update虚方法
      public update ( elapsedMsec: number, intervalSec: number ): void
      {
          super.update( elapsedMsec, intervalSec ); // 先调用基类的update方法
          // 然后更新当前序列的帧号
          this.currFrame++;
          // 周而复始连续播放算法
          this.currFrame %= this.model.anims[this.currAnimId].frames.length; 
          // 计算出当前动画序列的当前帧的姿态
          this.model.playAnim(this.currAnimId,this.currFrame); 
      }
    
      // 覆写基类的onKeyUp事件处理虚方法
      // 当按1键时,运行出拳动画序列
      // 当按其他任意键时,播放跑的动画序列
      protected onKeyUp ( evt: CanvasKeyBoardEvent ): void
      {
          if(evt.key==="1"){
              this.currAnimId = 1;
              this.currFrame = 0;
          }else{
              this.currFrame = 0;
              this.currAnimId = 0;
          }
          // 调用基类的键盘事件方法
          super.onKeyUp(evt); 
      }
    
  • 覆写(override)基类的render虚方法

    // 一旦更新好后,就需要绘制
      // 实现一个受保护的方法,用来渲染MD5骨骼动画
      protected renderDoom3MD5Skeleton():void{
          this.matStack.loadIdentity();
          this.matStack.rotate(-90,vec3.right); // 将id Doom3坐标系变换为WebGL坐标系
          this.matStack.translate(new vec3([0,0,4]))
          this.matStack.rotate(this.angle,vec3.forward);
          mat4.product(this.camera.viewProjectionMatrix,this.matStack.modelViewMatrix,mat4.m0);
          this.model.drawBindPose(this.texBuilder,mat4.m0); // 绘制bindpose
          this.matStack.pushMatrix();
          this.matStack.translate(new vec3([1.0,0,0]));
          mat4.product(this.camera.viewProjectionMatrix,this.matStack.modelViewMatrix,mat4.m0);
          this.model.drawAnimPose(this.texBuilder,mat4.m0); // 绘制当前序列的某帧姿态
          this.matStack.popMatrix();
      }
    
      // 覆写基类的render虚方法
      public render (): void
      {
          // 先调用基类同名方法,这样就会绘制出整个Doom3场景
          super.render();
          // 然后在Doom3场景中显示运行MD5骨骼动画
          this.renderDoom3MD5Skeleton();
      }
    } // 类定义结速
    
随风而行之青衫磊落险峰行(www.buleifeng.top) all right reserved,powered by Gitbook本文件修订时间: 2019-10-18 15:33:53

results matching ""

    No results matching ""