广州业余3D程序

沉着,简单,便捷,逐步重构
随笔 - 8, 文章 - 0, 评论 - 10, 引用 - 0
数据加载中……

(翻译)3.3 抽象渲染API(一)

    3.3 抽象渲染API(一)

 

    这章描述抽象基类Renderer,它担当着作为绘图对象的资源管理器的作用。接口相当多,因此,我会一次列出接口的一部分和描述每部分的作用,而不是把整个类结构的代码块都展示出来。

 

3.3.1 构造和析构

    基类Renderer是抽象的,因为它仅有的构造函数是保护的,并且它指定了相当一些纯虚函数,这些纯虚函数必须由继承类实现。相关的构建,销毁以及传递给构造函数的信息的存取函数成员,已经在下面列出来。

 

    Renderer( FormatType, DepthType, StencilType, BufferingType, MultiSamplingType, iWidth, iHeight );

    virtual ~Renderer();

    

    FormatType GetFormatType() const;

    DepthType GetDepthType() const;

    StencilType GetStencilType() const;

    BufferingType GetBufferingType() const;

    MultiSamplingType GetMultiSamplingType() const;

    int GetWidth() const;

    int GetHeight() const;

 

    enum

    {

        OPENGL,

        DIRECTX,

        SOFTWARE,

        MAX_RENDERER_TYPES

    };

    virtual int GetType() const = 0;

 

    构造函数接受的输入描述了应用程序需要什么样的帧缓存成分。典型的格式是32RGBA24RGB。深度类型为深度缓存指定位数,当前要么是没有,162432。如果你计划为图形系统创建继承类支持一种不同的位数(例如,SGI 02机器有一种15位格式),那么你必须添加新常量到DepthType枚举。模板类型为模板缓存指定位数,当前是没有或者8。缓冲类型要么是单或者双。对于实时应用程序,你需要双缓冲。多重采样类型指的是光栅化期间每像素产生多次采样的能力。你可选的采样次数是没有,2或者4。缓存的宽和高也同样在构造的时候指定。

    提供了宽,高和帧缓存参数的成员存取器。同时列在一起的是函数GetType,一种简单的运行时类型信息(RTTI)形式。引擎当前支持的仅有的继承类是OpenGLRenderer(枚举OPENGL),Dx9Renderer(枚举DIRECTX)和SoftRenderer(枚举SOFTWARE)。OpenGLsoftware渲染器运行在微软Windows之外的平台。为了提供少量平台相关的特性,每个平台都从这些类里继承新的类。例如,微软Windows OpenGL渲染器是类WglRenderer,它继承自OpenGLRenderer。抽象渲染API不需要知道这层继承,除了渲染器是基于OpenGL;这样,除了列在这里的,就没有其他的枚举。

 

3.3.2 摄像机管理

    画任何东西,为了定义要渲染的空间范围以及定义视模型(透视或正交),渲染器需要一个摄像机。摄像机相关的接口有

 

    void SetCamera( Camera* );

    Camera* GetCamera() const;

    virtual void OnFrameChange();

    virtual void OnFrustumChange();

    virtual void OnViewportChange() = 0;

 

    SetCamera函数告诉渲染器使用指定的摄像机绘图。这个调用在渲染器和摄像机之间建立了双路通讯——渲染器拥有一个摄像机的指针,反过来摄像机也拥有一个渲染器的指针。当摄像机移动了,重定位了,或者它的平截头体参数改变了,通过函数OnFrameChangeOnFrustumChangeOnViewportChange,渲染器会被自动通知到。在Wild Magic 3,渲染器继承类得去实现所有这3种情况,调用图形API,更新与摄像机坐标系统,摄像机视模型和视口相关联的齐次矩阵。2.8章作出的论断允许我按照自己的方法设置矩阵,而不是按照图形API通过它方便的函数进行设置的那种方式,因此,矩阵的存储和很多矩阵操作被移出继承类而放置在基类。世界矩阵,视矩阵和投影矩阵在渲染器里有显式的保存。继承类有少量工作去做,也就是,告诉图形API它们的是什么矩阵。

 

