2022年Ogre的渲染系统 .pdf
Ogre 的渲染系统( Rendering System)盛崇山 http:/ AntsamCGD 渲染系统个人认为就是同图形学有关的一切系统;包括了geometry system 、material system、shader system。Rendering system 分为两部分: API 无关的部分和API 相关部分。后者主要是只同DirectX 和 OpenGL 相关的系统。前者则是两个的共同的特性。API 无关部分同Pipeline Abstraction 有很大的关系,API的部分功能就是设置Pipeline ( Pipeline configuration ) ,Pipeline 可以参考 Pipeline Design 。 既然是 Render System 必然是有Target的,我们前面把Scene Manager 比喻成舞台跟导演,那么Render System 就是摄影机,而胶片就是 Render Target。先让我们看一下相关类的UML 图,然后在详细这些类以及相互之间的关系。一、 Render System UML 图 Render System 相关类 UML Part one :图一: Render System 相关类 UML Part one 图一中的类View Port 包含了一个Camera, 另外一个同Render System 相关的类(未画出,图中只有一根聚合的关系线)Root。前面说过把Render System 比喻成摄影机,现在我们进一步的细化:View Port 和 Camera 就是摄影机的摄像头,Render Target就是名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 13 页 - - - - - - - - - 胶带,那么Render System 就是一个光学系统,它把从摄像头进来的光进行处理变换,然后再把结果写到Render Target 中,而 Root 就是各种各样的道具;那么,演员呢?演员就是游戏中的各种角色;电影剧本对应的是游戏剧本(或者称为策划);化妆师对应的则是美工和建模人员;电影的音乐也越来越重要了,这就类似于游戏中的音乐。Good(_) ,现在让我们想象一下,我们在拍摄现场:导演Scene Manager 摄影机Render System (including view port 、 camera、 target)灯光、道具、服装 Root(engine or Resource Manager) 演员游戏中的角色(mesh、entity)化妆师美工和建模人员剧本游戏策划电影音乐游戏音乐从上面可以看出电影公司和游戏制作公司非常相似,那么一个基本的游戏引擎应该至少包括前面的四项,在场景组织分析那篇文章中从功能上对导演和Scene Manager 进行了类比,我们将在对Render System 具体的分析后在进行类比。 Render Target 的 UML 图如下所示:图二: Render System相关类 UML 图 Part two 电影的胶片不同,Render Target 也有不同( _) 。在上面的两幅图中还有两个listener类应该注意一下,我们将在下面的详细分析中再做具体的分析。二、详细分析Camera 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 13 页 - - - - - - - - - 首先然我们看一下Camera的定义: class _OgreExport Camera : public MovableObject protected: / Camera orientation, quaternion style Quaternion mOrientation; / Camera position - default (0,0,0) Vector3 mPosition; / Stored versions of parent orientation / position mutable Quaternion mLastParentOrientation; mutable Vector3 mLastParentPosition; / Derived positions of parent orientation / position mutable Quaternion mDerivedOrientation; mutable Vector3 mDerivedPosition; / Camera y-direction field-of-view (default 45) Real mFOVy; / Far clip distance - default 10000 Real mFarDist; / Near clip distance - default 100 Real mNearDist; / x/y viewport ratio - default 1.3333 Real mAspect; / Whether to yaw around a fixed axis. bool mYawFixed; / Fixed axis to yaw around Vector3 mYawFixedAxis; / The 6 main clipping planes mutable Plane mFrustumPlanes6; / Orthographic or perspective? ProjectionType mProjType; / Rendering type SceneDetailLevel mSceneDetail;Camera 的主要作用:Camera control、特定的拍摄手法(聚焦等_,这主要是通过改变投影方式的) 、Frustum Cull ,上面的代码中用了三种不同的颜色来表示三种功能的数据结构。 Camera Control用于控制摄影机的轨迹(例如:平移、旋转等,想象一下在拍电影的时候, 摄影机是怎么移动的) ;特定的拍摄手法主要是改变距离来改变成像的大小名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 13 页 - - - - - - - - - (凸透镜成像原理_) ;Frustum Cull 用于剔除在摄影机范围之外的Object,减小渲染压力。View Port 代码定义如下: class _OgreExport Viewport public: protected: Camera* mCamera; RenderTarget* mTarget; / Relative dimensions, irrespective of target dimensions (0.1) float mRelLeft, mRelTop, mRelWidth, mRelHeight; / Actual dimensions, based on target dimensions int mActLeft, mActTop, mActWidth, mActHeight; View Port 作用有点难表述,打个比方就是我们看的电影有的是宽银幕的,而有的只是一般银幕。 View Port就类似于这个银幕的大小,不同的View Port可以达到不同的效果。成员变量中还有Camera和 Render Target两个变量,暂时还没有弄清楚其作用,可能是把Camera同 Render Target一对一的对应起来吧。 Render Target Render Target 只是一个抽象类, 只包含了Render Target的基本信息, 代码定义如下所示: class _OgreExport RenderTarget public: protected: int mWidth; int mHeight; int mColourDepth; bool mIsDepthBuffered; / Stats StatFlags mStatFlags; Timer* mTimer ; float mLastFPS; float mAvgFPS; float mBestFPS; float mWorstFPS; float mBestFrameTime ; float mWorstFrameTime ; unsigned int mTris; String mDebugText;名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 13 页 - - - - - - - - - bool mActive; typedef std:mapint, Viewport*, std:less ViewportList; / List of viewports, map on Z-order ViewportList mViewportList; typedef std:vector RenderTargetListenerList; RenderTargetListenerList mListeners; 代码中包括了三个基本信息:Render Target 的尺寸、渲染的Fps(frame per second、Listener。下面看一下两个子类定义:Render Window 和 Render Texture。 class _OgreExport RenderTexture : public RenderTarget protected: / The texture that gets accesses by the rest of the API. Texture * mTexture; class _OgreExport RenderWindow : public RenderTarget protected: bool mIsFullScreen; int mLeft; int mTop; 上面两个类的定义中,不同的target又不同的特性,当纹理作为target的 时候必须有一张纹理作为target ,所以包含了成员变量(Texture m_Texture )。下面让我们来看一下更具体的Render Target的定义: class D3D9RenderWindow : public RenderWindow protected: HWND mExternalHandle; / External Win32 window handle HWND mHWnd; / Win32 Window handle HWND mParentHWnd; / Parent Win32 window handlebool mActive; / Is active i.e. visible bool mReady; / Is ready i.e. available for update bool mClosed; static LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 13 页 - - - - - - - - - / - / DirectX-specific / - / Pointer to D3DDriver encapsulating Direct3D driver D3D9Driver* mpD3DDriver; / Pointer to the 3D device specific for this window LPDIRECT3DDEVICE9 mpD3DDevice; D3DPRESENT_PARAMETERS md3dpp; LPDIRECT3DSURFACE9 mpRenderSurface; LPDIRECT3DSURFACE9 mpRenderZBuffer;到上面这个代码我们就比较熟悉了吧_!典型的 Win32 窗口。 可能我们还有个疑问,怎么把Object 渲染到 Window 上?Render System 现在我们可以看一下Render System 的定义了: class _OgreExport RenderSystem protected: /* The render targets. */ RenderTargetMap mRenderTargets; /* The render targets, ordered by priority. */ RenderTargetPriorityMap mPrioritisedRenderTargets; /* The Active render target. */ RenderTarget * mActiveRenderTarget; / Texture manager / A concrete class of this will be created and / made available under the TextureManager singleton, / managed by the RenderSystem TextureManager* mTextureManager; / Used to store the capabilities of the graphics card RenderSystemCapabilities* mCapabilities; / Active viewport (dest for future rendering operations) Viewport* mActiveViewport; CullingMode mCullingMode; bool mVSync; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 13 页 - - - - - - - - - / Store record of texture unit settings for efficient alterations Material:TextureLayer mTextureUnitsOGRE_MAX_TEXTURE_LAYERS; size_t mFaceCount; size_t mVertexCount; / Saved set of world matrices Matrix4 mWorldMatrices256; 上面的代码中有四块需要说明一下:第一块是把Render System 和 Target联系在一起,而第二块则是由于需要对Texture 操作,第三块是必须设置的ViewPort ,最后一块模拟了Matrix stack,这主要是由于OpenGL和 DirectX中对于 Matrix的实现方式的不同,而且用法也有区别。我们说过Render System 的主要作用在于对 Pipeline的配置( Pipeline configuration)。所以看Render System 的成员函数更有意义。 1. _set函数(主要用于内部设置)为什么需要一个内部的set函数呢?现在个人认为主要是由于Engine中对很多基本结构进行了包装,所以可以用能不设置函数进行一定的转化, 例如 _setTexture, 由于我们所有用的Texture 类和 DirectX 中的 Texture名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 13 页 - - - - - - - - - 类不同,不能直接调用DirectX 的 API,当然可以用用引用成员变量的方法来进行设置, 但是这么从外观上不好,而且也没有速度上的优势(暂时我只能给出这种解释_) 。还有一些Matrix 、Texture 属性、 Depth Buffer属性的设置。2. Set 和 Get 函数上面的图中包含了Stencil Buffer 、Light的设置,最值得关注的是对于Vertex Buffer 以及相关属性设置的函数。我们将在后面更具体的分析Buffer 。现在我们基本上分析了Render System中于具体的API 无关的部分, 现在我们分析一下同DirectX API 相关的部分,然我们看看D3D9RenderSystem的定义: class D3D9RenderSystem : public RenderSystem private: 这是同 DirectX 相关的 / Direct3D 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 13 页 - - - - - - - - - LPDIRECT3D9 mpD3D; / Direct3D rendering device LPDIRECT3DDEVICE9 mpD3DDevice; 这是同 Win32相关的 / external window handle ;)HWND mExternalHandle; / instance HINSTANCE mhInstance;这是同 DirectX 相关的 / List of D3D drivers installed (video cards) D3D9DriverList* mDriverList; / Currently active driver D3D9Driver* mActiveD3DDriver; / Device caps. D3DCAPS9 mCaps;/ Array of up to 8 lights, indexed as per API / Note that a null value indeicates a free slot Light* mLightsMAX_LIGHTS; D3D9DriverList* getDirect3DDrivers(void); void refreshD3DSettings(void); inline bool compareDecls( D3DVERTEXELEMENT9* pDecl1, D3DVERTEXELEMENT9* pDecl2, int size ); 这部分主要是由于 DirectX 中的用的是左手坐标系,而 一般系统沿用的是 OpenGL 的标准,采用了右手坐标系, 所以,在设置 Matrix 的时候需要进行转换。 / Matrix conversion D3DXMATRIX makeD3DXMatrix( const Matrix4& mat ); Matrix4 convertD3DXMatrix( const D3DXMATRIX& mat ); void initInputDevices(void); void processInputDevices(void); void setD3D9Light( int index, Light* light ); 这部分代码中直接用了 DirectX 的枚举常量, 这种定义应该是非常原始的操作,尽量不要用(所以放在Private 中) 因为不具有通用性。/ state management methods, very primitive ! 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 13 页 - - - - - - - - - HRESULT _SetRenderState(D3DRENDERSTATETYPE state, DWORD value); HRESULT _SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value); HRESULT _SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value);D3D9HardwareBufferManager* mHardwareBufferManager; size_t mLastVertexSourceCount; 前面基本上把 Render System分析的差不多了( _),在 Render System中还有一个于特定 API相关的类非常重要,那就是 Buffer ,下面我们就是来分析 Buffer ,而且实现上主要以分析 DirectX 为主。 Buffer 先看看同 Buffer 相关的类的UML 图,这里主要分析DirectX 的实现方式。图三: Buffer 相关类 UML图几个问题:Buffer 主要用在哪里?Buffer 什么时候创建?Buffer 通过谁来创建?Buffer 怎么来管理?Buffer 目前主要用于存放Mesh 的数据名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 13 页 - - - - - - - - - Buffer 在构造函数中创建主要通过Hardware Manager 以及其子类来创建,或者直接new。Buffer 通过 Hardware Manager 来管理, Hardware 是一个 Singleton 。现在分析一下Hardware Manager,其相关类UML 图如下所示:上面的图中我们可以看出Hardware Buffer Manager(在 DirectX 中 D3D9 Hardware Buffer Manager 对 Vertex Buffer 和 Index Buffer进行管理,邮编的那几个类用于所名Buffer 中的数据是以什么结构存放的,例如:Buffer中是否包含Color 、Position、Normal、Texture Coordinate 等,什么顺序存放等都在Declaration 中说明。还有一个类必须注意的是Vertex Buffer Binding ,起作用我们可以直接引用代码中的说明:/* Records the state of all the vertex buffer bindings required to provide a vertex declaration with the input data it needs for the vertex elements. remarks Why do we have this binding list rather than just have VertexElement referring to the vertex buffers direct? Well, in the underlying APIs, binding the vertex buffers to an 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 13 页 - - - - - - - - - index (or stream) is the way that vertex data is linked, so this structure better reflects the realities of that . In addition, by separating the vertex declaration from the list of vertex buffer bindings, it becomes possible to reuse bindings between declarations and vice versa, giving opportunities to reduce the state changes required to performrendering. par Like the other classes in this functional area, these binding maps should be created and destroyed using the HardwareBufferManager. class _OgreExport VertexBufferBinding public: / Defines the vertex buffer bindings used as source for vertex declarations typedef std:map VertexBufferBindingMap; protected: VertexBufferBindingMap mBindingMap; unsigned short mHighIndex; 除了 Buffer 与具体的 API 相关外, Texture也是同 API 相关的。Texture Texture 相关类 UML 图如下所示:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 13 页 - - - - - - - - - 从 UML 图中我们可以看出Texture 同 Buffer 在类结构上有非常多的相似性,从创建、管理上都一致,但是有一点是不同的,那就是Texture 在构造函数中是不创建纹理接口的,只是初始化了纹理所需要的属性,在适当的时候才load 纹理数据的,至于为什么,暂时未搞清楚。OK,差不多分析好了,有了导演,有了摄影师,那我们还少一些基本的道具和工具,下次我们分析数据文件结构,到时候我们就可以着剧本拍电影了_。三、 Summary 暂时分析到这里,其实还可以分析的更细一些,不过现在没有必要。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 13 页,共 13 页 - - - - - - - - -