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

2. 实现Doom3SceneWithMD5SkeletionApplication类:

  • 成员变量与构造函数

  1. import { mat4, vec3 } from "../common/math/TSM";
  2. import { HttpRequest } from "../common/utils/HttpRequest";
  3. import { MD5SkinedMesh } from "../lib/MD5SkinedMesh";
  4. import { GLMeshBuilder, EVertexLayout } from "../webgl/WebGLMesh";
  5. import { GLTextureCache } from "../webgl/WebGLTextureCache";
  6. import { GLAttribState } from "../webgl/WebGLAttribState";
  7. import { Doom3Application } from "./Doom3Application";
  8. import { CanvasKeyBoardEvent } from "../common/Application";
  9. /* 继承关系:
  10. Application
  11. WebGLApplication
  12. CameraApplication
  13. Doom3Application(第九章实现的Demo)
  14. Doom3SceneWithMD5SkeletionApplication
  15. */
  16. export class Doom3SceneWithMD5SkeletionApplication extends Doom3Application{
  17. public model:MD5SkinedMesh; // 要运行动画和显示的骨骼动画
  18. public currAnimId:number = 0; // 一个骨骼动画可以有多个动画序列,本Demo中包括【0:跑,1:出拳】
  19. public currFrame:number = 0; // 每个动画序列可以有n幅动画帧组成
  20. public texBuilder:GLMeshBuilder; // 使用纹理绘制器
  21. public constructor(canvas: HTMLCanvasElement){
  22. super( canvas); // 调用基类Doom3Application类的构造函数
  23. // 初始化本类的成员变量
  24. this.model = new MD5SkinedMesh();
  25. this.texBuilder = new GLMeshBuilder( this.gl, GLAttribState.POSITION_BIT | GLAttribState.TEXCOORD_BIT, this.program, GLTextureCache.instance.getMust("default"), EVertexLayout.INTERLEAVED );
  26. }
  • 覆写(override)基类渲染资源加载的async run虚方法

  1. // 本书在Application这个最顶层的类中实现了一套异步/同步加载的框架流程
  2. // 覆写基类的async run虚方法,该方法返回Promise<void>类型
  3. // 因此可以使用await进行等待同步
  4. public async run (): Promise<void>
  5. {
  6. // 1. 使用http从服务器请求MD5的Mesh数据,注意:使用await!!!!
  7. let response: string = await HttpRequest.loadTextFileAsync( MD5SkinedMesh.path + "suit.md5mesh" );
  8. this.model.parse(response); // 一旦获得MD5的Mesh数据后,进行词法解析并在内存中生成对应数据结构
  9. // 2. 然后再从服务器请求获得纹理数据,注意:也使用了await!!!!
  10. await this.model.loadTextures(this.gl);
  11. // 3. 再向服务器请求跑的动画序列数据,并且进行解析,生成对应的数据结构
  12. // 注意:使用await!!!!
  13. response = await HttpRequest.loadTextFileAsync( MD5SkinedMesh.path + "suit_walk.md5anim");
  14. this.model.parseAnim(response);
  15. // 4. 接着再向服务器请求出拳的动画序列,并且进行解析,生成对应的数据结构
  16. // 注意:使用await!!!!
  17. response = await HttpRequest.loadTextFileAsync( MD5SkinedMesh.path + "suit_punch.md5anim");
  18. this.model.parseAnim(response);
  19. // 记住一定要调用基类的run方法
  20. // 用来加载Doom3 Proc场景数据
  21. super.run();
  22. }
  • 覆写(override)基类的update和onKeyUp虚方法

  1. // 覆写基类的update虚方法
  2. public update ( elapsedMsec: number, intervalSec: number ): void
  3. {
  4. super.update( elapsedMsec, intervalSec ); // 先调用基类的update方法
  5. // 然后更新当前序列的帧号
  6. this.currFrame++;
  7. // 周而复始连续播放算法
  8. this.currFrame %= this.model.anims[this.currAnimId].frames.length;
  9. // 计算出当前动画序列的当前帧的姿态
  10. this.model.playAnim(this.currAnimId,this.currFrame);
  11. }
  12. // 覆写基类的onKeyUp事件处理虚方法
  13. // 当按1键时,运行出拳动画序列
  14. // 当按其他任意键时,播放跑的动画序列
  15. protected onKeyUp ( evt: CanvasKeyBoardEvent ): void
  16. {
  17. if(evt.key==="1"){
  18. this.currAnimId = 1;
  19. this.currFrame = 0;
  20. }else{
  21. this.currFrame = 0;
  22. this.currAnimId = 0;
  23. }
  24. // 调用基类的键盘事件方法
  25. super.onKeyUp(evt);
  26. }
  • 覆写(override)基类的render虚方法

  1. // 一旦更新好后,就需要绘制
  2. // 实现一个受保护的方法,用来渲染MD5骨骼动画
  3. protected renderDoom3MD5Skeleton():void{
  4. this.matStack.loadIdentity();
  5. this.matStack.rotate(-90,vec3.right); // 将id Doom3坐标系变换为WebGL坐标系
  6. this.matStack.translate(new vec3([0,0,4]))
  7. this.matStack.rotate(this.angle,vec3.forward);
  8. mat4.product(this.camera.viewProjectionMatrix,this.matStack.modelViewMatrix,mat4.m0);
  9. this.model.drawBindPose(this.texBuilder,mat4.m0); // 绘制bindpose
  10. this.matStack.pushMatrix();
  11. this.matStack.translate(new vec3([1.0,0,0]));
  12. mat4.product(this.camera.viewProjectionMatrix,this.matStack.modelViewMatrix,mat4.m0);
  13. this.model.drawAnimPose(this.texBuilder,mat4.m0); // 绘制当前序列的某帧姿态
  14. this.matStack.popMatrix();
  15. }
  16. // 覆写基类的render虚方法
  17. public render (): void
  18. {
  19. // 先调用基类同名方法,这样就会绘制出整个Doom3场景
  20. super.render();
  21. // 然后在Doom3场景中显示运行MD5骨骼动画
  22. this.renderDoom3MD5Skeleton();
  23. }
  24. } // 类定义结速