3.3.3 全局状态管理

    渲染器维护着一份当前起作用的的全局状态列表,这些状态有alpha混合,剔除(怎样剔除三角形),雾,材质,多边形偏移(怎样处理深度混叠问题),模板,线框和深度缓冲。这些存取器有

 

    virtual void SetAlphaState( AlphaState* );  

    virtual void SetCullState( CullState* );  

    virtual void SetFogState( FogState* );

    virtual void SetMaterialState( MaterialState* );

    virtual void SetPolygonOffsetState( PolygonOffsetState* );

    virtual void SetStencilState( StencilState* );
    virtual void SetWireframeState( WireframeState* );
    virtual void SetZBufferState( ZBufferState* );

    AlphaState* GetAlphaState();

    CullState* GetCullState();

    FogState* GetFogState();

    MaterialState* GetMaterialState();

    PolygonOffsetState* GetPolygonOffsetState();

    StencilState* GetStencilState();

    WireframeState* GetWireframeState();

    ZBufferState* GEtZBufferState();

    void SetReverseCullFace( bReverseCullFace );

    bool GetReverseCullFace() const;

    

    void SetGlobalState( GlobalStatePtr[] );

    void RestoreGlobalState( GlobalStatePtr[] );

 

    void SetLight( int, Light* );

    Light* GetLight( int );

 

    通过存取当前起作用状态的指针数组,全局状态的Set/Get函数都是直截了当的。凭借着镜像图像的三角形顶点顺序与正常图像顺序相反,SetReverseCullFaceGetReverseCullFace函数是被用在涉及到镜像的特别效果上。

    SetGlobalStateGetGlobalState函数在绘图系统里是作为内部使用的。绘图中,它们的使用是基于每个对象的。特别地,如果一个对象它自己有全局状态附加其上,那么在绘图期间,这些函数会覆盖掉当前起作用的全局状态,但,绘图后,之前的全局状态会被恢复。

    SetLightGetLight函数是一个简单的Light对象指针数组的存取器。同样,这些函数也作为内部使用的,当绘制对象时,用在需要有光照支持的特殊效果上。

 

3.3.4 缓存清除

    在绘制一个对象集之前,组成帧缓存的各种缓存可能需要清除。相关的接口列在这里。

 

    virtual void SetBackgroundColor( const ColorRGBA& );

    const ColorRGBA& GetBackgroundColor() const;

 

    virtual void ClearBackBuffer() = 0;

    virtual void ClearZBuffer() = 0;

    virtual void ClearStencilBuffer() = 0;

    virtual void ClearBuffers() = 0;

    virtual void DisplayBackBuffer() = 0;

 

    virtual void ClearBackBuffer( iXPos, iYPos, iWidth, iHeight ) = 0; 

    virtual void ClearZBuffer( iXPos, iYPos, iWidth, iHeight ) = 0; 

    virtual void ClearStencilBuffer( iXPos, iYPos, iWidth, iHeight ) = 0; 

    virtual void ClearBackBuffers( iXPos, iYPos, iWidth, iHeight ) = 0;

 

    典型地,所有缓存都被清除。双缓存渲染意味着渲染场景到一个后缓存(一个颜色缓存),随后交换到前缓存(显示在屏幕的颜色缓存)。这个交换通过DisplayBackBuffer的调用而发生。ClearBackBuffer函数清除后缓存,设置它的值为当前背景颜色。你可以用SetBackgroundColor来设置背景颜色。深度缓存通过ClearZBuffer函数来清除,而模板缓存通过ClearStencilBuffer函数。所有这三个缓存的清除可以通过ClearBuffers函数。第一块里面的清除函数是用于清除整个缓存,但第二块里面的清除函数是用于情况缓存的一个子矩形。

    典型的操作顺序是

 

    clear all buffers;

    render the scene;

    display back buffer;

 

    然而,这不是规定的。举个例子,如果你有一个填充整个窗口的天空穹,那么场景物体是在天空穹渲染之后才渲染,你并没有必要去清除后缓存。你也可能有一层预生成的静态几何体,它产生颜色缓存和深度缓存。意图是,这些缓存从磁盘里加载,并且每帧通过图形API的调用写到硬件。然后,另外的(动态的)物体才被渲染。这种情况下,你不需要清除后缓存或者深度缓存。

    清除缓存和交换后缓存到前缓存是平台和API特定的操作,因此,虚函数是纯的,并且继承类必须实现它们。

 

3.3.5 物体绘制

    物体的绘制通过下面的接口函数提供:

 

    virtual bool BeginScene();

    virtual void EndScene();

    void DrawScene( VisibleSet& );

    void Draw( Geometry* );

    virtual void DrawElements() = 0;

    void ApplyEffect( ShaderEffect*, rbPrimaryEffect );

 

    BeginSceneEndScene函数界限了包含有绘制调用的代码块。一些图形API可能需要绘制前设置以及绘制或清理。实例程序里面的主绘制例程是DrawScene。输入是潜在可见物体集。这个集合是由场景图剔除系统产生的;细节查看4.5章。Draw函数由DrawScene为每个场景里面的几何图元间接调用,但Draw是一个公开的函数,它能用作绘制屏幕空间多边形;例如,绘制在已渲染场景上面的GUI元素。ApplyEffect函数仅仅是由Draw调用。正在绘制的物体可以拥有多重特殊效果附加在其上面。ApplyEffect函数为每个效果而被调用。当光照起作用的时候它也被调用。DrawElements函数由每个渲染器继承类实现。当几何图元的所有资源都加载和启用完毕后,它就会被调用。

    DrawApplyEffect函数在3.4章里会有更细节的讨论。它们隐藏了许多绘图子系统,包括加载和启用资源,构造顶点和索引缓存,使着色程序有效,设置着色常量和创建纹理采样器。

 

