定位瓶颈

Gamebryo3.0SDK翻译-Progrmming 相关专题

Progrmming 相关专题

一、 基本知识

1. 类的继承结构

clip_image002

clip_image004

2. 对象系统

使用了RTTI、智能指针、流操作等

3. 静态对象和对象的生命期

4. 命名相关

5. 模板类:Lists、Array、Map等…………….

6. Unicode

GB支持UTC-2和Ascii,而不支持UNICODE和_UNICODE

二、 场景图

1. 变换和坐标系

世界坐标系(World coordinate system):

模型坐标系(Model coordinate system):从根节点到物体的所有变换的集合

局部坐标系(Local coordinate system):相对于父节点的变换

GB使用的是右手坐标系,NiMatrix3是顺时针的,NiQuaterninon是逆时针

2. NIAVObject的子类:

场景图中所有物体都继承于NIAVObject,主要有以下集中类型的物体

NiAVObject 
NiCamera 
NiDynamicEffect 
NiLight 
NiAmbientLight 
NiDirectionalLight 
NiPointLight 
NiSpotLight 
NiTextureEffect 
NiRenderObject

NiMesh 
NiPSParticleSystem 
NiNode 
NiBillboardNode 
NiBSPNode 
NiSortAdjustNode 
NiSwitchNode 
NiLODNode

3. 类的描述

NiDynamicEffect

主要包括:顶点光照,基本纹理特效。

NiDynamicEffectList:包含了一组受特效影响的对象。

4. 更行场景图

它沿子图进行深度优先访问,计算世界变换矩阵和包围球,因子最小化可视节点的数量。在更新完矩阵之后。沿着递归调用返回,更新世界包围球。总的来说,递归一个路径时变换操作被更新,而返回时包围球被更新。

在场景图的数据处理初始化中,当应用程序使用到场景图前,至少要对场景图的根节点进行一次例行update,这样保证所有节点的世界信息及本地信息都是最新的。

注意任何在父节点或者祖节点的Update调用,可以代替对象自己的Update调用。注意在场景图中Update应该尽量少调用。仅仅因为一个叶节点变化每帧都在场景图上调用Update将会降低性能。

5. 网格数据共享

clip_image006

6. 修改网格数据(Morphing Mesh Data)

除了使用动画变换,修改渲染器属性,这里的Morphing主要指实时修改形状、颜色、纹理等。可以使用NiMorphMeshModifer来实现每一帧修改Mesh的局部坐标。要每一帧修改Mesh的数据,此时数据流的访问标识应该设为:NiDataStream::CPU_WRITE_VOLATILE。

三、 场景渲染

纵观渲染场景主要包括如下内容:

A.确保场景中的对象被正确的更新

B.建立摄像机可视范围

C.决定场景中的那些在摄像机的可视范围内

D.清除输出设备

E.绘制场景中的可见对象到输出设备中

F.显示结果。

clip_image008

白色框:数据对象

棕色框:处理对象

The actual set of steps that must be taken to render a frame to the screen is slightly more involved than the high-level discussion or dataflow implied, as there are additional steps required to inform the renderer of the target and mark the beginning and end of rendering. The linked pages below will describe the basic functionality used to render common scenes, and then discuss advanced forms of each rendering step.

处理逻辑

1. 渲染前准备

2. 定义View

3. Collect Visible Objects

4. Begin the Current Frame

5. Open the Render Target

6. Pass the View to the Renderer

7. Sort and Render the NiRenderObject objects

8. Close the Render Target

1. 初始化渲染场景

更新场景的变换矩阵:Update

更新场景的渲染状态(一系列属性):Update Properties

更新场景的特效状态(一系列光照和纹理特效):Update Effcts

注:这些更新不是每一帧都进行的,而是对象相关属性改变时,会对进行相应的更新。

2. 渲染属性

节点的渲染属性会影响所有子节点。NiProperty可以被多个对象共享,每个对象包含一个NiPropertyState对象,它包含了所有该对象的渲染属性。

属性更新的条件:

A. 场景的根节点初始化

B. 节点上添加或删除相关属性

C. 节点上添加父亲或子节点。

3. Viewing Meshes

clip_image010

Vmw:摄像机的世界变换;Gmw:几何体的世界变换

两种摄像机:程序添加,美术添加

基于程序驱动摄像机(Application-driven)没有挂到场景中,而是手动设置它的世界变换,以及更新。

4. Cameras

相机坐标系:

A:相机位置为坐标系原点

B:X正方向为观察方向

C:Y正方向为屏幕的上方

D:Z正方向为屏幕的右方

GB支持两种投影模式:正交、透视

5. Culling

渲染只会正对于场景中的叶子节点。

NiCullingProcess类+场景图+摄像机+可见集合=完成场景裁剪工作,即生成一个渲染列表,包含了送到渲染器绘制的所有对象。

NiDrawScene:完成Cullingy生成可见物体集合,再绘制集合里的物体

