egret-docs-master/Engine3D/methods/compile/README.md

398 lines
15 KiB
Markdown
Raw Permalink Normal View History

2024-06-19 13:32:32 +08:00
## 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 摄像机控制器 。</p> * 指定摄像机看向的目标对象。</p> * 1.按下鼠标左键并移动鼠标可以使摄像机绕着目标进行旋转。</p> * 2.按下键盘的(w s a d) 可以摄像机(上 下 左 右)移动。</p> * 3.滑动鼠标滚轮可以控制摄像机的视距。</p> */
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.按下鼠标左键并移动鼠标可以使摄像机绕着目标进行旋转。</p> * 2.按下键盘的(w s a d) 可以摄像机(上 下 左 右)移动。</p> * 3.滑动鼠标滚轮可以控制摄像机的视距。</p>* 最后就是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`文件代码。
```
<div id="loadingCon" style="position:absolute;width:100%;height:100%;background:#ffffff"> <img id="loadingIcon" width="72" height="72" src="resource/logo.png" style="position:absolute;top:50%;left:50%;margin-top:-116px;margin-left:-36px" /> <div id='descCon' width="100" height="50" style="position:absolute;top:50%;left:50%;margin-top:-36px;margin-left:-50px"></div> </div>```
`inidex.html`提前添加了两个元素,一个是加载`icon`,一个是放置加载`loading`文字的`div`。而构造方法就是获取了加载`loading`文字的`div`,然后动态放入文本。
### 3.2 OnInitLoadingView
```
public OnInitLoadingView(max: number) {
this.max = max;
this.cur = 0;
if(max == 0) {
this.div.innerHTML = "正在加载:100%";
this.CloseLoadingView();
} else {
this.div.innerHTML = "正在加载:0%";
}
}
```
前边在`Main.ts`的构造方法中,初始化了`LoadingUI`,即调用了`OnInitLoadingView`方法。这个方法在`descCon`中动态加入了加载文字。
这里注意一下,`max`代表了加载资源的个数,当加载完毕后即调用`OnLoadFinished`
### 3.3 OnLoadFinished
```
public OnLoadFinished(): void {
if(this.cur == this.max) {
return;
}
if(this.cur + 1 >= this.max) {
this.div.innerHTML = "正在加载:100%";
this.CloseLoadingView();
} else {
this.cur++;
this.div.innerHTML = `正在加载:${Math.ceil(this.cur / this.max * 100)}%`;
}
}
```
每次加载素材完毕后会调用`OnLoadFinished`,这个方法将会判断是否将全部素材加载完毕,如果没有则显示进度,如果没有则调用`CloseLoadingView`隐藏`LoadingUI`。
### 3.4 CloseLoadingView
```
public CloseLoadingView(): void {
this.div.innerHTML = "正在加载:100%";
window.setTimeout(() => {
var loadingMap = document.getElementById('loadingCon');
loadingMap.hidden = true;
},1000);
}
```
很显然当前方法就是隐藏加载界面。
## 4、调试Egret3D项目
### 4.1 命令行
* 编译3D项目
> `Egret build`
* 运行3D项目
> `Egret run`
### 4.2 快捷键
* 编译3D项目
> `command shift b`
* 如果是windows
> `control shift b`
* 调试运行3D项目
> `F5`
### 4.3 可视化界面
* 点击调试按钮
![alt](575e571f2ecc6.jpg)
可以选择使用`wing内置播放器`调试或者使用浏览器调试。我们这里使用`Wing内置播放器`调试。
* 打开Wing内置播放器
![alt](575e571f3dfdd.jpg)
内置播放器集成了几个常用的功能。
* `分辨率`可以设置常用的分辨率
* `横竖屏`可以设置是横屏显示还是竖屏显示
* `缩放`可以设置缩放1倍2倍3倍
* 右键`切换显示列表查看器`继承了`Egret Inspector`查看显示列表等功能
* 右键`切换开发者工具`可以查看网络、`console`等数据
![alt](575e571f4e779.jpg)
### 4.4 修改代码调试
我们简单修改一下
```
/**
* 漫反射贴图加载回调
* @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);
}
```
上述代码屏蔽了材质的漫反射贴图代码,然后打上断点,`F5`调试
![alt](575e571f60564.jpg)
上图圈起的部分可以看到包含了主流IDE所有的调试功能包括
* `观察表达式`可以查看某个对象的数据信息
* `断点查看`可以查看当前文件中的所有断点
* `单步调试`可以一步步调试代码发现bug所在
* `变量`、`调用堆栈`等功能
![alt](575e571f6c232.jpg)
运行结果如上图因为没有漫反射贴图导致3D模型都是白色。