## 1、查看项目结构 ![alt](575e571ee66bc.jpg) 查看项目源码我们可以看到,有两个文件`Main.ts`、`LoadingUI.ts`。 1. `Main.ts`是入口文件,在`Main.ts`中加载3D素材和核心逻辑代码。 2. `LoadingUI`显示加载进度条,在资源加载完毕后需要移除加载素材。 接下来咱们详细分析一下默认项目代码。 ## 2、查看Main.ts文件 ### 2.1 基本概念 ``` // Canvas操作对象 protected _egret3DCanvas: egret3d.Egret3DCanvas; // View3D操作对象 protected _view3D: egret3d.View3D; /** * look at 摄像机控制器 。
* 指定摄像机看向的目标对象。 * 1.按下鼠标左键并移动鼠标可以使摄像机绕着目标进行旋转。 * 2.按下键盘的(w s a d) 可以摄像机(上 下 左 右)移动。 * 3.滑动鼠标滚轮可以控制摄像机的视距。 */ private cameraCtl: egret3d.LookAtController; // 灯光组 private lights: egret3d.LightGroup = new egret3d.LightGroup(); // 模型对象 private model: egret3d.Mesh; // 待机动画 private idle: egret3d.SkeletonAnimationClip; // 加载界面 private loadingUI = new LoadingUI(); ``` * `_egret3DCanvas`存放view3D对象 * `_view3D`存放3D模型对象 * `cameraCtl`摄像机控制器,可以设置查看3D对象的距离、角度等参数 * `lights`存放灯光数据,没有灯光3D模型就会是黑色,就像黑夜看不见东西一样 * `model`3D模型对象,放到_view3D中 * `idle`存放3D骨骼动画 * `loadingUI`加载界面,控制加载图片文本的显示隐藏 我们目前先不做详细解释,先知道怎么用,在后续文档中会详细介绍各个概念的用法。 ### 2.2 查看构造方法 ``` super(); //创建Canvas对象。 this._egret3DCanvas = new egret3d.Egret3DCanvas(); //Canvas的起始坐标,页面左上角为起始坐标(0,0)。 this._egret3DCanvas.x = 0; this._egret3DCanvas.y = 0; //设置Canvas页面尺寸。 this._egret3DCanvas.width = window.innerWidth; this._egret3DCanvas.height = window.innerHeight; //创建View3D对象,页面左上角为起始坐标(0,0) this._view3D = new egret3d.View3D(0,0,window.innerWidth,window.innerHeight); //当前对象对视位置,其参数依次为: //@param pos 对象的位置 //@param target 目标的位置 this._view3D.camera3D.lookAt(new egret3d.Vector3D(0,0,1000),new egret3d.Vector3D(0,0,0)); //View3D的背景色设置 this._view3D.backColor = 0xffffffff; //将View3D添加进Canvas中 this._egret3DCanvas.addView3D(this._view3D); //创建平行光 var dirLight: egret3d.DirectLight = new egret3d.DirectLight(new egret3d.Vector3D(0.3,-0.3,0.1)); dirLight.diffuse = 0xffffff; this.lights.addLight(dirLight); ///创建加载类 var load: egret3d.URLLoader = new egret3d.URLLoader(); //设置加载完成回调 load.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE,this.onLoad,this); //开始加载 load.load("resource/LingTong/Bonezero.esm"); this.InitCameraCtl(); //启动Canvas。 this._egret3DCanvas.start(); this._egret3DCanvas.addEventListener(egret3d.Event3D.ENTER_FRAME,this.update,this); this.loadingUI.OnInitLoadingView(3); //设置window resize事件 egret3d.Input.addEventListener(egret3d.Event3D.RESIZE,this.OnWindowResize,this); ``` 构造方法中主要进行对象的实例化,我们一个个解释一下。 * 实例化Canvas对象和View3D对象,然后把View3D对象放到Canvas对象中,舞台就可以显示View3D中的内容。 * 实例化平行光对象,稍后可以添加到3D模型上 >`this.model.material.lightGroup = this.lights;` * load是加载类用来加载`.esm``.eam``.png`等素材文件 * 所有准备好就可以启动Canvas了 >`this._egret3DCanvas.start();` * 而`this.update`方法则用来持续渲染摄像机控制器,它集成了很多功能。 只需要在帧循环事件中调用`this.cameraCtl.update();`即可实现如下功能。 * 1.按下鼠标左键并移动鼠标可以使摄像机绕着目标进行旋转。 * 2.按下键盘的(w s a d) 可以摄像机(上 下 左 右)移动。 * 3.滑动鼠标滚轮可以控制摄像机的视距。* 最后就是LoadingUI实例化,开始初始化,后续会调用加载进度,最后素材加载完毕后移除LoadingUI,下一个小节我们专门解释一下LoadingUI ### 2.3 相机方法相关 接下来我们单独解释一下各个方法功能以及用法。 ``` public update(e: egret3d.Event3D) { this.cameraCtl.update(); } ``` 这个其实是用来持续渲染摄像机控制器,上边已经解释过。 ``` /** * 初始化相机控制 */ private InitCameraCtl() { //摄像机控制类 this.cameraCtl = new egret3d.LookAtController(this._view3D.camera3D,new egret3d.Object3D()); //设置目标和相机的距离 this.cameraCtl.distance = 300; //设置相机x轴旋转 this.cameraCtl.rotationX = 0; } ``` 这个方法是设置一些摄像机初始数值,比如 > `this.cameraCtl.distance = 300` 是设置摄像机距离观察对象为300,稍后我们在第三节`调试Egret3D项目`中修改测试。 > `this.cameraCtl.rotationX = 0` 这句话则是调整摄像机的x轴角度为0. ### 2.4 窗口尺寸变化监听 ``` /** * 窗口尺寸变化事件 */ private OnWindowResize(e: egret3d.Event3D): void { //重置ui大小 this._egret3DCanvas.width = window.innerWidth; this._egret3DCanvas.height = window.innerHeight; this._view3D.width = window.innerWidth; this._view3D.height = window.innerHeight; } ``` 这个方法是当浏览器窗口变化时,保证3D场景能够及时更新。 ### 2.5 模型加载数据处理 ``` //创建加载类 var load: egret3d.URLLoader = new egret3d.URLLoader(); //设置加载完成回调 load.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE,this.onLoad,this); //开始加载 load.load("resource/LingTong/Bonezero.esm"); ``` 以上处理加载Egret模型数据,通过上述代码实现。 ``` /** * 模型加载回调 * @param e: egret3d.URLLoader 加载器对象 */ protected onLoad(e: egret3d.LoaderEvent3D) { this.loadingUI.OnLoadFinished(); //创建纹理材质 var mat = new egret3d.TextureMaterial(); //创建模型基类 var ge: egret3d.Geometry = e.loader.data; //生成mesh this.model = new egret3d.Mesh(ge,mat); if(ge.vertexFormat & egret3d.VertexFormat.VF_SKIN) { ///设置骨骼动画 this.model.animation = new egret3d.SkeletonAnimation(ge.skeleton); } this.model.material.lightGroup = this.lights; this.model.y = -100; //插入model this._view3D.addChild3D(this.model); var loadtex: egret3d.URLLoader = new egret3d.URLLoader(); //注册贴图读取完成回调 loadtex.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE,this.onLoadTexture,this); //开始读取贴图 loadtex.load("resource/LingTong/hero_12.png"); loadtex["mat"] = mat; var loadAniIdle: egret3d.URLLoader = new egret3d.URLLoader(); //注册动画读取完成回调 loadAniIdle.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE,this.onAnimationIdle,this); //开始读取动画 loadAniIdle.load("resource/LingTong/Idle.eam"); } ``` 首先检查数据是否加载完成 > `this.loadingUI.OnLoadFinished();` 这个稍后再下个小节再说 ``` //创建纹理材质 var mat = new egret3d.TextureMaterial(); //创建模型基类 var ge: egret3d.Geometry = e.loader.data; //生成mesh this.model = new egret3d.Mesh(ge,mat); ``` 然后创建纹理材质保留后用,创建模型数据对象,生成mesh对象。 ``` if(ge.vertexFormat & egret3d.VertexFormat.VF_SKIN) { ///设置骨骼动画 this.model.animation = new egret3d.SkeletonAnimation(ge.skeleton); } this.model.material.lightGroup = this.lights; this.model.y = -100; //插入model this._view3D.addChild3D(this.model); ``` * 然后绑定骨骼动画到`mesh`上。 * 注意这里在材质上边绑定了平行光`this.lights`,这样可以保证模型有亮度,而不是黑乎乎的一片。 * 最后将模型添加到`view3D`上。 ``` var loadtex: egret3d.URLLoader = new egret3d.URLLoader(); //注册贴图读取完成回调 loadtex.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE,this.onLoadTexture,this); //开始读取贴图 loadtex.load("resource/LingTong/hero_12.png"); loadtex["mat"] = mat; var loadAniIdle: egret3d.URLLoader = new egret3d.URLLoader(); //注册动画读取完成回调 loadAniIdle.addEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE,this.onAnimationIdle,this); //开始读取动画 loadAniIdle.load("resource/LingTong/Idle.eam"); ``` 接下来加载贴图素材,加载动画素材。 ### 2.6 模型加载贴图 ``` /** * 漫反射贴图加载回调 * @param e: egret3d.URLLoader 加载器对象 */ protected onLoadTexture(e: egret3d.LoaderEvent3D) { this.loadingUI.OnLoadFinished(); //设置材质的漫反射贴图。 e.loader["mat"].diffuseTexture = e.loader.data; //注销回调 e.loader.removeEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE,this.onLoadTexture,this); } ``` 贴图加载完毕后,设置材质的漫反射贴图。如果没有设置的话,就会变成如下效果。 ![alt](575e571f1be44.jpg) ### 2.7 模型加载动画文件 ``` /** * 动画加载回调 * @param e: egret3d.URLLoader 加载器对象 */ protected onAnimationIdle(e: egret3d.LoaderEvent3D) { this.loadingUI.OnLoadFinished(); //骨骼动画 this.idle = e.loader.data; //动画名称 this.idle.animationName = "idle"; //添加clip this.model.animation.skeletonAnimationController.addSkeletonAnimationClip(this.idle); //播放动画 this.model.animation.skeletonAnimationController.play(this.idle.animationName); //注销回调 this.model.removeEventListener(egret3d.LoaderEvent3D.LOADER_COMPLETE,this.onAnimationIdle,this); } ``` 将骨骼动画添加到模型上,3D模型就可以包含动作了。如果没有骨骼动画,3D模型就没有动作,像一个雕塑你养。 ### 3、查看LoadingUI.ts文件 `LoadingUI`包含了四个方法,`构造方法`、`OnInitLoadingView`、`OnLoadFinished`、`CloseLoadingView`。 ### 3.1 构造方法 > this.div = document.getElementById('descCon'); 看代码我们发现,这是通过`document`获取了`html`中的一个id为`descCon`的元素。 接着咱们看一下`index.html`文件代码。 ```