Away3D 优化技巧与实用指南
1. 优化材质
Away3D 中的材质在复杂度和风格上差异很大,为了减少它们对内存和处理能力的消耗,可以采用多种优化方法。像使用纹理或光照的复杂材质,如果使用不当,会大量消耗资源。因此,在 Away3D 项目中,花些时间避免不必要的材质浪费是很有必要的。
1.1 材质优化方法
以下是一些优化材质的方法:
-
避免过度使用复杂材质
:复杂材质如使用纹理或光照的材质,会消耗大量资源,应谨慎使用。
-
合理选择材质类型
:根据场景需求,选择合适的材质类型,避免使用过于复杂的材质。
-
优化材质参数
:调整材质的参数,如透明度、反射率等,以减少资源消耗。
2. 优化着色
在探索任何 3D Flash 引擎时,动态实时着色是最令人兴奋的特性之一。在 Away3D 中使用着色材质,可以创建包含多个光源的场景,并控制各种着色选项。然而,在 Flash 中大量使用动态光照时,性能会很快受到限制。由于当前 Flash Player 的软件渲染器,几乎不可能实时完全着色复杂场景。因此,在需要着色时,需要在静态和动态着色之间进行选择,并限制动态着色的使用量。
2.1 静态着色
静态着色有两种常见方法:纹理烘焙和表面缓存。
-
纹理烘焙(Texture Baking)
:在导入图像之前,将纹理的位图数据与静态光照贴图相乘。由于着色步骤在 Flash Player 外部完成,因此可以使用标准位图材质在 Away3D 中实现着色效果,而无需额外的处理成本。这种技术适用于背景网格和相对于光源位置固定的对象。可以使用专业 3D 程序(如 Maya、LightWave、Blender 和 3ds Max)或免费程序 Prefab3D 进行纹理烘焙。
-
表面缓存(Surface Caching)
:对于偶尔需要更新光照贴图的 3D 对象,可以使用表面缓存技术在运行时生成着色材质的静态输出,并可以偶尔更新光照贴图。在 Away3D 的大多数位图着色材质(如 PhongBitmapMaterial 和 Dot3BitmapMaterial)中都可以使用表面缓存,通过将材质的 surfaceCache 属性设置为 true 来激活。激活表面缓存的材质看起来与未缓存的材质非常相似,但渲染速度几乎与常规位图材质一样快。不过,不建议将表面缓存应用于需要每帧更新的着色材质。
2.2 不同着色选项示例
| 着色选项 | 材质类型 | 特点 |
|---|---|---|
| No shading | 标准位图材质 | 无着色效果 |
| Baked | 标准位图材质 | 通过纹理烘焙实现着色效果 |
| Away3D Dot3 | DOT3 位图材质 | 动态平滑着色,可使用表面缓存提高性能 |
| Away3D Phong | Phong 位图材质 | 动态平滑着色,可使用表面缓存提高性能 |
2.3 静态着色操作步骤
graph LR
A[选择静态着色方法] --> B{纹理烘焙}
A --> C{表面缓存}
B --> D[使用专业3D程序或Prefab3D进行纹理烘焙]
C --> E[选择支持表面缓存的材质]
E --> F[将surfaceCache属性设置为true]
3. 法线贴图图像
在 Away3D 提供的所有动态着色选项中,DOT3 材质是最有效和通用的着色材质类型之一。然而,要使用 DOT3 材质,需要一个法线贴图图像,而在没有专业建模软件的情况下,生成法线贴图图像可能会很困难。
away3d.materials.utils
包中的
NormalMapGenerator
类提供了一种解决方案,它可以在运行时使用任何 3D 网格作为输入生成法线贴图图像,前提是提供的几何体中的 UV 数据不包含重叠的 UV 坐标。
3.1 使用
NormalMapGenerator
类生成法线贴图的步骤
- 创建文档类 :
package flash3dbook.ch10
{
import away3d.core.base.*;
import away3d.core.math.*;
import away3d.core.utils.*;
import away3d.events.*;
import away3d.lights.*;
import away3d.loaders.*;
import away3d.materials.*;
import away3d.materials.utils.*;
import flash3dbook.ch10.models.*;
[SWF(width="800", height="600")]
public class UsingNormalMapGenerator extends Chapter10SampleBase
{
[Embed(source="../../assets/ch10/headtexture.jpg")]
private var HeadTexture : Class;
private var _head : ObjectContainer3D;
private var _generator : NormalMapGenerator;
private var _light : DirectionalLight3D;
public function UsingNormalMapGenerator()
{
super();
}
private function _onTraceProgress(event:TraceEvent):void {
trace("Processing normal map : " + event.percent.toFixed(0) + "% complete");
}
private function _onTraceComplete(event:TraceEvent):void {
trace("Completed normal map");
}
protected override function _createScene() : void
{
}
}
}
- 导入模型 :
_head = new HeadModel();
_head.scale(30);
_view.scene.addChild(_head);
- 设置光源 :
_light = new DirectionalLight3D();
_light.ambient = 0.3;
_light.diffuse = 0.5;
_light.specular = 0.5;
_light.direction = new Number3D(0.5, -0.5, 0);
_view.scene.addLight(_light);
- 生成法线贴图 :
_generator = new NormalMapGenerator(_head, 512, 512);
_generator.addEventListener(TraceEvent.TRACE_PROGRESS, _onTraceProgress);
_generator.addEventListener(TraceEvent.TRACE_COMPLETE, _onTraceComplete);
_generator.execute();
- 应用 DOT3 材质 :
private function _onTraceComplete(event:TraceEvent):void {
trace("Completed normal map");
_head.children[0].children[0].material = new
Dot3BitmapMaterial(Cast.bitmap(HeadTexture), _generator.normalMap);
}
3.2 保持光源相对于相机静止的代码
override protected function _onEnterFrame(ev : Event) : void
{
super._onEnterFrame(ev);
var angle:Number = (_camera.rotationY)*Math.PI/180;
_light.direction = new Number3D(-Math.cos(angle), -0.5, Math.sin(angle));
}
4. 节省材质实例
与任何 Flash 应用程序一样,减少 Away3D 项目中新对象实例的数量可以降低整体内存消耗并提高性能。最常见的方法是通过对象池和重用。在 Away3D 中,位图材质实例由于占用大量内存,是重用的主要候选对象。
4.1 优化内存消耗示例
以下是创建 50 个随机位置立方体的示例,展示了如何通过重用位图材质实例来优化内存消耗。
-
未优化代码
:
package flash3dbook.ch10
{
import away3d.core.utils.*;
import away3d.materials.*;
import away3d.primitives.*;
[SWF(width="800", height="600")]
public class BitmapInstanceTest extends Chapter10SampleBase
{
[Embed(source="../../assets/ch10/cubetexture.jpg")]
private var CubeTexture : Class;
public function BitmapInstanceTest()
{
super();
}
protected override function _createScene() : void
{
// create 50 cubes
for (var i : int = 0; i < 50; i++) {
var cube : Cube = new Cube();
// assign a random position to the cube
cube.x = (Math.random()-.5)*1000;
cube.y = (Math.random()-.5)*1000;
cube.z = (Math.random()-.5)*1000;
// assign a new bitmap material to the cube
cube.material = new BitmapMaterial(Cast.bitmap(CubeTexture));
_view.scene.addChild(cube);
}
}
}
}
- 优化代码 :
package flash3dbook.ch10
{
import away3d.core.utils.*;
import away3d.materials.*;
import away3d.primitives.*;
[SWF(width="800", height="600")]
public class BitmapInstanceTest extends Chapter10SampleBase
{
[Embed(source="../../assets/ch10/cubetexture.jpg")]
private var CubeTexture : Class;
public function BitmapInstanceTest()
{
super();
}
protected override function _createScene() : void
{
var material : BitmapMaterial = new BitmapMaterial(Cast.bitmap(CubeTexture));
// create 50 cubes
for (var i : int = 0; i < 50; i++) {
var cube : Cube = new Cube();
// assign a random position to the cube
cube.x = (Math.random()-.5)*1000;
cube.y = (Math.random()-.5)*1000;
cube.z = (Math.random()-.5)*1000;
// assign the same bitmap material to the cube
cube.material = material;
_view.scene.addChild(cube);
}
}
}
}
4.2 优化内存消耗操作步骤
graph LR
A[创建多个使用相同纹理的对象] --> B{是否使用新的材质实例}
B --> C{是}
B --> D{否}
C --> E[创建新的材质实例,内存消耗高]
D --> F[重用同一个材质实例,内存消耗低]
5. 切换 3D 坐标系统
在 Away3D 中,每个对象都有自己的局部坐标系,它通过将其父容器的变换与自身的变换相结合来工作。在表达空间中某一点的向量位置时,有五种主要类型的坐标系需要考虑:
-
对象空间(Object space)
:3D 对象(如网格)的局部坐标系,相当于 Flash 中本地 DisplayObject 的坐标系。网格内顶点的位置向量以对象空间表示。
-
父空间(Parent space)
:3D 对象相对于其父容器的坐标系,相当于应用局部坐标系变换后网格内顶点的坐标。容器内对象的位置向量以父空间表示。
-
场景空间(Scene space 或 World space)
:场景的全局坐标系,相当于 Flash 中本地 Stage 对象的坐标系。在场景空间中描述 3D 对象类似于将本地 DisplayObject 的坐标从局部转换为全局坐标。
-
相机空间(Camera space 或 View space)
:3D 对象相对于相机的场景空间。将相机对象的逆变换应用于对象在场景空间中的表示,得到相机所看到的对象的位置和变换。
-
屏幕空间(Screen space)
:场景内容被投影并绘制到的坐标系。将相机镜头对象的投影变换应用于 3D 对象在相机空间中的表示,得到对象投影到屏幕后的位置和变换。
5.1 不同坐标系的特点
| 坐标系类型 | 定义 | 示例 |
|---|---|---|
| 对象空间 | 3D 对象的局部坐标系 | 网格内顶点的位置向量 |
| 父空间 | 3D 对象相对于其父容器的坐标系 | 容器内对象的位置向量 |
| 场景空间 | 场景的全局坐标系 | 3D 对象在场景中的位置 |
| 相机空间 | 3D 对象相对于相机的场景空间 | 相机所看到的对象的位置和变换 |
| 屏幕空间 | 场景内容被投影并绘制到的坐标系 | 对象投影到屏幕后的位置和变换 |
5.2 示例代码
package flash3dbook.ch10
{
import away3d.containers.*;
import away3d.core.draw.*;
import away3d.core.math.*;
import away3d.materials.*;
import away3d.primitives.*;
import flash.display.*;
import flash.events.*;
[SWF(width="800", height="600")]
public class TransformTest extends Chapter10SampleBase
{
private var _plane : Plane;
private var _planeContainer : ObjectContainer3D;
private var _cube : Cube;
private var _cubeContainer : ObjectContainer3D;
private var _marker : Sphere;
private var _shape : Shape;
public function TransformTest()
{
super();
}
protected override function _createScene() : void
{
_plane = new Plane();
_plane.segmentsW = 10;
_plane.segmentsH = 10;
_plane.material = new WireColorMaterial(0x808080);
_plane.width = 200;
_plane.height = 200;
_plane.bothsides = true;
_plane.yUp = false;
_plane.position = new Number3D(-200, 0, 0);
_planeContainer = new ObjectContainer3D(new Trident(100, true));
_planeContainer.x = -200;
_planeContainer.addChild(_plane);
_view.scene.addChild(_planeContainer);
_cube = new Cube();
_cube.material = new WireColorMaterial(0xFFFFFF);
_cube.pivotPoint = new Number3D(200, 0, 0);
_cubeContainer = new ObjectContainer3D(new Trident(100, true));
}
protected override function _onEnterFrame(event : Event) : void
{
super._onEnterFrame(event);
}
}
}
5.3 切换坐标系操作步骤
graph LR
A[确定需要表达的点的位置] --> B{选择坐标系类型}
B --> C{对象空间}
B --> D{父空间}
B --> E{场景空间}
B --> F{相机空间}
B --> G{屏幕空间}
C --> H[使用对象的局部坐标系]
D --> I[考虑父容器的变换]
E --> J[转换为全局坐标系]
F --> K[应用相机的逆变换]
G --> L[应用相机的投影变换]
通过以上优化技巧和方法,可以提高 Away3D 项目的性能,减少内存消耗,并更好地控制场景的着色和坐标系统。希望这些内容对你有所帮助!
6. 利用框架提取空间数据
在 Away3D 里,支撑 3D 坐标系统计算的框架有很多实用属性,我们可以利用这个框架从场景中提取有用的空间数据。
6.1 不同坐标系的转换
不同的坐标系之间可以进行转换,以满足不同的需求。以下是常见的转换关系:
| 转换类型 | 描述 |
| ---- | ---- |
| 对象空间到父空间 | 应用对象自身的变换 |
| 父空间到场景空间 | 逐级应用父容器的变换 |
| 场景空间到相机空间 | 应用相机的逆变换 |
| 相机空间到屏幕空间 | 应用相机的投影变换 |
6.2 转换操作步骤
graph LR
A[选择起始坐标系] --> B{对象空间}
A --> C{父空间}
A --> D{场景空间}
A --> E{相机空间}
B --> F[转换到父空间]
C --> G[转换到场景空间]
D --> H[转换到相机空间]
E --> I[转换到屏幕空间]
F --> G
G --> H
H --> I
6.3 示例代码
// 假设我们有一个对象 _object 在对象空间
// 将其位置转换到场景空间
var positionInSceneSpace:Number3D = _object.localToGlobal(_object.position);
// 将场景空间的点转换到相机空间
var positionInCameraSpace:Number3D = _camera.globalToLocal(positionInSceneSpace);
// 将相机空间的点转换到屏幕空间
var positionInScreenSpace:Number3D = _camera.project(positionInCameraSpace);
7. 优化渲染流程
除了上述的优化方法,还可以从渲染流程的角度进行优化,以提高 Away3D 项目的性能。
7.1 减少不必要的渲染
在 Away3D 中,有些对象可能在某些情况下不需要渲染,我们可以通过判断来避免不必要的渲染操作。
// 假设我们有一个对象 _object
if (_object.visible && _object.isInFrustum(_camera)) {
// 进行渲染操作
_view.render();
}
7.2 批量渲染
将多个对象合并为一个批次进行渲染,可以减少渲染调用的次数,提高性能。
// 假设我们有多个 Cube 对象
var cubes:Array = [];
for (var i:uint = 0; i < 10; i++) {
var cube:Cube = new Cube();
cubes.push(cube);
_view.scene.addChild(cube);
}
// 创建一个批次
var batch:MeshBatch = new MeshBatch(cubes);
_view.scene.addChild(batch);
7.3 渲染优化操作步骤
graph LR
A[开始渲染] --> B{对象是否可见且在视锥体中}
B --> C{是}
B --> D{否}
C --> E[判断是否可以批量渲染]
E --> F{是}
E --> G{否}
F --> H[进行批量渲染]
G --> I[单独渲染对象]
D --> J[跳过渲染]
8. 总结
通过对 Away3D 项目的材质、着色、坐标系统和渲染流程等方面进行优化,可以显著提高项目的性能,减少内存消耗。以下是一些关键的优化点总结:
1.
材质优化
:避免过度使用复杂材质,合理选择材质类型,优化材质参数,重用材质实例。
2.
着色优化
:使用静态着色(纹理烘焙和表面缓存),利用
NormalMapGenerator
类生成法线贴图。
3.
坐标系统
:了解不同坐标系的特点和转换方法,利用框架提取空间数据。
4.
渲染流程
:减少不必要的渲染,进行批量渲染。
希望这些优化技巧和方法能帮助你在 Away3D 项目中取得更好的效果,创造出更加出色的 3D 场景。
8.1 优化要点列表
-
材质方面:
- 避免复杂材质的过度使用。
- 重用位图材质实例。
-
着色方面:
- 采用静态着色技术。
-
利用
NormalMapGenerator生成法线贴图。
-
坐标系统方面:
- 掌握不同坐标系的转换。
- 利用框架提取空间数据。
-
渲染流程方面:
- 减少不必要的渲染。
- 进行批量渲染。
通过综合运用这些优化方法,你可以让 Away3D 项目在性能和效果上达到更好的平衡。
超级会员免费看
45

被折叠的 条评论
为什么被折叠?



