NiGeometryData::STATIC |
The data never changes. |
NiGeometryData::MUTABLE |
The data changes infrequently. |
NiGeometryData::VOLATILE |
The data changes every frame. |
BackgroundLoad Demo Code Overview
The following NiStream functions are used to perform the background load in this sample:
如下的NiStream 函数展示了如何进行后台加载:
void NiStream::BackgroundLoadBegin(const char* pcFileName);
BackgroundLoadBegin is used to launch the background load.
BackgroundLoadBegin 用来启动后台加载。
NiStream::ThreadStatus NiStream::BackgroundLoadPoll(LoadState* pkState);
BackgroundLoadPoll is used to poll the status of the background load. It returns NiStream::IDLE when the background load has finished. It returns NiStream::LOADING while the background load is in progress. If a non-NULL pointer is passed as the pkState argument to BackgroundLoadPoll and BackgroundLoadPoll returns NiStream::LOADING, the structure pointed to by pkState is filled in with values that indicate the progress of the background load. These values are used in this sample to calculate the values displayed on the screen that indicate the progress of the background load.
BackgroundLoadPoll 用来查询后台加载的情况. 当后台加载完成的时候返回NiStream::IDLE。当后台加载还在进行的时候返回NiStream::LOADING 如果一个非NULL的pkState参数传入BackgroundLoadPoll 并且BackgroundLoadPoll 返回NiStream::LOADING, pkState指向的结构被填充后台加载进度的值。
bool NiStream::BackgroundLoadGetExitStatus() const;
After BackgroundLoadPoll indicates that the background load has finished, BackgroundLoadGetExitStatus is used to determine whether the background load succeeded. It returns true if the load succeeded and false if it failed.
在BackgroundLoadPoll指示后台加载已经完成。BackgroundLoadExitStatus 用来决定后台加载是否成功,true 代表加载成功,false 表示失败.
加载结束后BackgroundLoadOnExit 函数被调用可以在里面确定是否加载成功. assert(BackgroundLoadGetExitStatus());
bool NiStream::BackgroundLoadFinish();
BackgroundLoadFinish blocks until a background load runs to completion. In this sample, we call it before allowing the application to exit. If the user quits the application before the background load finishes, calling BackgroundLoadFinish is necessary. It is an error to destroy an NiStream object while a background load is in progress. If the background load has already finished before BackgroundLoadFinish is called, BackgroundLoadFinish will return immediately.
BackgroundLoadFinish 用来阻塞直到后台加载完成。我们可以在应用程序退出前调用这个函数。如果用户在后台加载完成前退出应用程序,调用BackgroundLoadFinish 是必须的。在后台加载正在进行的时候摧毁 NiStream 对象是错误的行为。当后台加载完成时。BackgroundLoadFinish 将马上返回。
On most platforms, a background load will not receive any cycles unless the foreground thread yields the processor by calling NiSleep, a global function declared in NiSystem.h:
在大部分平台 ,后台加载线程不会执行除非前台线程通过调用NiSleep让出处理器,在NiSystem.h 中有一个全局函数NiSleep
void NiSleep(unsigned int uiMilliseconds);
NiSleep puts the calling thread to sleep for the number of milliseconds specified by its uiMilliseconds argument. If a background load has been launched, it will wake up and run while the foreground thread is asleep.
The BackgroundLoad sample loads its NIF files using an NiStream-derived class called CallbackStream. CallbackStream overloads the virtual NiStream function BackgroundLoadOnExit. BackgroundLoadOnExit is called by the background loading code in NiStream when a background load completes. The default implementation, NiStream::BackgroundLoadOnExit, does nothing. The purpose of the function is to allow applications to override it in classes derived from NiStream and do work that should be done in the background thread to avoid frame rate hits that would happen if the work was done in the application's main thread. CallbackStream::BackgroundLoadOnExit creates property states and effect states for the objects extracted from ROOM.NIF and precaches the geometry objects.
unsigned int AddGraph(GraphCallbackObject* pkObject, const char* pcName, const NiColor& kColor, unsigned int uiNumSamplesToKeep, float fMinSampleTime, bool bShow);
This adds a GraphCalbackObject to the list of graphs maintained by the NiVisualTracker. A GraphCalbackObject is the class that maintains the current state of a tracked statistic. pcName is the name of the object as it is to be displayed below the graph. kColor is the color for both the lines drawn and the displayed name. uiNumSamplesToKeep is the number of samples to keep in the history for that statistic. fMinSampleTime is the minimum time that must elapse between samples. bShow is the initial show/hide status for that particular graph.
向NiVisualTracker维护的图形列表添加一个GraphCallbackObject对象。一个GraphCallbackObject 负责维护tracked当前状态的统计信息。pcName 是在图形列表下面显示的曲线图名称。kColor 是统计曲线和显示名称使用的颜色。uiNumSamplesTokeep 统计保存的历史数据包含的采样个数。fMinSampleTime 在2次采样之间流逝的时间。bShow 初始化某个曲线图的显示/隐藏状态。
NiVisualTrackerOutput
This class is a metrics output module designed for easily adding instrumented metrics to an NiVisualTracker graph.
为简化向NiVisualTracker图添加测量工具
//构造函数
NiVisualTrackerOutput(unsigned int uiFramePeriod)
Constructs a visual tracker with the specified frame period. The frame period is how many frames each metric will be calculated for before being displayed to the tracker. This number must be greater than zero.
创建一个执行周期为uiFramePeriod的visual tracker. 这个周期指每次测量之间的帧数。这个数必须大于0
//添加曲线图函数
void AddGraph(NiVisualTracker* pkTracker, const char* pcMetricName, MetricsFunction eFunction = FUNC_MEAN, const NiColor& kColor = NiColor::WHITE, unsigned int uiNumSamplesToKeep = 100, float fMinSampleTime = 0.1f, bool bShow = true, float fScale = 1.0f, bool bAddFunctionSuffix = true, const char* pcAlternateName = NULL)
This function adds a metric by name to an existing visual tracker. eFunction is an enumeration (defined in NiCalculatingOutput) that defines which function of the metric should be graphed (mean, sum, min, max, or count.) kColor, uiNumSamplesToKeep, fMinSampleTime, bShow, and fScale are all passed directly to the NiVisualTracker::AddGraph function.
通过测量名称(如NiApplicationMetrics::ms_acNames[NiApplicationMetrics::FRAMERATE] 存储的帧速率的名称)为一个存在的visual tracker 添加测量信息, eFunction 是在NiCalculatingOutput中的一个枚举,定义采用那个函数处理数据(mean,sum,min,max.count 平均值、总和、最大值、最小值、计数,指一个uiFramePeriod 周期内数据)。
NIMETRICS_ADDVALUE(ms_pcMetricName, 100 * NiUnitRandom()); 添加某个测量名称对应的测量数据
//例子
NiVisualTrackerOutput* pkVTOutput = NiNew NiVisualTrackerOutput(uiVTFramePeriod);
NiMetricsLayer::AddOutputModule(pkVTOutput);
pkVTOutput->AddGraph(m_kTrackers.GetAt(0), NiParticleMetrics::ms_acNames[NiParticleMetrics::UPDATED_PARTICLES],
NiVisualTrackerOutput::FUNC_SUM_PER_FRAME, NiColor(0.0f, 1.0f, 0.0f),100, 0.1f, true, 1.0f, false, "Particles");
使用xml记录数据
const char* pcFilename = "ProfileSampleXMLOutput.xml";
// Add XML output module to metrics layer
NiXMLMetricsOutput* pkXML = NiNew NiXMLMetricsOutput(uiFramePeriod, pcFilename);
NiMetricsLayer::AddOutputModule(pkXML);
NiXMLMetricsOutput
This class calculates instrumented metrics over some user-specified number of frames. It will calculate the mean, sum, min, max, and count for each metric and output them in an XML file. (Count is the number of values that were used to calculate the other four values.)
OM®W = PM®W [ OT OR OS ] //由模型空间变换到世界坐标系的矩阵表示
where:
PM®W |
is the parent object's model to world space transform |
OT |
is O's translation matrix (which is a pure translation matrix) |
OR |
is O's rotation matrix (which is a pure rotation matrix - i.e. orthonormal) |
OS |
is O's scaling matrix (which is a pure uniform scaling matrix) |
vL = [ OT OR OS ] vM
Scene Graph Hierarchy and Hierarchical Coordinate Systems
In order to render an object in world space, it is necessary to transform into additional coordinate systems. For more information on this, including the camera's coordinate system, please see Viewing Geometry.
NiCamera
NiCamera objects represent virtual cameras for imaging the geometry represented by a scene graph. It is important to note that NiCamera is a descendant of NiAVObject. As a result, a camera may have a parent object that affects the camera's position and orientation. This approach enables cameras to be attached as children of objects in the scene, in order to follow them automatically, as they move. The camera object may operate on a portion of the scene graph that is an ancestor of itself.
NiDynamicEffect
The subclasses of the abstract class NiDynamicEffect represent time- and geometry-dependent visual effects, such as per-vertex lighting, texture-based fogging, shadows, projected images, etc. These effects fall into two major categories: per-vertex lights and texture-based effects.
NiDynamicEffect is a subclass of NiAVObject, so objects of this type have a concept of a model space coordinate system. The positions and directions of subclassed effects are defined in the object's model coordinate system, so effects may be attached as children of other scene graph objects. This approach enables the effects to be attached to characters or objects in the scene, such as headlights being attached to a car.
NiLight
NiTextureEffect
NiGeometry
NiLines
NiTriBasedGeom
NiParticles
During frame-to-frame application runtime, applications must call Update on an object "O" if any of the following criteria are met:
O is attached to or detached from a parent (direct parent only – not a "grandparent", etc)
O has a new child attached or a current child detached (direct children only – not "grandchildren", etc)
Any of O's transforms are changed
Names
void SetName(const NiFixedString& kName);
const NiFixedString& GetName() const;
SetName increments the reference to kName.
NiAVObject* GetObjectByName(const NiFixedString& kName);
模板类
Gamebryo提供了一序列基本的模版容器类。在Gamebryo内部这些容器类在库的内部普遍使用。这些基本的容器类在下面描述;特们的特定用处和成员函数将在后面的章节中描述。
列表
NiTPointerList对象用来可以用来容纳和管理指针、智能指针或者其他等于指针类型大小或更小的元素。这个类允许在任意的位置有效地插入或删除元素,以及有效地前向和后向迭代所有元素。这个类也可用来查找给定值的元素的存在和位置。NiTPointerList的项从共享内存池中按块分配,这使得这个类快速和内存高效。NiTList已经不赞成使用,应用程序应该使用NiTPointerList代替。对于大小大于指针大小的对象,可以使用NiTObjectList。
映射
NiTPointMap对象实现哈希表(也叫“字典”)的功能,允许任意类的键映射到一个指针、智能指针或者其他等于指针类型大小或更小的元素。它们能够进行键/值对的快速存储和查找。不要使用它来作为字符串键的哈希表,对于这样的哈希表请使用专门为之设计的NiTStringPointerMap对象。NiTPointerMap和NiTStringPointerMap的项从共享内存池中按块分配,这使得这些类快速和高效。对于大小大于指针大小的对象可以使用NiTMap和NiTStringMap。
Type |
Prefix |
Example |
character |
c |
char cVariable; |
short |
s |
short sVariable; |
integer |
i |
int iVariable; |
long |
l |
long lVariable; |
unsigned character |
uc |
unsigned char ucVariable; |
unsigned short |
us |
unsigned short usVariable; |
unsigned integer |
ui |
unsigned int uiVariable; |
unsigned long |
ul |
unsigned long ulVariable; |
enumeration |
e |
NiFogProperty::FogFunction eFunction; |
float |
f |
float fVariable; |
double |
d |
double dVariable; |
class, struct |
k |
NiPoint3 kVariable; |
array |
a |
unsigned int auiVariable[2]; |
pointer |
p |
float* pfVariable; |
pointer to pointer |
pp |
float** ppfVariable; |
pointer to void |
pv |
void* pvVariable; |
pointer to function |
pfn |
int (*pfnVariable)(); |
size_t |
st |
size_t stVariable; |
ptrdiff_t |
dt |
ptrdiff_t dtVariable; |
NiInt32 |
i32 |
NiInt32 i32Variable; |
NiUInt32 |
ui32 |
NiUInt32 ui32Variable; |
NiInt64 |
i64 |
NiInt64 i64Variable; |
NiUInt64 |
ui64 |
NiUInt64 ui64Variable; |
指向类指针 pk,智能指针 sp
NiAlloc, NiMalloc, NiFree, NiRealloc, NiAlignedMalloc...
Gamebryo direct allocation routines are used for intrinsic types (floats, ints, chars, etc) and types that do not need constructors or destructors. Much like malloc, free, and realloc, these routines simply allocate the memory that you requested. They perform no initialization of that memory. Calls to NiMalloc and NiRealloc must be paired with calls to NiFree for deallocation to occur properly. Similarly, calls to NiAlignedMalloc and NiAlignedRealloc must be paired with calls to NiAlignedFree for deallocation to occur properly.
Gamebryo
If an application does not use these allocation routines, the memory will not be tracked or managed by Gamebryo. This can cause a mismatch if the memory was allocated externally and then freed by Gamebryo routines. Please see Memory Management Troubleshooting for more details on common memory management issues.
The routines NiAlloc, NiMalloc, NiFree, etc are actually macros that call internal versions of these functions. The macro allows the engine to generate file, line, function information automatically in memory tracking builds.
NiMemObject, NiNew, and NiDelete
Objects requiring constructors and destructors in Gamebryo are allocated using NiNew and NiDelete and must be derived from a common base class, NiMemObject. These macros, like NiAlloc, NiFree, and others listed above encapsulate the need to store the file, line, and function information for memory tracking.
NiMemObject overrides the global new and delete on a class level. All derived classes will inherit these allocation overrides. Note that inheriting from NiMemObject requires no additional per-object memory overhead. Additionally, NiMemObject overrides new[] and delete[] on a class level. The only overhead for array allocations is a few bytes that the compiler generates in order to call the destructor for each element in the array. Most objects will have this data generated automatically, so the overhead should not be a concern.
The NiDevImageConverter supports the following formats for ReadImageFileInfo and ReadImageFile:
Windows BMP – see the NiBMPReader documentation for details.
Gamebryo NIF – see the NiNIFImageReader documentation for details.
SGI's INT, INTA, RGB, RGBA – see the NiSGIReader documentation for details.
Truevision Targa TGA – see the NiTGAReader documentation for details.
DirectX Compressed Textures, DDS – see the NiDDSReader documentation for details. Note that this format is Win32-specific.
The NiDevImageConverter functions ConvertPixelData and ConvertPixelDataFormat are capable of converting among the following formats. Note that PAL8, PALA8, RGB24, RGBA32, BUMP16, BUMPLUMA32, all refer to the NiPixelFormat-scoped standard format static objects of the same name, and DXT1, DXT3, DXT5 refer to the compressed formats:
Source Formats |
Valid Destination Formats |
RGB24, RGBA32 |
Any 16 or 32-bit RGB, RGBA, BUMP, or BUMPLUMA format RGB24 or 24-bit BGR (in that order) |
PAL8, PALA8 |
PALA8, PAL8 Any 16 or 32-bit RGB or RGBA format RGB24 or 24-bit BGR (in that order) |
BUMP16, BUMPLUMA32 |
Any 16 or 32-bit BUMP or BUMPLUMA format |
DXT1, DXT3, DXT5 |
Any 16 or 32-bit RGB or RGBA format RGB24 or 24-bit BGR (in that order) |
Any 16 or 32-bit RGB or RGBA format |
RGB24, RGBA32 |
24-bit BGR (in that order) |
RGB24, RGBA32 |
gamebryo 标准像素格式见:
NiPixelFormat 文档
Gamebryo Update Slowdowns
The Update function in Gamebryo performs a variety of tasks and is often a source of slowdown for developers. Understanding what Update does can help you optimize around some of the more expensive operations. This document outlines some of the things you can do to speed up Update.
GameBryo 中的 Update执行各种任务对于开发者来说通常是效率低下的原因,理解Update做什么有利于优化昂贵的操作。
What does Update do?
At it's core, Update prepares the scene graph for rendering. However, Update performs several operations during this process such as updating the transforms on NiAVObject based classes, updating NiTimeController objects and updating the bounds on objects. Because of this, Update can become a very expensive function call and should be used only where necessary. Listed below are several ways to optimize calls to Update.
Update 做什么
作为核心,Update 为图形场景渲染做准备,在这期间Update执行几个操作,如更新NiAVObject对象的变换操作,更新NiTimeController对象,更新对象的包围盒。因此Update是一个非常昂贵的操作,只有在需要的时候才调用,下面有几种操作优化对Update的调用
Don't Call Update
It doesn't make much sense at first, but the fastest way to speed up a call to Update is not to call it. Update handles changes to transforms, bounds, and time controllers. If some subsection of your scene graph never has any of these changes, consider updating it separately from the dynamic portion of your scene graph. In general, this means that scenery in a game that never moves and has no animations can be updated once and rendered every frame from a new camera angle. Separate your scene graph into static and dynamic components. Update the static component once and update the dynamic component as needed.
分离场景成为动态和静态组成2个部分,只更新静态部件1次,根据需要更新动态部件
Use UpdateSelected
UpdateSelected is a variant on Update that tries to avoid expensive calculations when they are unnecessary. For example, UpdateSelected may skip the work of updating transforms if there are no NiTimeController objects attached that could change the transform. Assets exported from the art plugins should already be configured for use with UpdateSelected. In general, using UpdateSelected will give some but not all of the benefits of segmenting a scene graph into components and updating only the dynamic components as suggested in the "Don't Call Update" section. It is also important to note that if every NiAVObject in a hierarchy is animated such as a character with skeletal animation, UpdateSelected can sometimes actually be more expensive than Update since it must perform branching operations based off of the data for each object.
UpdateSelected 可以检测一个物体变换矩阵是否改变,未变则不执行update,这样可以提高性能,适合场景图形。但对于人物模型不太适合,因为对于人物动画或者骨骼动画,UpdateSelected 可能浪费性能。所有这个函数适合场景。而骨骼动画,mesh最好不要attach 到场景上,作为单独单元存在
Simplify the Scene Graph Hierarchy
Every node inserted into the scene graph costs some CPU time to update. Removing unnecessary nodes can increase the speed of Update operations. By default, the optimization plugin tries to do this coming out of the art packages. If there are NiNode objects in a scene graph that only serve to hold a name and a single child, they can easily be removed by pushing the name and the transform down to that child.
Use Linear Animation Keys
There are several types of animation keys in the Gamebryo animation system, but linear keys are the simplest to interpolate between and take the least amount of CPU time. If possible, consider exporting art with linear keys to increase performance.
Use Fewer Bones
Characters with skeletal animation often represent the most expensive portion of a scene graph because each NiNode represents a bone that has to be animated and then updated correctly. Consider reducing the number of bones in a character either permanently in the art package or dynamically using the Bone LOD system. The Bone LOD system allows you to turn off animation of subtrees which will decrease the amount of time needed in Update. Bone LOD is further discussed in the NiAnimation documents for NiBoneLODController and documents for the 3ds max and Maya plugins.
Gamebryo 支持mmorpg fps 类型游戏。即同时支持 室内场景渲染(主要可能是mesh + protal)和室外场景渲染,对于目前工具来讲,能更好的支持室内环境。对于室外地形还不是太好。可能2.5的地形编辑器能提高这部分的能力
优点:,
1 面向对象设计、插件式结构,场景图体系表示,和主流的3D建模工具集成,强大的艺术工具链集成,有效的可视对象裁减,在所有平台上支持高级的3D硬件加速,高端的纹理贴图和渲染效果
动态碰撞检测,支持3D音效,Level-of-detail 表示,灵活的渲染、排序、裁减方法
分为NiApplication 和 Corelib 两部分
corelib 负责图形渲染功能,图形方面基本拥有流行商业引擎的全部功能。部分特性如下:
Lighting:Per-vertex, Per-pixel, Gloss maps
Shadows:Shadow Mapping。
Texturing: Basic, Multi-texturing, Bumpmapping, Mipmapping, Projected
Shaders: Vertex, Pixel, High Level.支持 rendermonkey,cgfx,HLSL
Scene Management:General, Portals, Occlusion Culling, PVS, LOD
Animation:IK, Forward Kinematics, 关键帧动画, 骨骼动画, Animation Blending
Meshes Mesh Loading, Skinning, Progressive: • Level of detail, including Bone LODs
Special Effects Environment: Mapping, Lens Flares, Billboarding, Particle System, Sky, Fire, Explosion, Decals, Fog: Environment maps (spherical environment maps are supported on all platforms, with cubic environment maps supported on DX8 and Xbox).
Rendering Fixed-function, Render-to-Texture
NiApplication 官方建议由开发人员修改来改善性能,相当于主工程。封装了 Winmain 和 消息处理函数,以及FPS 控制,输入输出控制、游标、实体等功能
而客户端、服务器逻辑可以制作成dll, 由主工程调用。
2 支持的第三方工具
Audio:Miles,Sensaura,FMOD,wwise(这个有辅助工具)
Video:bink,Smacker
AI: AI Implant
Networking:butterfly.net,quazal
Physics: physx
Trees:Speedtree 这个可能需要另外花钱
Facial Animation: OC3 Impersonator
3 拥有线程安全的内存分配跟踪管理系统、RTTI 动态类型识别、profile 性能测试。运行时刻性能分析工具,渲染每个对象的时间,每个对象渲染的三角形数据,内存使用分析。后台多线程资源读取,不影响前台的渲染流程。
4 支持众多平台,而且源码开放,有简单疑惑的地方可能通过阅读部分源码及时解决。
// NiObject.h
// NiObject.cpp
// NiObjectNET.h
// NiObjectNET.cpp
// NiAVObject.h