3.3.6 文本和2D绘制

    在渲染的场景上面显示文本是很普通的。渲染器API有一些基本的函数来支持这个功能。

 

    virtual int LoadFont( acFace, iSize, bBold, bItalic ) = 0;

    virtual void UnloadFont( iFontId ) = 0;

    virtual bool SelectFont( iFontId ) = 0;

    virtual void Draw( iX, iY, rkColor, acText ) = 0;

    virtual void Draw( aucBuffer ) = 0; 

 

    提供了最少量的字体处理。WglRendererDx9Renderer类使用微软Windows API调用来选择字体。AglRenderer类(Macintosh)拥有唯一一种默认字体;还没有加入选择其他字体的支持。GlxRenderer类(Linux/Unix)使用位图字体。与视窗系统的对接不是这本书的重点。

    最后一个函数Draw允许你写一个已经创建的颜色缓存到后缓存。我仅仅使用它来支持2D图形程序。渲染器写2D图元到一个内存缓存,它然后被传递给Draw和交换到前缓存。如果你想看细节的话,实例里有一些2D程序。2D系统仅有最少量支持来绘制图元(点,线段,圆,矩形,文本)。

 

3.3.7 杂项

    下面列出的函数支持各种有趣的操作。

 

    virtual void SetColorMask( bAllowRed, bAllowGreen, bAllowBlue, bAllowAlpha );

    virtual void GetColorMask( &bAllowRed, &bAllowGreen, &bAllowBlue, &bAllowAlpha );

 

    virtual void SetDepthRange( fZMin, fZMax ) = 0;

 

    virtual void EnableUserClipPlane( int, const Plane3f& ) = 0;

    virtual void DisableUserClipPlane( int ) = 0;

 

    virtual void SetPostWorldTransformation( const Matrix4f& );

    virtual void RestorePostWorldTransformation();

 

    virtual void SetWorldTransformation();

    virtual void RestoreWorldTransformation();

 

    void SetProjector( Camera* );

    Camera* GetProjector();

 

    virtual const char* GetExtension() const = 0;

    virtual char GetCommentCharacter() const = 0;

 

    SetColorMaskGetColorMask函数允许你指定哪个颜色通道可以被像素着色器更新;细节可以查看3.1.11

    SetDepthRange函数允许你改变默认的深度范围[0,1]来完成一些不同的事情。这在某些特效里面很有用;例如,PlanarReflections实例设置深度范围为[1,1],因此,当渲染包含有镜子的平面时,深度缓存的值被设置为最大深度。这允许其它物体,当它们在镜子上面(或前面)绘制时,能被正确地(在深度)绘制。

    六个平截头体面用作裁剪,但用户可以指定额外的裁剪平面。EnableUserClipPlaneDisableUserClipPlane函数允许你指定裁剪平面。输入的平面一定要在模型坐标。它会被内部转换到摄像机坐标来支持裁剪空间裁剪。PlanarReflections实例同样也操作用户自定义裁剪平面。

    模型到裁剪空间转换是一个应用到模型空间点的组合,

 

    XmodelHworldHviewHproj

 

    在进一步在视空间或裁剪空间处理之前,一些特效需要转换世界空间的点。这可以通过在组合里插入额外的转换来完成,

 

    XmodelHworldHpostworldHviewHproj

 

    效果会在它需要的时候提供HworldSetPostWorldTransformationRestorePostWorldTransformation函数是钩子,它们允许你指定如此一个转换。PlanarReflections实例使用这个机制来将一个反射矩阵插入到组合里。PlanarShadows实例使用这个机制来将一个投影矩阵插入到组合里。这个矩阵是相对于产生阴影的光源的投影。

    SetWorldTransformationRestoreWorldTransformation函数是由Draw内部使用。它们设置保存在Renderer里面的世界矩阵。继承类也要将新的世界矩阵通知图形APISetProjectorGetProjector函数用在特效里,这些特效需要通知渲染器一个投射源,例如投射纹理,投射阴影和阴影贴图。

    GetExtensionGetCommentCharacter函数是由继承类实现,用于为从磁盘加载和分析着色程序提供信息。所有着色程序拥有一个.wmspWild Magic着色程序)扩展名,但每种图形API拥有它自己版本的程序。OpenGL版本拥有复合扩展名.ogl.wmsp。这个渲染器的GetExtension函数返回oglDirect3D渲染器函数返回dx9,软件渲染器返回sft。着色程序被分析以获得相关信息,这些信息有输入变量,输出变量和着色常量,包括哪些寄存器已经被分配给它们。这些信息出现在程序文件的注释里,每个注释行以一个特定的字符开始。这个字符在调用GetCommentCharacter时返回。OpenGL渲染器返回字符#。Direct3D和软件渲染器返回字符/

posted on 2009-04-22 21:35 saltyshrimp 阅读(2582) 评论(1)  编辑 收藏 引用 所属分类: 3D游戏引擎设计-实时计算机图形学的应用方法(第二版)

评论

# re: (翻译)3.3 抽象渲染API(一)  回复  更多评论   

一曲肝肠断 天涯何处觅知音
2011-03-22 02:26 | 付轩杰

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理