也可以通过NiCullingProcess、NiVisiableArray再结合NiDrawScene来完成上述

涉及的物体:

A源物体:就是被处理的对象,包括场景图(场景根节点)和NiCamera

B处理工具:NiCullingProcess

C目标物体:NiVisiableArray

NiVisibleArray:是一个存放可见物体的容器,由NiCullingProcess产生这些物体,再对这些可见物体进行排序和渲染

NiCullingProcess:用来进行Culling处理

6. 使用帧

for each rendered frame

{

CreateFrame

DisplayFrame

}

过程:创建帧(BegainFrame--à相关处理àEndFrame-)à渲染帧(DisplayFrame)。

可以常见多个帧,如实现多窗口显示。DisplayFrame可以绘制多个Displayable buffer。

Gamebryo支持离屏渲染(BeginOffScreenFrame and EndOffScreenFrame),不能对其使用DisplayFrame。

可以使用NiRenderer::GetFrameState来追踪当期帧的状态。

7. 使用渲染目标组

NiRenderTargetGroup:封装了一个color buffers、depth buffer,stencil buffer(根据需要是否添加)

GB支持的RenderTareget:Buffer、Texture、Cubemap

l Rendering Meshes

l Object Sorting

8. 排序

9. 使用绘制函数

NiDrawScene:完成Culling、排序、绘制工作

NiDrawVisibleArray:

NiDrawVisibleArrayAppend:

10. 屏幕空间的的绘制

渲染对象:NiMeshScreenElements,它是屏幕空间的NiMesh对象,支持多边形列表,shaders,渲染状态,光照和动态变换,因为它是NiMesh的子类。

NiMeshScreenElemments对象使用完成的几何管线,在绘制之前必设置屏幕空间相机(NiRenderer::SetScreenSpaceCameraData)从而绘制完所有屏幕对象后重新设置3D空间的相机参数。

屏幕空间坐标系:2D空间坐标系组成了左手坐标系。所以在进行背面剔除时要和3D空间相反。Z值可以取0-9999。

可以把场景渲染到一张离屏纹理上,在把这个纹理添加到一个屏幕Mesh中,在进行shader处理,从而产生很多特效。

应用程序需要建立一个链表来管理这些屏幕空间的渲染对象。

NiMeshScreenElements:由许多多边形组成,这些多边形构成了屏幕中所有2D元素。

多变边型,在NiMeshScreenElements中使用handles来标识。

四、

四、 改网格数据:特效

1. Dynamic Effets介绍

Scope:代表了特效所影响的范围,一个场景节点列表。处于该列表的对象都会受该特效影响。可以使用AttachAffectedNode向特效注册新的节点(包含它的所有子节点)。

2. 光照特效

3. 光照子类

环境光影响因素:环境光的环境光颜色、光源的调光器(dimmer)、材质的环境光颜色

4. 漫反射光照方程

clip_image012

clip_image014

5. 顶点颜色和光照方程

顶点颜色属性(NiVertexColorProperty)包含两个控制部分:

顶点颜色控制:

l SOURCE_IGNORE:忽略顶点颜色,使用材质代替((i.e. VE=ME, VA=MA, VD=MD

l SOURCE_EMISSIVE:使用顶点的颜色代替材质的自发光颜色(i.e. VE=ME, VA=VC, VD=VC

l SOURCE_AMB_DIFF:使用顶点颜色代替材质的环境光、漫反射颜色(.e. VE=ME, VA=VC, VD=VC

光照控制:决定了光照方程的那一部分决定最终顶点颜色。

l LIGHTING_E:仅仅使用光照方程终的自发光

l LIGHTING_E_A_D:使用光照方程的自发光、环境光、漫反射光。

6. 镜面高光

开启镜面高光的条件:

l 确保漫反射光照开启(设置NiVertexColorProperty设置为LIGHTING_E_A_D)

l 向节点添加NiSpecularProperty属性。

l 设置材质的Specular颜色不能为零。

l 至少有一个光源的Specular颜色不为零。

7. 光照效率

l 光照计算的消耗(高->低):环境光源、方向光源、点光源、聚光源。

l 使用点、聚光源时可以设置二次、常量参数为零、而线性参数不为零。从而加速计算。

l 尽量在少数光源里设置镜面高光。因为镜面高光的计算很费。

l 可以使用GB标准(NiStandarMaterial)才是来设置光照的方式:逐顶点、逐像素计算。

l 可以不使用动态光照,而使用光照纹理代替

l 如果应用程序不需要顶点颜色,则不需要添加顶点颜色,这样可以忽略该部分的计算。

8. 纹理特效

NiTextureEffect实现投影多纹理。从额可以实现各种复杂的聚光灯、光柱、反射面、投影阴影等。

(1)纹理特效类型:定义了影响对象(scope list中的)纹理的的方式。

PROJECTED_LIGHT:

PROJECTED_SHADOW:

ENVIRONOMENT_MAP:

FOG_MAP:

(2)纹理坐标的生成

五、 导入和导出

创建NIF文件

使用max或maya插件导出、程序写文件

加载NIF文件

使用NiStream类完成加载功能

GB支持后台加载

NIF文件的输入、输出原理

六、 其它模块

音效系统

入口系统

碰撞检测系统

主要是针对bounding spheres、alternate bounding volumes、oriented bounding boxes、trangle-triangle之间的碰撞检测

七、 优化

1. 加速几何体的更新

几何体的类型:

Frequency of movement

Geometry that moves every frame

Geometry that moves only in special situations

Geometry that never moves.

Type of motion

Completely independent motion of objects in a subtree

Motion of an entire subtree as a single, rigid body

首先对整个场景中的对象进行分类,使用UpdateSelected代替Update从而使得该对象及其孩子忽略此次更新处理,只进行世界包围盒的更新。

降低NiMaterialInstance的更新

2. 加速纹理的加载

提高加载纹理的速度:存储纹理以platform-specilc texures形式存放到NIF文件中。

3. 优化

(1) 定位瓶颈

A: 使用工具

Frame Rate-NiFrameRate

High Performance Counters-NiGetPerformanceCounter

NiMetrics

Low level Profiling

B:间断性和持续性的低效

(2) 追踪低效

瓶颈的主要分为以下几部分:

l 应用程序逻辑

l 引擎的更新

l 渲染

l 交换缓冲区

(3) 应用程序逻辑

(4) 引擎的更新

更新包括:世界变换的更新、时间控制器的更新、对象包围盒的更新。

A:由于更新操作比较消耗,所以只在需要更新时才去更新。

B:可以把场景分为静态和动态两部分,静态部分只更新一次,动态部分只在需要时更新。

C:使用UpdateSelected。

D:剔除不需要的节点。

E:使用线性动画关键帧。

F:减少骨骼数-使用Bone Lod

(5) 渲染

A:合并相似的对象—共享属性和特效的。

B:减少角色的骨骼数。

C:尽量把任务提交给GPU

使用顶点shader处理大量的骨骼替代传统的硬件硬件蒙皮。

(6) 缓冲区交换-SwapeBuffer

使用SwapeBuffer的数据,必须等待GPU完成绘制管线中的所有数据。

A、GPU组成部分:数据总线、顶点处理单元、像素处理单元

B、总线瓶颈

C、顶点处理单元瓶颈

D、像素处理单元瓶颈

E、NVPerfHUD

(7) 处理间断型

A、看是否是摄像机相关的

B、游戏对象相关

(8) 更低级别处理

使用工具:Sampling Profilers、Intel VTune、AMD CodeAnalyst。

使用系统计数器

使用DX PIX

4. UpdateSeleted

该函数把对象的所有子节点看做一个,只更新world bound信息。

(1)概述

在使用UpdateSelected是必须注意:

A:设置正确的Flags-SetSelectedUpdateFlags。

B:在调用UpdateSelected之前必须确保调用Update和UpdateNodeBound一次。通常在程序开始时。

(2)行为

clip_image016

(3)Bound更新

SelectiveUpdateRigid

True:UpdateSelected的行为和Update一样去计算世界包围盒,并且合并孩子的世界包围盒。当子节点包含动画变换时,几点的包围盒必须合并此时使用该标识。

False:UpdateSelected通过本地包围盒乘上该节点的世界变换,从而计算出世界包围盒。当子节点不包含动画变换时,使用该标志。

(4)例子

八、 内存策略

1. 分配策略

Efd::MemManager设计成黑盒

2. 存储管理

3. 平台相关的纹理存储优化

4. 纹理的存储管理

九、 Skinned对象

十、 多线程

1. 效率影响线程安全

并行操作:假如,在多核处理器中,两个线程同时对引用计数(初始为0)进行增加,此时引用计数为1,但正确的结果应该是2。解决该类问题的方法:确保访问和增加引用计数的操作是一个原子操作,使用critical section或thinner从而实现线程同步。

二次操作:假如,在单核处理器中,第一个线程获的了操作智能指针的权,但引用计数没有增加,此时返回。此时执行第二个线程释放了该资源。这是第一个现在重新获取引用计数进行操作会出现错误。

分析:对没一个操作进行同步操作,会大大增加程序的复杂度。解决办法:对每个类添加同步功能,使其负责所有成员函数的同步处理.

优先权转置: 由于一个低优先权的线程拥有某个资源而阻止了高优先权的线程执行的情况.

2. 同样多线程

调用NiSleep:当使用单核处理时,可以调用NiSleep来休眠当前线程,而执行优先权更低的线程.当然,使用多核时可以直接把两个优先权不同的线程放到不同核上执行.

避免同时访问:场景图尽量避免多线程处理.

3. 后台加载

4. 线程和纹理

5. 线程和指针

6. 线程和渲染器

分类:  文档翻译
0
0
(请您对文章做出评价)

posted on 2011-02-27 13:45 arun 阅读(82) 评论(0)  编辑 收藏

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值