• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            D3D常用API

            D3DAPI大全,全部函數(shù)

            //Direct3D 9.0 SDK 開(kāi)發(fā)參考Direct3D 9.0 SDK 文檔 (中文版)

            詞匯表

            DirectX 8 教程

            你也可以把 COM 對(duì)象就想象成一套為某個(gè)主題而設(shè)計(jì)的一整套庫(kù)函數(shù)。DX 就提供了一套完整的設(shè)計(jì)3D游戲的庫(kù)。

            http://baike.baidu.com/view/1169027.htm

            使用DirectX的不同組件,你需要鏈接不同的靜態(tài)庫(kù)。例如你要使用DirectDraw組件,你就需要ddraw.lib。

            對(duì)于DirectDraw,這個(gè)頭文件是ddraw.h。//com編程

            D3D.H

            http://wowe1314.blog.163.com/blog/static/2358876200751191213583/

            在Direct3D編程中,我們要做的工作基本上可以歸納為:

            調(diào)用適當(dāng)?shù)暮瘮?shù)獲取接口指針;

            調(diào)用接口的方法(成員函數(shù))來(lái)完成所需功能;

            用完接口后,調(diào)用Release方法進(jìn)行“釋放”,注意釋放順序應(yīng)該和獲取它們的順序相反。

            http://www.lihuasoft.net/article/show.php?id=2928

            Microsoft_DirectX_9.0c里的 9個(gè)DirectX的DLL

            DX9和DX10在渲染流水線上都是有天壤之別的,好在DX高版本開(kāi)發(fā)包運(yùn)行庫(kù)中包含了對(duì)低版本開(kāi)發(fā)包運(yùn)行庫(kù)的實(shí)現(xiàn),所以用DX8開(kāi)發(fā)的程序,DX9運(yùn)行庫(kù)也能夠很好的支持,在安裝有D9運(yùn)行庫(kù)的系統(tǒng)上跑DX8開(kāi)發(fā)的程序不需要再安裝DX8運(yùn)行庫(kù),但是這個(gè)兼容性支持在最近被微軟逐漸放棄,有時(shí)候DX9的不同更新版本做的程序也不能向下兼容,比如DX9FEB2007SDK,同DX9AUG2006SDK在shader編譯規(guī)則上也是不同的,2007放棄了VS2.0和PS2.0以下版本shader的支持,同時(shí)對(duì)于HLSL中#include相對(duì)路徑引用的默認(rèn)根目錄也是有區(qū)別的.openGL的shader擴(kuò)展不同的廠商有不同的擴(kuò)展開(kāi)發(fā)包,但是這種情況隨著GLSL和openGL2.0的出現(xiàn)有所改觀.同時(shí)OpenGL是跨平臺(tái)的而DX不是,這意味著用OpenGL和GNU   C++規(guī)則開(kāi)發(fā)的程序可以同時(shí)在Linux,unix和安裝有GNU環(huán)境的Windows上同時(shí)運(yùn)行。從效率上來(lái)看,DX由于數(shù)據(jù)時(shí)批量寫(xiě)入顯存的,同OpenGL的單條函數(shù)寫(xiě)入來(lái)講DX效率上要高一些,不過(guò)近來(lái)OpenGL也支持了批寫(xiě)入,只是支持批寫(xiě)入的OpenGL放棄了openGL一慣的優(yōu)勢(shì)也就是語(yǔ)言架構(gòu)上的簡(jiǎn)潔使得函數(shù)的數(shù)目變得很冗雜。在效果上看DX9同支持GLSL或CG擴(kuò)展的openGL可以實(shí)現(xiàn)相同的顯示效果。但是有一點(diǎn)不同是DXUT和D3DX在一些基礎(chǔ)繪制上比glu和openGL   ARB   Extend要差一點(diǎn),比如繪制虛線,DX沒(méi)有好的函數(shù)可以是實(shí)現(xiàn)這一功能。但是DX的擴(kuò)展工具比openGL擴(kuò)展工具又有多余的優(yōu)勢(shì)比如向量計(jì)算,GUI控件,mesh優(yōu)化和曲面展開(kāi),PRT預(yù)計(jì)算等等和性能測(cè)試等等上又要強(qiáng)一點(diǎn)。DX10同OpenGL比較就感覺(jué)openGL不是同一個(gè)數(shù)量級(jí)上的產(chǎn)品,DX10在渲染流水線和架構(gòu)上和能夠?qū)崿F(xiàn)的效果上要比DX9和openGL進(jìn)步的多。要做面向未來(lái)的游戲產(chǎn)品盡量還是用DX10吧。

            ­

            LPDIRECT3D9 D3D主接口

            LPDIRECT3DDEVICE9 D3D硬件主接口

            LPDZRECT3DVERTXBUFFER9 頂點(diǎn)緩沖區(qū)接口

            LPD3DVIEWPORT9  視口接口

            LPD3DDISPLAYMODE D3D設(shè)備顯示模式接口

            LPD3DPRESENT_PARAMETERS 創(chuàng)建結(jié)構(gòu)用來(lái)保存設(shè)備的顯示模式接口

            LPD3DXVECTOR3  3D向量接口

            LPDIRECT3DTEXTURE9 紋理接口

            ID3DXSprite  精靈接口

            g.pvb  成員函數(shù)

            g_pD3D  成員函數(shù)

            g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm) 獲取顯示模式

            g_pd3dDevice 成員函數(shù)

            g_pd3dDevice->SetRenderState(,BOOL) 是否開(kāi)啟燈光

            g_pd3dDevice->SetTransform( D3DTS_WORLD, &(matWorld * matWorld_x));//將上面計(jì)算出來(lái)的旋轉(zhuǎn)矩陣,設(shè)置為世界變換矩陣

            g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );寫(xiě)入流

            g_pd3dDevice->SetFVF() 設(shè)置FVF

            g_pd3dDevice->DrawIndexedPrimitive( 畫(huà)形狀, 0, 0, 點(diǎn)個(gè)數(shù), 0, 三角形個(gè)數(shù) ); 畫(huà)

            timeGetTime 當(dāng)前系統(tǒng)的時(shí)間

            DIRECT3DTXTURE 文理接口

            BITMAPPEILEHEADER 文件頭

            BITMAPINFOHEADER 信息頭

            fread 讀一個(gè)數(shù)據(jù)塊

            biBitcout 每個(gè)象素占幾個(gè)字節(jié)

            bicompression 是否被壓縮

            fseek 跳,偏移指針

            greatetxture 創(chuàng)建一個(gè)空文理

            D3Dcaked_RECT 鎖定結(jié)構(gòu)體

            setTexturestagestata 設(shè)置文理操作

            CONSTD3DMATRIX*  進(jìn)行變換的變換矩陣

            結(jié)構(gòu)體

            D3DPRESENT_PARAMETERS 存儲(chǔ)D3D設(shè)備信息

            D3DXMATRIX  修改矩陣

            數(shù)組

            CUSTOMVERTEX 設(shè)置頂點(diǎn)位置顏色信息

            ­

            矩陣函數(shù)

            D3DXMATRIX * D3DXMatrixIdentity(POut,pM) 單位矩陣

            D3DXMATRIX * D3DXMatrixTranspose(上)  矩陣轉(zhuǎn)置

            D3DXMATRIX * D3DXMatrixInverse(上中間加個(gè)FLOAT) 逆矩陣

            D3DXMATRIX * D3DXMatrixTransformation()

            D3DXMATRIX* D3DXMatrixTranslation(輸出矩陣,X,Y,Z) 平移變換

            D3DXMATRIX * D3DXMatrixScaling(上) 縮放變換

            FLOAT D3DXPlaneDotCoord(pp,pv) 點(diǎn)和平面之見(jiàn)的關(guān)系

            D3DXPLANE * D3DXPlaneFromPointNormal(POUT,PPOINT,PNORMAL) 構(gòu)造子

            D3DXPLANE * D3DXPlaneFromPoints(Pout,pv1,pv2,pv3) 通過(guò)點(diǎn)來(lái)描述平面

            D3DXPLANE * D3DPlaneNormalize(POUT,PP) 標(biāo)準(zhǔn)化一個(gè)平面

            D3DXPLANE * D3DXPlaneTransform(POUT,PP,PM) 平移平面

            D3DXM

            轉(zhuǎn)換函數(shù)

            D3DXMATRIX* D3DXMatrixLookAtLH(輸出用于視圖轉(zhuǎn)換的矩陣,攝象機(jī)的位置,攝象機(jī)面向的位置,攝象機(jī)的正方向)  視圖轉(zhuǎn)換的矩陣

            D3DXMATRIX* D3DXMatrixOrthoLH(輸出用于正交投影的交換矩陣,取景寬,取景高,取景離攝象機(jī)的最近距離,取景離攝象機(jī)的最遠(yuǎn)距離) 正交投影變換矩陣

            D3DXMATRIX* D3DXMatrixPerspectiveFovLH(輸出用于透視投影的交換矩陣,攝象機(jī)鏡頭的夾角Y,平截臺(tái)體的縱橫比,近平截面的距離,遠(yuǎn)平截面的距離) 透視投影的矩陣

            Direct3DCreate9(D3D版本) 創(chuàng)建D3D對(duì)象

            設(shè)備函數(shù)

            SetTransform(變換的類型,變換的變換矩陣) 設(shè)置左手或右手坐標(biāo)

            SetViewport(視口指針) 設(shè)置遠(yuǎn)近距離

            GetClientRect(hWnd,*RECT) 獲取窗口繪圖區(qū)域

            memcpy(指針,數(shù)組,長(zhǎng)度) 拷貝

            SetStreamSource(0,G.pvb接口指針,0,長(zhǎng)度) 數(shù)據(jù)流

            GetAdapterDisplayMode(指定顯示卡序列號(hào),存儲(chǔ)顯示模式的指針) 獲取顯卡的模式

            HRESULT CreateDevice(顯卡序列號(hào),D3D設(shè)備類型,所屬窗口句柄,D3D進(jìn)行3D運(yùn)算,存儲(chǔ)D3D設(shè)備相關(guān)信息指針,返回D3D設(shè)備借口指針的地址) 創(chuàng)建設(shè)備借口

            HRESULT CreateVertexBuffer(頂點(diǎn)緩沖區(qū)大?。ㄗ止?jié)),頂點(diǎn)緩沖區(qū)屬性,靈活頂點(diǎn)格式,頂點(diǎn)緩沖區(qū)內(nèi)存位置,頂點(diǎn)緩沖區(qū)指針地址,保留參數(shù)通常為0) 創(chuàng)建頂點(diǎn)緩沖

            HRESULT CreateIndexBuffer(索引緩沖區(qū)大小(字節(jié)),頂點(diǎn)緩沖區(qū)屬性,FMT顏色,頂點(diǎn)緩沖區(qū)內(nèi)存位置,索引緩沖區(qū)指針地址,保留參數(shù)通常為0)   創(chuàng)建索引緩沖

            HRESULT Lock(加鎖內(nèi)存起始地址,加鎖內(nèi)存大小,返回內(nèi)存指針地址,加鎖屬性) 加縮內(nèi)存

            HRESULT UnLock() 解鎖

            HRESULT SetStreamSource(渲染數(shù)據(jù)流序列號(hào),進(jìn)行綁定連接的頂點(diǎn)緩沖區(qū)指針,進(jìn)行綁定連接渲染數(shù)據(jù)流的起始位置,渲染數(shù)據(jù)流中一個(gè)頂點(diǎn)所占的內(nèi)存大小) 頂點(diǎn)緩沖區(qū)和渲染數(shù)據(jù)流連接

            HRESULT SetFVF(靈活頂點(diǎn)格式) 設(shè)置頂點(diǎn)格式

            HRESULT DrawPrimitive(繪制的圖元類型,繪制的開(kāi)始頂點(diǎn)的索引值,繪制的圖元數(shù)量)  畫(huà)到后向緩沖區(qū)

            HRESULT DrawPrimitiveup() 可以直接畫(huà)

            HRESULT Preesent(復(fù)制源的矩形區(qū)域指針,復(fù)制目的地的矩形區(qū)域指針,D3D設(shè)備窗口句柄,最小更新區(qū)域指針) 屏幕翻轉(zhuǎn)

            HRESULT SetIndices(使用的索引緩沖區(qū)指針) 設(shè)置當(dāng)前繪制的索引數(shù)組

            DrawIndexedPrimitive(圖元類型,繪制到的索引緩沖區(qū)的開(kāi)始地址,最小的索引數(shù)組元素的值,頂點(diǎn)的數(shù)目,開(kāi)始的索引數(shù)組元素的值,繪制的數(shù)量) 同DrawPrimitive()

            ­

            繪制函數(shù)

            HRESULT DrawPrimitive(基本圖元類型,起始頂點(diǎn),繪制的圖元的數(shù)量)  圖元繪制

            HRESULT Clear(清楚的矩形區(qū)域數(shù)量,清除的舉行區(qū)域數(shù)組指針,清楚哪個(gè)緩沖區(qū),清除后重置的顏色,清除后重置的深度,0-1.0,重置的摸版值) 清空?qǐng)D形繪制區(qū)

            HRESULT BeginScene() 開(kāi)始繪制

            HRESULT EndScene() 結(jié)束繪制

            ­

            紋理函數(shù)

            CreateTexture()  創(chuàng)建D3D紋理對(duì)象

            LoadBmpTeture() 裝載文理函數(shù)

            LoadBmpTexture24Bit (LPDIRECT3DDEVICE9 pDevice,LPCSTR  pSrcFile,LPDIRECT3DTEXTURE9* ppTexture) 24位紋理

            D3DXCreateTextureFromFile(D3D設(shè)備指針,紋理圖形文件,存儲(chǔ)D3D文理的指針地址) 直接從磁盤(pán)獲取紋理

            D3DXCreateTextureFromFileEx(D3D設(shè)備指針,紋理圖形文件,指定紋理寬,高,指定漸進(jìn)紋理序列級(jí)數(shù),紋理使用方式一般為0,指定紋理圖形格式,紋理存放的內(nèi)存類型一般位為0,紋理過(guò)濾方式,自動(dòng)生成的紋理序列過(guò)濾方式,設(shè)置透明色,圖形文件信息存放地址可設(shè)置0,調(diào)色板存儲(chǔ)地址,創(chuàng)建的D3D文理的指針地址) 高級(jí)獲取紋理

            HRESULT SetTexture(多級(jí)紋理的索引0-7,D3D的紋理接口指針) 設(shè)置當(dāng)前要渲染的紋理

            HRESULT SetTextureStageState(多級(jí)紋理的索引,紋理渲染狀態(tài)的類型,紋理渲染狀態(tài)的值,與類型相對(duì)應(yīng)) 設(shè)置紋理的渲染狀態(tài)

            HRESULT SetSamplerState(指定紋理屬性0-7,紋理采樣屬性類型,設(shè)置紋理采樣屬性) 紋理采樣

            HRESULT CheckDeviceFormat(指定顯卡序列號(hào),D3D設(shè)備類型,指定顯示模式格式,緩沖區(qū)屬性,需要使用查詢的格式的設(shè)備類型,需要查詢的顯示格式) 紋理壓縮

            HRESULT LockRect(指定加鎖的紋理級(jí)別,指向D3DLOCKED_RECT結(jié)構(gòu),要加鎖的RECT區(qū)域-0代表整個(gè)區(qū)域,加鎖類型-取0或下表的值) 鎖定紋理

            HRESULT UnlockRect(解鎖的紋理級(jí)別) 解鎖紋理

            向量函數(shù)

            D3DXVECTOR3 * D3DXVer3Length(V) 向量模的計(jì)算

            D3DXVECTOR3 * D3DXVec3Normalize(返回指針,V) 單位化

            D3DXVECTOR3 * D3DXVec3Add(返回的指針,u,v) 向量加法

            D3DXVECTOR3 * D3DXVec3Subtract(同上) 減法

            D3DXVECTOR3 * D3DXVec3Cross(同上) 向量X乘

            D3DXVECTOR3 * D3DXVec3Lerp(同上) 數(shù)乘

            D3DXVECTOR3 * D3DXVec3Maximize(同上) 取最大值

            D3DXVECTOR3 * D3DXVec3Minimize(同上) 取最小值

            D3DXVECTOR3 * D3DXVec3Scale(返回指針,PV,F(xiàn)LOAT) 比例

            FLOAT D3DXVec3Dot(pv1,pv2) 點(diǎn)乘

            參見(jiàn)編程精粹.chm中的COM中模塊的導(dǎo)出函數(shù)

            Private Type D3DVECTOR

                x As Single

                y As Single

                z As Single

            End Type

            '返回3D向量的規(guī)格化向量

            Private Declare Function D3DXVec3Normalize Lib "DX8VB.DLL" Alias "VB_D3DXVec3Normalize" (VOut As D3DVECTOR, v As D3DVECTOR) As Long

            Private Declare Function D3DXVec3Add Lib "DX8VB.DLL" Alias "VB_D3DXVec3Add" (VOut As D3DVECTOR, v1 As D3DVECTOR, V2 As D3DVECTOR) As Long

            Private Declare Function D3DXVec3Subtract Lib "DX8VB.DLL" Alias "VB_D3DXVec3Subtract" (VOut As D3DVECTOR, v1 As D3DVECTOR, V2 As D3DVECTOR) As Long

            Private Declare Function D3DXVec3Length Lib "DX8VB.DLL" Alias "VB_D3DXVec3Length" (v As D3DVECTOR) As Single

            D3DFVF 自由頂點(diǎn)的格式

            D3DFVF_DIFFUSE 包含謾反射的信息

            D3DFVF_NORMAL 包含法線信息

            D3DFVF_PSIZE 頂點(diǎn)信息指明繪制點(diǎn)的大小

            D3DFVF_SPECULAR 包含鏡面反射的信息

            D3DFVF_XYZ 包含未經(jīng)轉(zhuǎn)換的頂點(diǎn)坐標(biāo)

            D3DFVF_XYZRHW 包含經(jīng)過(guò)轉(zhuǎn)換的頂點(diǎn)坐標(biāo)

            D3DFVF_XYZB1 through D3DFVF_XYZB5 包含用于骨骼動(dòng)化的頂點(diǎn)和頂點(diǎn)對(duì)骨骼的權(quán)重信息

            D3DFVF_XYZW 包含經(jīng)過(guò)轉(zhuǎn)換和裁剪的頂點(diǎn)坐標(biāo)

            D3DTRANSFORMSTATETYPE 變換的類型

            ­

            D3DPRIMITIVETYPE 定義基本圖元

            D3DPT_POINTLIST 一組點(diǎn)的集合

            D3DPT_LINELIST 一組線的集合

            D3DPT_LINESTRIP 首尾相連的線段的集合

            D3DPT_TRIANGLELIST 一組三角形的集合

            D3DPT_TRIANGLESTRIP 首尾相連的三角形,有兩個(gè)頂點(diǎn)集合

            D3DPT_TRIANGLEFAN   組成扇形的一組三角形集合

            D3DPT_FORCE_DWORD 未定義的

            D3DDISPLAYMODE 屏幕顯示模式

            D3DFMT_UNKNOWN  未知的象素格式

            D3DFMT_R8G8B8  24位色,RGB各占8位

            D3DFMT_A8R8G8B8  32位色,@RGB各占8位

            D3DFMT_X8R8G8B8  32位色,X為保留8位 RGB各占8位

            D3DFMT_R5G6B5  16位色,R占5,G占6,B占5位

            D3DFMT_X1R5G5B5  16位色,保留1位,RGB各占5位

            D3DFMT_A1R5G5B5  16位色,@占1位,RG5各占5位

            D3DFMT_A4R4G4B4  16位色,@RGB各占4位

            D3DFMT_R3G3B2  8位色,R3,G3,B2位

            D3DFMT_A8  只有8位@

            D3DFMT_A8R3G3B2  16位色,@8,R3,G3,B2位

            D3DFMT_X4R4G4B4  16位色

            D3DFMT_A2B10G10R10 32位色,@占2位,RGB各10位

            D3DFMT_A8B8G8R8  32位色

            D3DFMT_X8B8G8R8  32位色

            D3DFMT_G16R16  32位色,只有紅和綠

            D3DFMT_A2R10G10B10 32位色

            D3DFMT_A16B16G16R16 64位色

            D3DFMT_A8P8  8位色,8位表示半透明,8位表示顏色

            D3DFMT_P8  8位色,用牙色索引值表示

            D3DFMT_L8  8位色,只表示亮度

            D3DFMT_L16  16位色,只表示亮度

            D3DFMT_A8L8  16位色,8位表示半透明,8位表示亮度

            D3DFMT_A4L4  8位色,4位表示半透明,4位表示亮度

            D3DDEVTYPE_HAL   硬件抽象層,通過(guò)顯示硬件來(lái)完成圖形渲染工作

            D3DDEVTYPE_NULLREF  

            D3DDEVTYPE_REF   參考光柵器,一般用語(yǔ)測(cè)試顯示卡不支持的D3D功能

            D3DDEVTYPE_SW   用語(yǔ)支持第三方的軟件

            D3DDEVTYPE_FORCE_DWORD  擴(kuò)展的

            D3DCREATE 3D運(yùn)算的方式

            D3DCREATE_ADAPTERGROUP_DEVICE

            D3DCREATE_DISABLE_DRIVER_MANAGEMENT

            D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX

            D3DCREATE_FPU_PRESERVE   激活雙精度浮點(diǎn)運(yùn)算或浮點(diǎn)運(yùn)算異常檢測(cè),設(shè)置該項(xiàng)會(huì)降低系統(tǒng)性能

            D3DCREATE_HARDWARE_VERTEXPROCESSING 由D3D硬件進(jìn)行頂點(diǎn)預(yù)算

            D3DCREATE_MIXED_VERTEXPROCESSING 由混合方式進(jìn)行頂點(diǎn)運(yùn)算

            D3DCREATE_MULTITHREADED   支持多線程繪制,設(shè)置該項(xiàng)會(huì)降低系統(tǒng)性能

            D3DCREATE_NOWINDOWCHANGES  

            D3DCREATE_PUREDEVICE   禁用D3D的GET*()函數(shù),禁止D3D使用虛擬設(shè)備模擬頂點(diǎn)運(yùn)算

            D3DCREATE_SCREENSAVER  

            D3DCREATE_SOFTWARE_VERTEXPROCESSING 由D3D軟件進(jìn)行頂點(diǎn)運(yùn)算

            D3DSWAPEFFECT 取值列表

            D3DSWAPEFFECT_DISCARD    后臺(tái)緩沖區(qū)復(fù)制到前臺(tái)時(shí),清除后臺(tái)緩沖區(qū)內(nèi)容

            D3DSWAPEFFECT_FLIP    后臺(tái)緩沖區(qū)內(nèi)容復(fù)制后,保持不變,有多個(gè)后臺(tái)緩沖區(qū)時(shí)使用

            D3DSWAPEFFECT_COPY    后臺(tái)緩沖區(qū)內(nèi)容復(fù)制后,保持不變,只有1個(gè)后臺(tái)緩沖區(qū)時(shí)使用

            D3DSWAPEFFECT_FORCE_DWORD   強(qiáng)迫該直作為32位存儲(chǔ),通常不用

            D3DPRESENT 屏幕反轉(zhuǎn)模式列表

            D3DPRESENT_DONOTWAIT  

            D3DPRESENT_INTERVAL_DEFAULT 默認(rèn)的同ONE

            D3DPRESENT_INTERVAL_ONE  當(dāng)屏幕刷新一次時(shí)前臺(tái)后臺(tái)進(jìn)行交換

            D3DPRESENT_INTERVAL_TWO  當(dāng)屏幕刷新二次時(shí)前臺(tái)后臺(tái)進(jìn)行交換

            D3DPRESENT_INTERVAL_THREE 當(dāng)屏幕刷新三次時(shí)前臺(tái)后臺(tái)進(jìn)行交換

            D3DPRESENT_INTERVAL_FOUR 當(dāng)屏幕刷新四次時(shí)前臺(tái)后臺(tái)進(jìn)行交換

            D3DPRESENT_INTERVAL_IMMEDIATE 圖形繪制完成時(shí)立即進(jìn)行交換

            D3DPRESENT_LINEAR_CONTENT

            D3DUSAGE 緩沖區(qū)屬性值列表

            D3DUSAGE_AUTOGENMIPMAP  

            D3DUSAGE_DEPTHSTENCIL

            D3DUSAGE_DMAP  

            D3DUSAGE_DONOTCLIP 禁用裁剪,表示頂點(diǎn)緩沖區(qū)中的頂點(diǎn)不進(jìn)行裁剪,當(dāng)設(shè)置該屬性時(shí),渲染狀態(tài)D3DRS_CLIPPING必須設(shè)為FALSE

            D3DUSAGE_DYNAMIC 使用動(dòng)態(tài)內(nèi)存分配

            D3DUSAGE_NPATCHES 使用頂點(diǎn)緩沖區(qū)繪制N-patches曲線

            D3DUSAGE_POINTS  使用頂點(diǎn)緩沖區(qū)繪制點(diǎn)

            D3DUSAGE_RENDERTARGET

            D3DUSAGE_RTPATCHES 使用頂點(diǎn)緩沖區(qū)繪制曲線

            D3DUSAGE_SOFTWAREPROCESSING 使用軟件進(jìn)行頂點(diǎn)運(yùn)算,否則使用硬件計(jì)算

            D3DUSAGE_WRITEONLY 只寫(xiě)屬性,不能進(jìn)行讀操作,設(shè)置該屬性可以提高系統(tǒng)性能

            D3DPOOL  緩沖區(qū)資源內(nèi)存位置列表

            D3DPOOL_DEFAULT  默認(rèn)的,頂點(diǎn)緩沖區(qū)盡可能存在與顯存中

            D3DPOOL_MANAGED  由D3D自動(dòng)調(diào)度頂點(diǎn)緩沖區(qū)內(nèi)存位置(顯存和內(nèi)存)

            D3DPOOL_SCRATCH  頂點(diǎn)緩沖區(qū)位于計(jì)算機(jī)的臨時(shí)內(nèi)存中,這種類型的頂點(diǎn)緩沖區(qū)不能直接進(jìn)行渲染,只能進(jìn)行內(nèi)存枷鎖,拷貝等操作

            D3DPOOL_SYSTEMMEM 頂點(diǎn)緩沖區(qū)位于內(nèi)存中

            D3DLOCK  緩沖區(qū)加鎖

            D3DLOCK_DISCARD  更新整個(gè)緩沖區(qū)

            D3DLOCK_DONOTWAIT

            D3DLOCK_NO_DIRTY_UPDATE 在加鎖的過(guò)程中系統(tǒng)進(jìn)行其他操作(默認(rèn)有Dirty標(biāo)記)

            D3DLOCK_NOOVERWRITE 保證不腹稿緩沖區(qū)數(shù)據(jù),設(shè)置該屬性可以立即返回內(nèi)存指針,提高系統(tǒng)性能

            D3DLOCK_NOSYSLOCK 在加鎖的過(guò)程中系統(tǒng)可能執(zhí)行其他操作

            D3DLOCK_READONLY 設(shè)置緩沖區(qū)位只讀屬性

            D3DXVECTOR3 向量算法

            D3DXVECTOR3u(x,y,z);

            D3DXVECTOR3v(x,y,z);

            float 變量=D3DXVec3Dot(u指針,v指針) 點(diǎn)乘

            D3DXMATRIX 矩陣

            D3DXMatrixIdentity 單位矩陣

            D3DXMatrixInverse 逆矩陣

            D3D實(shí)現(xiàn)圖形變換

            D3DXMatrixTranslation 平移矩陣

            D3DXMatrixLockAtLH 觀察矩陣

            D3DXMatrixIdentity  將一個(gè)矩陣單位化

            D3DXMatrixRotationY 繞Y軸轉(zhuǎn)

            D3DXMatrixRotationX 繞X軸轉(zhuǎn)

            D3DXMatrixRotationZ 繞Z軸轉(zhuǎn)

            D3DXMatrixScaling 縮放變換

            D3DXMatrixMuLationAxis 圍繞任意一個(gè)軸旋轉(zhuǎn)

            D3DXMatrixMultiply 組合變換

            D3DUSAGE 紋理使用

            D3DUSAGE_AUTOGENMIPMAP 自動(dòng)生成多級(jí)漸進(jìn)紋理序列,該方式在資源處于D3DPOOL_SYSTEMMEM時(shí)無(wú)效

            D3DUSAGE_DEPTHSTENCIL 深度模版緩沖區(qū),只在資源處于D3DPOOL_default時(shí)有效

            D3DUSAGE_DMAP  該紋理是一個(gè)置換紋理

            D3DUSAGE_DONOTCLIP

            D3DUSAGE_DYNAMIC

            D3DUSAGE_NPATCHES

            D3DUSAGE_POINTS

            D3DUSAGE_RENDERTARGET 該文理是一個(gè)渲染目標(biāo)緩沖區(qū)

            D3DUSAGE_RTPATCHES

            D3DUSAGE_SOFTWAREPROCESSING 應(yīng)用坐標(biāo)變換

            D3DUSAGE_WRITEONLY

            D3DTEXTURESTAGESTATETYPE 渲染狀態(tài)類型

            D3DTSS_COLOROP   1 文理層的顏色混合方式

            D3DTSS_COLORARG1  2 顏色混合的第一個(gè)參數(shù)

            D3DTSS_COLORARG2  3 顏色混合的第二個(gè)參數(shù)

            D3DTSS_ALPHAOP   4 指定紋理層的Alpha透明

            D3DTSS_ALPHAARG1  5 Alpha混合的第一個(gè)參數(shù)

            D3DTSS_ALPHAARG2  6 Alpha混合的第二個(gè)參數(shù)

            D3DTSS_BUMPENVMAT00  7 繪制凹凸紋理時(shí)

            D3DTSS_BUMPENVMAT01  8 繪制凹凸紋理時(shí)

            D3DTSS_BUMPENVMAT10  9 繪制凹凸紋理時(shí)

            D3DTSS_BUMPENVMAT11  10 繪制凹凸紋理時(shí)

            D3DTSS_TEXCOORDINDEX  11 該紋理層使用的紋理坐標(biāo)的索引

            D3DTSS_BUMPENVLSCALE  22 繪制凹凸紋理的縮放參數(shù)

            D3DTSS_BUMPENVLOFFSET   23 繪制凹凸紋理的平移參數(shù)

            D3DTSS_TEXTURETRANSFORMFLAGS  24 控制紋理坐標(biāo)的轉(zhuǎn)換標(biāo)志

            D3DTSS_COLORARG0  26 指定混合過(guò)程的第三個(gè)顏色

            D3DTSS_ALPHAARG0  27 Alpha混合的第三個(gè)參數(shù)

            D3DTSS_RESULTARG  28 顏色混合的結(jié)果輸出寄存器

            D3DTSS_CONSTANT  32 顏色混合的常量寄存器

            D3DTSS_FORCE_DWORD  0x7fffffff 強(qiáng)制轉(zhuǎn)換為32位,通常不用

            D3DSAMPLERSTATETYPE 紋理采樣屬性

            D3DSAMP_ADDRESSU  1 包裝紋理

            D3DSAMP_ADDRESSV  2 包裝紋理

            D3DSAMP_ADDRESSW  3 包裝紋理

            D3DSAMP_BORDERCOLOR  4

            D3DSAMP_MAGFILTER  5 處理放大過(guò)濾

            D3DSAMP_MINFILTER  6 處理縮小過(guò)濾

            D3DSAMP_MIPFILTER  7 多紋理過(guò)濾

            D3DSAMP_MIPMAPLODBIAS  8 多級(jí)文理級(jí)數(shù)偏移值,初試直為0

            D3DSAMP_MAXMIPLEVEL  9 最大多紋理級(jí)別,初試值為0

            D3DSAMP_MAXANISOTROPY  10 各向異性,初試值為1

            D3DSAMP_SRGBTEXTURE  11

            D3DSAMP_ELEMENTINDEX   12

            D3DSAMP_DMAPOFFSET  13

            D3DSAMP_FORCE_DWORD  0x7fffffff 強(qiáng)制轉(zhuǎn)換32位,通常不用

            紋理尋址

            D3DTADDRESS_WRAP  1 包裝紋理尋址

            D3DTADDRESS_MIRROR  2 鏡像紋理尋址

            D3DTADDRESS_CLAMP  3 夾取紋理尋址

            D3DTADDRESS_BORDER  4 邊框顏色紋理尋址

            D3DTADDRESS_MIRRORONCE  5 一次鏡像紋理尋址

            D3DTADDRESS_FORCE_DWORD 0x7fffffff強(qiáng)制轉(zhuǎn)換32位,通常不用

            世界變換

            D3DTS_WORLD  世界變換

            posted @ 2009-09-17 07:55 RedLight 閱讀(3704) | 評(píng)論 (0)編輯 收藏

            D3d9的一些更新 (轉(zhuǎn))

            由于Aug 8造成的D3D9恐懼癥已經(jīng)完全消除了,這一章將會(huì)給大家介紹將3D引擎轉(zhuǎn)向D3D9的各個(gè)方面,包括終于出現(xiàn)的全屏幕模式。從這章以后,我將使用D3D9作為講解的語(yǔ)言繼續(xù)D2D教程。

            【OP結(jié)束,開(kāi)始正片】

            『Why?』

              估計(jì)大家首先要問(wèn)的就是“Why?”為什么要前進(jìn)到D3D9?理由如下:
            1、D3D9修復(fù)了D3D8已知的所有Bug,因此運(yùn)行起來(lái)更穩(wěn)定,速度也要快。
            2、D3D9提供了許多便利的新功能,雖然絕大多數(shù)是面向3D的,但是也有不少2D適用的,比如IDirect3DDevice9::StretchRect,以及對(duì)IDirect3DSurface9的改進(jìn)等等。D3DX庫(kù)就更多了,比如D3DXSaveSurfaceToFileInMemory,一開(kāi)始沒(méi)發(fā)現(xiàn)這個(gè)函數(shù)有啥用處,現(xiàn)在基本離不開(kāi)了。
            3、HLSL。就像上一話我說(shuō)的那樣,D2D教程以后會(huì)有PixelShader的內(nèi)容。我可不想拿匯編來(lái)寫(xiě)Shader,會(huì)死人的(祝賀我吧,終于拋棄匯編Shader了……)。雖然說(shuō)這不是決定性的理由,因?yàn)檫€有Cg什么的,不過(guò)我想編寫(xiě)顯卡無(wú)關(guān)的代碼,因此我不去研究Cg(反正和HLSL差不多)以及R2VB之類。
            4、ID3DXFont,往下看你就知道了。

            《D3D的變化》

            『界面名稱變化』

              一句話:8改成9就行。

            『“創(chuàng)建”型方法的一個(gè)統(tǒng)一變化』

              許多Create*()方法,比如創(chuàng)建設(shè)備、創(chuàng)建紋理、創(chuàng)建頂點(diǎn)緩沖等等,多了一個(gè)HANDLE* pSharedHandle參數(shù),無(wú)用,NULL之(看來(lái)微軟原打算弄個(gè)共享句柄之類,不過(guò)被D3D10巨大的變化浮云了)

            『創(chuàng)建D3D設(shè)備的變化』

              D3DPRESENT_PARAMS的FullScreen_PresentationInterval變成了PresentationInterval,也就是說(shuō)即使在窗口模式下也可以做到垂直同步來(lái)防止撕裂現(xiàn)象(2D的福音?。?。相應(yīng)的,D3DSWAPEFFECT_COPY_VSYNC消失了,反正這個(gè)效果也不咋的,消失了也好。
              要做到垂直同步需要給PresentationInterval賦值D3DPRESENT_INTERVAL_DEFAULT或D3DPRESENT_INTERVAL_ONE。其中D3DPRESENT_INTERVAL_ONE的效果比D3DPRESENT_INTERVAL_DEFAULT好一點(diǎn),不過(guò)相應(yīng)的也會(huì)占用多一點(diǎn)點(diǎn)系統(tǒng)資源……真的只有一點(diǎn)點(diǎn)而已,實(shí)在是無(wú)所謂的……
              如果不要垂直同步,想要看看實(shí)際禎速的話,D3DPRESENT_INTERVAL_IMMEDIATE。
              注意在窗口模式下,你只能使用這三種Present模式,全屏幕模式下就可以使用別的(但是要首先檢測(cè)D3DCAPS9以查看顯卡是否支持)。不過(guò)我感覺(jué)對(duì)99%的游戲來(lái)說(shuō),有這三個(gè)就足夠了。
              另外在窗口模式下,BackBufferFormat也可以設(shè)置成D3DFMT_UNKNOWN,D3D會(huì)自動(dòng)獲取當(dāng)前桌面的格式設(shè)定成后備緩沖的格式,省去GetDisplayMode。實(shí)際上,窗口模式下的后備緩沖已經(jīng)不需要和桌面格式相同,你可以通過(guò)IDirect3D9::CheckDeviceFormatConversion來(lái)檢查,如果這個(gè)設(shè)備支持這兩種顏色格式之間的轉(zhuǎn)換,就可以給程序的后備緩沖設(shè)定上不同的格式。我試過(guò)在桌面格式為32Bit(D3DFMT_X8R8G8B8)時(shí)將程序的后備緩沖格式設(shè)置為D3DFMT_R5G6B5(16Bit),發(fā)現(xiàn)了速度提升,也就是說(shuō)這個(gè)設(shè)定是有意義的。
              可創(chuàng)建的設(shè)備類型多了一種D3DDEVTYPE_NULLREF,在安裝了D3D SDK的機(jī)子上等同于D3DDEYTYPE_REF,在其他的機(jī)子上,這種設(shè)備實(shí)際上沒(méi)有創(chuàng)建真正意義的D3D設(shè)備,只是允許你創(chuàng)建的紋理、表面等資源,但是Render、Present等操作都會(huì)無(wú)效(實(shí)際上這些資源都創(chuàng)建在了D3DPOOL_SCRATCH池里,不管你設(shè)定使用的是什么POOL)。也就是說(shuō),僅僅在模擬基本的運(yùn)行而已。你可以用這個(gè)設(shè)備來(lái)編寫(xiě)一個(gè)利用D3DX函數(shù)庫(kù)進(jìn)行圖像格式轉(zhuǎn)換的程序,比如把一大堆不同的格式轉(zhuǎn)換成易于D3D9使用的DDS格式。因?yàn)閷?shí)際上沒(méi)有創(chuàng)建設(shè)備,你甚至可以編寫(xiě)成控制臺(tái)的,通過(guò)GetConsoleWindow的方法獲得HWND。Mercury 3用的MIF格式的轉(zhuǎn)換器就是這么做出來(lái)的。注意D3DDEVTYPE_NULLREF只能用在IDirect3D::CreateDevice時(shí),其他的方法都不行。

            『創(chuàng)建表面的變化』

              創(chuàng)建表面(Surface)的方法變成了IDirect3DDevice9::CreateOffscreenPlainSurface,參數(shù)很簡(jiǎn)單不用多說(shuō),需要注意的是可以選擇POOL了。

            『設(shè)定FVF的變化』

              設(shè)定FVF時(shí),原來(lái)通過(guò)IDirect3DDevice8::SetVertexShader,現(xiàn)在有了一個(gè)專門(mén)用來(lái)設(shè)定FVF的方法:IDirect3DDevice9::SetFVF。這是個(gè)很好的變化,省得把FVF和Shader弄混(題外話:也就是因?yàn)檫@個(gè)變化,讓Shader在設(shè)備Reset后得以保存,不錯(cuò)不錯(cuò))

            『獲取后備緩沖』

              D3D9現(xiàn)在允許有多個(gè)后備緩沖交換鏈,不過(guò)對(duì)于2D來(lái)說(shuō),基本不需要這種東西,IDirect3DDevice9::GetBackBuffer多出來(lái)的第一個(gè)參數(shù)賦值0即可。如果你有興趣,可以去研究一下這個(gè)玩意,有時(shí)候可以用來(lái)做分場(chǎng)。

            SetStreamSource』

              這個(gè)方法的功能被擴(kuò)展了,對(duì)比參數(shù)就可以知道,多出來(lái)的OffsetInBytes允許你選擇一個(gè)頂點(diǎn)緩沖的Offset,D3D9將從這個(gè)Offset之后開(kāi)始讀取數(shù)據(jù)。因此你可以把幾組用來(lái)渲染紋理的正方形頂點(diǎn)存儲(chǔ)到一個(gè)頂點(diǎn)緩沖里面。

            SetSamplerState』

              這個(gè)是D3D9的新方法,把原先SetTextureStageState的一些功能獨(dú)立了出來(lái),和2D關(guān)系最密切的就是紋理過(guò)濾了。原先的D3DTSS_MINFILTER變成了D3DSAMP_MINFILTER,相應(yīng)的D3DTSS_MAGFILTER也變成D3DSAMP_MAGFILTER,D3DTSS_MAXANISOTROPY變成D3DSAMP_MAXANISOTROPY。另外還有更多的,比如紋理尋址等。你去看一下D3DSAMPLERSTATETYPE枚舉類型的內(nèi)容就知道它“遷移”了些什么。
              這個(gè)變化對(duì)于Shader來(lái)說(shuō)很方便。改成Sampler的東西在PixelShader過(guò)程也會(huì)有效,而沒(méi)有更改的東西在PixelShader就不會(huì)有效了。D3D8時(shí)候把這些全都放在了一起,容易造成混亂。

            SetRenderTarget』

              D3D9現(xiàn)在允許多重RenderTarget存在,不過(guò)我們基本上只用一個(gè),RenderTargetIndex設(shè)為0,第二個(gè)參數(shù)仍然是需要設(shè)定的表面。與D3D8相同的是,在設(shè)定之前仍然需要先通過(guò)GetSurfaceLevel獲得表面才行。

            『頂點(diǎn)緩沖的鎖定』

              注意IDirect3DVertexBuffer9::Lock的第三個(gè)參數(shù),從原來(lái)的BYTE**變成了void**。也就是這樣了……

            『其他的一些變化』

            1、CopyRects變成了UpdateSurface。和UpdateTexture一樣,只能從D3DPOOL_SYSTEMMEM拷貝到D3DPOOL_DEFAULT
            2、增加了一個(gè)比較有用的IDirect3DDevice9::ColorFill方法,作用是向D3DPOOL_DEFAULT的某個(gè)區(qū)域填充顏色,和Clear的功能類似,但是在使用目的上要比Clear明確的多,并且由于不牽扯深度緩沖之類,速度要快一些。
            3、增加了一個(gè)IDirect3DDevice9::StretchRect方法,通過(guò)這個(gè)方法就可以在D3DPOOL_DEFAULT的表面或紋理之間進(jìn)行帶過(guò)濾器的縮放操作,免去利用Render的過(guò)程,非常有用。不過(guò)這個(gè)方法由于使用了硬件處理,限制較多,請(qǐng)大家仔細(xì)看SDK文檔的Remarks部分。

            《D3DX的變化》

              D3DX的變化實(shí)際上相當(dāng)?shù)亩?,但正如我一開(kāi)始所說(shuō),基本都是面向3D的。需要我們注意的有以下幾種:
            1、D3DX***FromFile之類的函數(shù)支持的圖像格式增加了,不過(guò)所增加的都是很少見(jiàn)的格式。平時(shí)基本上還是用BMP、TGA和PNG就足夠。
            2、增加了D3DXSave***ToFileInMemory,將會(huì)把文件寫(xiě)入內(nèi)存。這個(gè)函數(shù)的作用似乎不是很容易想到,但是如果你要寫(xiě)一個(gè)集成了轉(zhuǎn)換、打包功能的工具,這個(gè)就很有用了,省去了通過(guò)臨時(shí)文件操作造成的各種問(wèn)題。另外如果你熟悉某種圖形文件的格式的話,還可以通過(guò)直接訪問(wèn)這個(gè)文件獲得RAW信息。注意,這類函數(shù)寫(xiě)入的是一個(gè)ID3DXBuffer,這個(gè)東西很簡(jiǎn)單,只有兩個(gè)特定的方法,一看便懂,不再多言。
            3、增加了一個(gè)ID3DXLine,可以方便你在2D上畫(huà)線,創(chuàng)建ID3DXLine的方法是D3DXCreateLine。這個(gè)東西也不復(fù)雜,使用方法有點(diǎn)像ID3DXSprite,稍微研究一下就能弄懂,注意每次Draw的是D3DPT_LINESTRIP。用它比直接用頂點(diǎn)緩沖的好處是可以方便的打開(kāi)反鋸齒,效果嘛……基本滿意。
            4、增加了一個(gè)ID3DXRenderToSurface,“理論上來(lái)說(shuō)”方便了利用RenderTarget的過(guò)程……不過(guò)我感覺(jué)反而弄得復(fù)雜了。創(chuàng)建的方法是D3DXCreateRenderToSurface,有心情的朋友自己研究看看吧,我就不講了。

              ID3DXSprite和ID3DXFont在Summer 2004的DX9 SDK(也就是第一版DX9.0c)開(kāi)始發(fā)生了很大變化,下面詳述:

            『ID3DXSprite』

              你會(huì)發(fā)現(xiàn)ID3DXSprite::DrawTransform不見(jiàn)了,取而代之的是其功能被整合到ID3DXSprite::SetTransform里面,也就是說(shuō)為了縮放和旋轉(zhuǎn),我們不得不和矩陣打交道了。其實(shí)也不會(huì)太復(fù)雜,因?yàn)槲覀冎皇亲鲆恍┚仃囘\(yùn)算,學(xué)過(guò)線性代數(shù)的朋友肯定會(huì)很熟悉,就算你不怎么熟悉線性代數(shù),也沒(méi)關(guān)系,D3DX函數(shù)庫(kù)提供了現(xiàn)成的矩陣運(yùn)算函數(shù),你只要用就行了。

            D3DXMatrixScaling
            D3DXMatrixRotationZ
            D3DXMatrixTranslation

              按照順序調(diào)用這三個(gè)函數(shù)……或許學(xué)過(guò)3D的馬上就想到這點(diǎn)了,的確是沒(méi)錯(cuò)啦。注意順序哦:Scaling -> Rotation -> Translation,簡(jiǎn)稱SRT(看過(guò)全金屬狂潮嗎?看過(guò)的話這個(gè)單詞很好記吧^_^),弄錯(cuò)了可是得不到正確結(jié)果的。
              你是不是想到把同一個(gè)D3DXMATRIX當(dāng)作參數(shù)使用三次?錯(cuò)啦!你要用矩陣乘法。創(chuàng)建三個(gè)D3DXMATRIX,比如mat1、mat2、mat3,分別用這三個(gè)函數(shù)將其創(chuàng)建為縮放矩陣、旋轉(zhuǎn)矩陣和平移矩陣,然后在ID3DXSprite::SetTransform時(shí),這樣寫(xiě):

            SetTransform(mat1 * mat2 * mat3);

              有夠麻煩的是不?ID3DXSprite方便了做3D的,可害苦了做2D的,所以我已經(jīng)不直接用這個(gè)了(什么叫不直接用?往下看)。

            『ID3DXFont』

              大家來(lái)歡呼吧!Summer 2004改進(jìn)的ID3DXFont徹底槍斃掉了上一話那個(gè)字體引擎……
              這東西的改進(jìn),怎么說(shuō)呢,應(yīng)該說(shuō)是改頭換面吧,速度、效果都和以前不是一個(gè)數(shù)量級(jí)??蓱z的PixelFont,才存在了一話就要被拋棄了。
              ID3DXFont多出來(lái)的幾個(gè)方法,Preload*()這類的,就是把一些常用的字的字模提前讀取到內(nèi)存里面加快速度,同時(shí)還可以使用ID3DXSprite渲染,進(jìn)一步加快速度。雖然內(nèi)部仍然有GDI的部分,不過(guò)很明顯工作方式發(fā)生了極大的變化。根據(jù)我的估計(jì),這次的ID3DXFont很聰明的利用GDI獲得文字的輪廓,然后通過(guò)紋理來(lái)渲染。這樣的速度就快得多了,而且文字質(zhì)量也得到了很好的控制,基本和直接用GDI的質(zhì)量相同了。
              由于PreloadCharacters()和PreloadGlyphs()不是那么好理解,一般用PreloadText()就行。建議將所有ASCII字符、標(biāo)點(diǎn)符號(hào)和部分漢字預(yù)讀進(jìn)去。這個(gè)預(yù)讀過(guò)程略微有點(diǎn)慢,而且根據(jù)預(yù)讀的文字?jǐn)?shù)量和你創(chuàng)建文字的字號(hào),占用的內(nèi)存也不同。這里給大家一堆文字,你Copy過(guò)去就行:

            引用

            const char strPreloadText[] = " 1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM~!@#$%^&*()-=[]\\;',./_+{}|:\"<>? 、。·ˉˇ¨〃—~‖…‘’“”〔〕〈〉《》「」『』〖〗【】!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}我人有的和主產(chǎn)不為這工要在第一上是中國(guó)經(jīng)已發(fā)了民同";

              注意第一個(gè)字符是空格哦!把空格預(yù)讀進(jìn)去可是很重要的^_^
              看上去并不多,因?yàn)橐紤]到內(nèi)存占用及速度,我只預(yù)讀了一些符號(hào)和五筆的一鍵字。這些字符在24號(hào)字時(shí)候已經(jīng)占用了快1MB了,比起PixelFont字庫(kù)占用的要大得多。天知道ID3DXFont到底預(yù)讀了些什么……
              PreloadText()的第二個(gè)參數(shù)不要用strlen,sizeof(strPreloadText)即可。
              然后就是利用ID3DXSprite來(lái)渲染。注意ID3DXFont::DrawText的第一個(gè)參數(shù)就是LPD3DXSPRITE,因此如果要利用ID3DXSprite,要將ID3DXFont::DrawText放到ID3DXSprite::Begin和ID3DXSprite::End之間。這就是我剛才說(shuō)的不直接用ID3DXSprite的意思,ID3DXFont會(huì)完成ID3DXSprite的全部調(diào)用,你不用擔(dān)心。
              另外你應(yīng)該注意到ID3DXSprite::Begin增加了參數(shù),實(shí)際上DX文檔里面沒(méi)說(shuō),但是示例里面有,如果想讓ID3DXSprite發(fā)揮作用并且最大幅度的提升效率,參數(shù)上設(shè)定D3DXSPRITE_ALPHABLEND | D3DXSPRITE_SORT_TEXTURE即可。意思很明白:打開(kāi)Alpha過(guò)濾和紋理篩選。這里DX文檔上有個(gè)錯(cuò)誤一直沒(méi)改:文檔里給出的是D3DXSprite__SORT_TEXTURE,但是你可以試試,絕對(duì)報(bào)錯(cuò)。
              剩下的就沒(méi)啥了,ID3DXFont的使用方法上一話已經(jīng)講過(guò)。要注意的是D3DXCreateFont和D3DXCreateFontIndirect都發(fā)生了變化。D3DXCreateFont已經(jīng)不再牽扯GDI了,D3DXCreateFontIndirect所使用的結(jié)構(gòu)也變成了D3DXFONT_DESC,相對(duì)于LOGFONT結(jié)構(gòu),除去了一些用不著的參數(shù),增加了一個(gè)MipLevels,就是MipMap等級(jí)啦,不用多說(shuō),2D下只用1。其他的上一話都有。實(shí)際上由于D3DXCreateFont已經(jīng)不再關(guān)聯(lián)GDI,D3DXCreateFontIndirect的存在僅僅是由于歷史原因(為了兼容像我這種人的使用習(xí)慣),大家還是用D3DXCreateFont吧,省事。
              截圖就不貼了,沒(méi)啥意義。你可能覺(jué)得直接向后備緩沖上DrawText還不夠好看,那么就先畫(huà)到一張紋理上,然后將紋理錯(cuò)位渲染到后備緩沖并且打開(kāi)線型過(guò)濾,就可以達(dá)到和PixelFont相同的效果了。
              速度嘛……我畫(huà)了整整一屏幕字,在不緩沖文字的情況下(這個(gè)“緩沖文字”和ID3DXFont的文字緩沖可不是一回事啊!看過(guò)上一話的都應(yīng)該知道我這里指的是什么),速度仍然在120FPS以上?;蛟S你會(huì)覺(jué)得速度還是有點(diǎn)慢,但是,如果用D3D8的ID3DXFont畫(huà)上這么一屏幕,基本就只剩20FPS了。
              使用ID3DXFont替換掉PixelFont的優(yōu)勢(shì)就是可以方便的自定義字體字號(hào)了,并且也不再受GB2312字庫(kù)的限制。所以大家都換了吧……都換了吧……把PixelFont忘了吧……

            『穩(wěn)定的DX9 SDK版本』

              我現(xiàn)在用的是April 2006,而且應(yīng)該會(huì)用很長(zhǎng)時(shí)間。August 2006我是肯定不會(huì)去用啦!即使我不再恐懼D3D9,也會(huì)對(duì)這個(gè)SDK避讓三分的。其實(shí)對(duì)于2D,我感覺(jué)用到April 2006就足夠了,之后的DX9 SDK主要在D3DX的3D函數(shù)庫(kù)部分進(jìn)行更改……其實(shí)也是秋后的螞蚱蹦達(dá)不了幾天,D3D10馬上就要出來(lái)了。要說(shuō)D3D10啊……你還是看我另外一篇日志好了,總之打死我都不拿它做2D。

              實(shí)際上僅僅是2D的話,從D3D8轉(zhuǎn)向D3D9并沒(méi)有多少變化,主要是穩(wěn)定嘛!只要你不調(diào)用一些D3D9專用的功能,即使拿D3D9來(lái)做2D,在絕大多數(shù)顯卡上還是能夠運(yùn)行的。嗯……GF2等級(jí)以上吧,GF2之前的,也太老了,無(wú)視好了。

            《再上點(diǎn)菜好了:全屏幕模式》

              其實(shí)并不是多么復(fù)雜的問(wèn)題,讓我拖了這么久……不拖了,這里就教給大家如何做全屏幕模式以及如何處理設(shè)備丟失的問(wèn)題。

            『創(chuàng)建全屏幕模式』

              D3DPRESENT_PARAMS里面,Windowed設(shè)定為false,并且一定要設(shè)定BackBufferWidth和BackBufferHeight,完畢。
              哈哈,就這么簡(jiǎn)單,或許早就有人嘗試過(guò)了,但是你試試按下Alt+Tab,再切換回去,保證你什么都看不到。
              之前曾經(jīng)說(shuō)過(guò),DX8之前的版本,在全屏幕下工作比在窗口下容易,到DX8之后就則完全顛倒過(guò)來(lái)。因?yàn)樵诖翱谀J较虏挥脫?dān)心設(shè)備丟失(除非你更改桌面分辨率),全屏幕模式下就會(huì)有這個(gè)問(wèn)題了。下面詳述:

            『設(shè)備、資源丟失』

              設(shè)備丟失會(huì)發(fā)生在全屏幕模式下切換回桌面時(shí)(不論是通過(guò)Alt+Tab還是QQ上有人給你發(fā)了張圖片-_-bbb),而且如果在調(diào)用IDirect3DDevice9::Reset(從現(xiàn)在開(kāi)始就是D3D9了啊!忘記D3D8吧……)的時(shí)候發(fā)生錯(cuò)誤,設(shè)備也會(huì)丟失。
              設(shè)備丟失會(huì)造成資源丟失:所有創(chuàng)建在D3DPOOL_DEFAULT池的資源都會(huì)丟失,需要重新創(chuàng)建,其內(nèi)容當(dāng)然也會(huì)消失,需要重寫(xiě)。
              然而創(chuàng)建在D3DPOOL_SYSTEMMEM和D3DPOOL_SCRATCH池的資源不會(huì)受到影響。創(chuàng)建在D3DPOOL_MANAGED池的資源也不會(huì)丟失,而且在設(shè)備重新可用的時(shí)候,D3DPOOL_MANAGED池的資源也可以立即投入使用,內(nèi)容也不會(huì)改變。看這個(gè)池名字:托管池就能知道,D3D幫你處理了所有問(wèn)題。
              因此避免設(shè)備丟失后資源丟失的簡(jiǎn)易方法就是將所有資源創(chuàng)建在D3DPOOL_MANAGED池內(nèi)。不過(guò)這并不是個(gè)好方法,這意味著不能用渲染對(duì)象——記得嗎?RenderTarget只能創(chuàng)建在D3DPOOL_DEFAULT。實(shí)際上最好的方法是跟蹤所有D3DPOOL_DEFAULT資源,比如利用std::list,將所有D3DPOOL_DEFAULT資源勾住,在設(shè)備發(fā)生丟失的時(shí)候釋放掉資源,設(shè)備可以繼續(xù)使用的時(shí)候重新創(chuàng)建資源,記得把數(shù)據(jù)寫(xiě)回去。對(duì)于其他的池就不用這么折騰了。

            『當(dāng)設(shè)備丟失之后』

              不論通過(guò)任何方式發(fā)生了設(shè)備丟失,所有的操作幾乎都會(huì)失效,只有Release()可以用——其實(shí)D3D會(huì)保證有部分操作可以成功,但是也僅僅是“可以”成功而不是“一定”成功,所以你還不如認(rèn)定丟失的時(shí)候全都會(huì)失敗比較好——以及IDirect3DDevice9::TestCooperativeLevel。因此在設(shè)備丟失之后,你應(yīng)該停止整個(gè)游戲循環(huán),而通過(guò)反復(fù)調(diào)用IDirect3DDevice9::TestCooperativeLevel判斷設(shè)備是否可用。

            『IDirect3DDevice9::TestCooperativeLevel』

              這個(gè)方法檢測(cè)當(dāng)前的設(shè)備狀態(tài)。返回值有四種:D3D_OK一切正常,D3DERR_DEVICELOST設(shè)備丟失,D3DERR_DEVICENOTRESET設(shè)備可以Reset。另外還有D3D9新增的D3DERR_DRIVERINTERNALERROR,遇到這個(gè)你就完蛋了,基本不可能恢復(fù)了,終止程序吧。
              按照順序來(lái)講,如果游戲在正常運(yùn)行,D3D_OK會(huì)返回;如果發(fā)生了設(shè)備丟失并且在這個(gè)時(shí)候不能恢復(fù),比如全屏幕模式的時(shí)候用戶切換到了Windows桌面,就會(huì)返回D3DERR_DEVICELOST;如果用戶又切換回了游戲,設(shè)備可以恢復(fù)了(還沒(méi)恢復(fù)呢!只是“可以”恢復(fù)而已),就會(huì)返回D3DERR_DEVICENOTRESET。
              另外,IDirect3DDevice9::Present也會(huì)返回類似的值,不過(guò)你最好別指望這個(gè),老老實(shí)實(shí)的用TestCooperativeLevel。因?yàn)镻resent在設(shè)備可以恢復(fù)的時(shí)候還是返回D3DERR_DEVICELOST(外一句:D3D10的時(shí)候TestCooperativeLevel就會(huì)完全整合到Present里面了,可喜可賀可喜可賀)

            『處理設(shè)備丟失』

              看下面的偽代碼:

            switch (IDirect3DDevice9::TestCooperativeLevel()){
              case D3D_OK:
                GameLoop();
                break;
              case D3DERR_DEVICELOST:
                break;
              case D3DERR_DEVICENOTRESET
                OnLostDevice();
                IDirect3DDevice9::Reset();
                OnResetDevice();
                break;
              default:
                QuitGame();
                break;
            }

              GameLoop()就是你的游戲運(yùn)行的過(guò)程了。把這個(gè)switch寫(xiě)在我們游戲框架的GameMain()部分,具體的位置可以看任何一話附帶的源代碼。
              好像我一直沒(méi)有講IDirect3DDevice9::Reset的參數(shù)啊?因?yàn)橹挥幸粋€(gè)參數(shù),就是指向D3DPRESENT_PARAMS的指針。把你第一次創(chuàng)建設(shè)備時(shí)使用的D3DPRESENT_PARAMS結(jié)構(gòu)保存起來(lái),供Reset來(lái)用。
              OnLostDevice()就是Release掉所有D3DPOOL_DEFAULT的資源,OnResetDevice()就是Create*()恢復(fù)啦!你可能注意到ID3DXFont、ID3DXSprite等等都有同名的方法,就是在這個(gè)時(shí)候調(diào)用的。如果你沒(méi)有這么做,也就是說(shuō)還保留著任何D3DPOOL_DEFAULT的資源的話,IDirect3DDevice9::Reset就一定會(huì)失敗。
              另外在OnResetDevice里面你還要重新進(jìn)行SetRenderState、SetSamplerState等等,Reset之后這些東西也丟失了。實(shí)際上Reset和重新創(chuàng)建一次設(shè)備類似,所不同的是重新創(chuàng)建設(shè)備的話你需要連D3DPOOL_MANAGED的資源也Release掉。這個(gè)話題就不討論了。
              從代碼可以看出來(lái),D3DERR_DEVICELOST時(shí)程序什么都沒(méi)做,只是在傻等。我認(rèn)為這是一個(gè)好習(xí)慣,因?yàn)閷?shí)在不能保證在D3DERR_DEVICELOST時(shí)除了Release還能干什么,與其這樣還不如等設(shè)備能用了再說(shuō)。

              實(shí)在懶得管資源的話,全部D3DPOOL_MANAGED好了。至于渲染對(duì)象?自己想辦法。

            『人工制造“設(shè)備丟失”』

              “干嘛還要制造設(shè)備丟失?。?#8221;如果更改游戲分辨率、色深、切換全屏幕及窗口狀態(tài),進(jìn)行這樣的操作也要通過(guò)Reset,同樣的,Reset之前也要釋放掉所有D3DPOOL_DEFAULT資源(其實(shí)嚴(yán)格來(lái)說(shuō),還有更多的資源也要釋放,不過(guò)在2D下基本不會(huì)創(chuàng)建這類資源,你就不用管了)并且調(diào)用ID3DXSprite::OnLostDevice之類的方法。這就是人工制造“設(shè)備丟失”了。實(shí)際上在這個(gè)過(guò)程設(shè)備并沒(méi)有真正的丟失,只是會(huì)有一段時(shí)間處于不可用的狀態(tài),此時(shí)Reset尚未返回,整個(gè)D3D設(shè)備就好像死了一樣。舉個(gè)例子,你切換桌面分辨率,會(huì)有那么一段時(shí)間顯示器上什么都不顯示,然后很快就正常了。和這個(gè)現(xiàn)象是同一個(gè)原因。Reset成功后記得恢復(fù)資源。
              你可能注意到這里的Reset和上面的Reset不是一回事。的確是這樣,這里是為了重設(shè)狀態(tài)而不是恢復(fù)設(shè)備。因此更改分辨率、色深的Reset需要寫(xiě)到switch外面,也就是別和它攪和的意思-_-bb。而且你只需要OnLostDevice -> Reset -> OnResetDevice。記住:正確的調(diào)用Reset不會(huì)造成設(shè)備丟失,這個(gè)概念別弄混了。

            『切換全屏幕模式時(shí)的注意事項(xiàng)』

              注意WindowStyle的變化。切換成全屏幕模式后,只能使用WS_POPUP,不然顯示會(huì)變得怪怪的,你可以通過(guò)SetWindowLongPtr函數(shù)更改窗口外觀,第二個(gè)參數(shù)指定GWL_STYLE即可。別忘了WS_VISIBLE啊!不然你什么都看不見(jiàn)。

            『更詳細(xì)的文檔』

              我這里只是簡(jiǎn)單討論了造成設(shè)備丟失的原因及處理方法,更詳細(xì)的內(nèi)容你可以參考DX SDK文檔的Lost Device文章,人家是權(quán)威的。

            【以上,正片結(jié)束,后面是ED】

              我們前進(jìn)到了D3D9,趕上了時(shí)代。
              我們創(chuàng)建了全屏幕游戲,趕上了時(shí)代。
              我卻變得一腦子漿糊,被觀眾拋棄了。
              哈哈,開(kāi)玩笑啦,不過(guò)這一話很亂倒是真的,因?yàn)椴徽撌歉碌紻3D9還是設(shè)備丟失,牽扯的東西都太散太雜,結(jié)果弄得這一話也是一盤(pán)散沙(居然又沒(méi)有附帶代碼)。唉,大家就忍了吧,忍不了的話就來(lái)PIA我吧。

              關(guān)于更新至D3D9更多的內(nèi)容,你可以參考SDK文檔的《Converting to Direct3D 9》。

            【以上,ED結(jié)束,后面是……】

              第一季完結(jié)了……
              回過(guò)頭來(lái)看看,從第一話創(chuàng)建一個(gè)Windows窗口,到這一話的設(shè)備丟失,話題的層次一直在深入,現(xiàn)在已經(jīng)深入到了不再是“學(xué)習(xí)”而是“研究”的范圍。我也不再想僅僅是搞“教學(xué)”而是想和大家“討論”。不過(guò)第一季主要還是教學(xué)吧。能堅(jiān)持著看D2D教程到現(xiàn)在的,應(yīng)該基本能夠?qū)懗鐾暾?D Demo來(lái)了吧。如果有什么問(wèn)題的話,歡迎提出,我在看到后會(huì)立刻回答的……只要你這個(gè)問(wèn)題不太RP的話……
              那么,第二季會(huì)是什么樣子?
              第二季就不再是教學(xué)了,而開(kāi)始我和大家的討論過(guò)程。第二季的第一話,也就是第09話,我將提供一些高級(jí)技巧給大家,并希望有興趣的朋友和我一起進(jìn)行這些技巧的研究。另外在第二季里面,我們還要?jiǎng)?chuàng)建一個(gè)2D圖形引擎。原來(lái)打算給大家講解Medux 2,不過(guò)現(xiàn)在感覺(jué)這東西實(shí)在小兒科,絕對(duì)會(huì)讓大家B4的。那么既然如此,干脆介紹Mercury 3好了,有意見(jiàn)無(wú)?
              透漏一點(diǎn)下一話的內(nèi)容吧:模糊精度和多次紋理渲染,嘿嘿,聽(tīng)上去挺高深的是不?實(shí)際上超級(jí)簡(jiǎn)單,就看你能不能想到而已。
              希望你在看完這一話之后,返回去再把前面的內(nèi)容看看,相信你會(huì)得到新的收獲。搞不好你還能抓出幾個(gè)Bug呢!因?yàn)槲沂窍氲绞裁磳?xiě)什么,沒(méi)個(gè)章法,Bug是難免的。
             


            附加:

            Direct3D中的字體與文本顯示
            圖形系統(tǒng)中為了獲得當(dāng)前運(yùn)行程序的相關(guān)信息,往往需要在屏幕上顯示文本,Direct3D的功能擴(kuò)展接口ID3DXFont對(duì)此提供了方便的解決方法。

             

             

            創(chuàng)建ID3DXFont對(duì)象

            使用接口ID3DXFont繪制文本,首先需要通過(guò)函數(shù)D3DXCreateFont()創(chuàng)建ID3DXFont字體對(duì)象。ID3DXFont接口封裝了Windows字體和Direct3D設(shè)備指針,D3DXCreateFont()函數(shù)通過(guò)Windows字體和Direct3D設(shè)備指針創(chuàng)建ID3DXFont對(duì)象,該函數(shù)的聲明如下:

            Creates a font object for a device and font.

            HRESULT D3DXCreateFont(  LPDIRECT3DDEVICE9 pDevice,  INT Height,  UINT Width,  UINT Weight,  UINT MipLevels,  BOOL Italic,  DWORD CharSet,  DWORD OutputPrecision,  DWORD Quality,  DWORD PitchAndFamily,  LPCTSTR pFacename,  LPD3DXFONT * ppFont);
            Parameters
            pDevice
            [in] Pointer to an IDirect3DDevice9 interface, the device to be associated with the font object.
            Height
            [in] The height of the characters in logical units.
            Width
            [in] The width of the characters in logical units.
            Weight
            [in] Typeface weight. One example is bold.
            MipLevels
            [in] The number of mipmap levels.
            Italic
            [in] True for italic font, false otherwise.
            CharSet
            [in] The character set of the font.
            OutputPrecision
            [in] Specifies how Windows should attempt to match the desired font sizes and characteristics with actual fonts. Use OUT_TT_ONLY_PRECIS for instance, to ensure that you always get a TrueType font.
            Quality
            [in] Specifies how Windows should match the desired font with a real font. It applies to raster fonts only and should not affect TrueType fonts.
            PitchAndFamily
            [in] Pitch and family index.
            pFacename
            [in] String containing the typeface name. If the compiler settings require Unicode, the data type LPCTSTR resolves to LPCWSTR. Otherwise, the string data type resolves to LPCSTR. See Remarks.
            ppFont
            [out] Returns a pointer to an ID3DXFont interface, representing the created font object.
            Return Values
            If the function succeeds, the return value is S_OK. If the function fails, the return value can be one of the following: D3DERR_INVALIDCALL, D3DXERR_INVALIDDATA, E_OUTOFMEMORY.

            Remarks
            The creation of an ID3DXFont object requires that the device supports 32-bit color.

            The compiler setting also determines the function version. If Unicode is defined, the function call resolves to D3DXCreateFontW. Otherwise, the function call resolves to D3DXCreateFontA because ANSI strings are being used.

            If you want more information about font parameters, see The Logical Font.

            示例代碼如下:

            D3DXCreateFont(g_device, 50, 20, 20, 0, FALSE, DEFAULT_CHARSET, 0, 0, 0, "Arial", &g_font);

            posted @ 2009-09-12 07:40 RedLight 閱讀(2427) | 評(píng)論 (0)編輯 收藏

            OpenGL中的選擇和反饋

            讀完此章之后,你將能夠做到:
              建立允許用戶選擇(select)屏幕區(qū)域或拾取(pick)繪制在屏幕上的物體的應(yīng)用程序
              利用OpenGL的反饋(feedback)模式獲取絢染計(jì)算結(jié)果
              
              有些圖形應(yīng)用程序只繪制兩維和三維物體構(gòu)成的靜態(tài)圖形,另一些允許用戶識(shí)別屏幕上的物體并移動(dòng)、修改、刪除或用其它方法操縱這些物體。OpenGL正是設(shè)計(jì)用于支持這些交互式應(yīng)用程序的。因?yàn)槔L制在屏幕上的物體通常經(jīng)過(guò)多次旋轉(zhuǎn)、移動(dòng)和透視變換,所以確定用戶選中了三維場(chǎng)景中的哪個(gè)物體會(huì)很困難。為了幫助你,OpenGL提供了一個(gè)選取機(jī)制可惟自動(dòng)告訴你哪個(gè)物體被繪制在窗口的提定區(qū)域里。你可以用這個(gè)機(jī)制與一個(gè)工具例程(a special utility routine)一道決定哪個(gè)物體在用戶說(shuō)明或用光標(biāo)選取的區(qū)域里。
              
              選擇(selection)實(shí)際上是OpenGL的一個(gè)操作模式;反饋(feedback)是這類模式中的別一個(gè)。在反饋模式中,你用你的圖形硬件和OpenGL完成通常的絢染計(jì)算。但與用這個(gè)計(jì)算結(jié)果去在屏幕上繪制圖形相反,OpenGL返回(或反饋(feeds back))這些繪制信息給你。如果你想在繪圖儀而不是屏幕上繪制圖形,舉個(gè)例子,你就得在反饋模式繪制它們,收集繪制指令,然后將這些指令轉(zhuǎn)換為繪圖儀可以理解的命令。
              
              在選擇和反饋模式中,繪制信息返回給應(yīng)用程序而不是象在絢染模式中那樣送往幀緩沖。因此,當(dāng)OpenGL處于選擇或反饋模式時(shí),屏幕將被凍結(jié)-沒(méi)有圖形出現(xiàn)。這一章將會(huì)在各自的節(jié)中解釋這些模式:
              
              “選擇(Selection)” 討論怎樣使用選擇模式和相關(guān)的例程以使你程序的用戶能拾取畫(huà)在屏幕上的物體。
              
              “反饋(Feedback)” 描述了怎樣獲取有關(guān)什么將被畫(huà)在屏幕上的信息和這些信息是以什么格式組織的。
              
              ---------------------------------------------------
              Section
              
              通常,當(dāng)你打算使用OpenGL的選擇機(jī)制時(shí),你首先把你的場(chǎng)景畫(huà)進(jìn)幀緩沖,然后進(jìn)入選擇模式并重新繪制這個(gè)場(chǎng)景。然而,一旦你進(jìn)入了選擇模式,幀緩沖的內(nèi)容將保存不變,直到你退出選擇模式。當(dāng)你退出時(shí),OpenGL返回一個(gè)圖元(premitives)清單,圖元可能被視見(jiàn)體(viewing volume)分割(記住,視見(jiàn)體是由當(dāng)前模式視見(jiàn)和投影矩陣及你定義的所有裁剪面定義,裁剪面詳見(jiàn)"Additional Clipping Planes.")。每個(gè)被視見(jiàn)體圖元引出一資選擇命中(hit)。確切的說(shuō),圖元清單是作為一個(gè)取整數(shù)值的名字(integer-valued names)數(shù)組和相關(guān)的數(shù)據(jù)-命中記錄(hit record)-對(duì)應(yīng)名字棧(name stack)的當(dāng)前內(nèi)容。當(dāng)你在選擇模式下發(fā)布圖元繪制命令時(shí)向名字棧中加入名字就可建立起名字棧。這樣,當(dāng)名字清單被返回后,你就可以用它來(lái)確定屏幕上的哪個(gè)圖元可能被用戶選中了。
              
              除了這個(gè)選擇機(jī)制之外,OpenGL提供了一個(gè)工具例程,以便在某些情況下通過(guò)限定在視口(viewport)一個(gè)小區(qū)域內(nèi)繪制來(lái)簡(jiǎn)化選擇。通常你可以用這個(gè)例程決定哪個(gè)物體被畫(huà)在光標(biāo)附近了,這樣你就能識(shí)別用戶拾取了哪個(gè)物體。你也可以通過(guò)指定附加的裁剪面來(lái)界定一個(gè)選擇區(qū)域;詳見(jiàn)"Additional Clipping Planes"。因?yàn)槭叭∈沁x擇的一個(gè)特殊情況,所以本章選講選擇,然后講拾取。
              
              基本步驟
              建立名字矩陣
              命中記錄
              一個(gè)選擇的例子
              拾取
              關(guān)于編寫(xiě)使用選擇的程序的提示
              
              ------------------------------------------------------------------------
              基本步驟
              
              為使用選擇機(jī)制,你得作以下幾步:
              1、用glSelectBuffer()指定用于返回命中記錄的數(shù)組。
              2、以GL_SELECT為參數(shù)調(diào)用glRenderMode()進(jìn)入選擇模式。
              3、用glInitName()和glPushName()初始化名字棧。
              4、定義用于選擇的視見(jiàn)體。通常它與你原來(lái)用于繪制場(chǎng)景的視見(jiàn)體不同。因此你或許會(huì)想用glPushMatrix()和glPopMatrix()來(lái)保存和恢復(fù)當(dāng)前的變換矩陣。
              5、交替發(fā)布圖元繪制命令和名字棧控制命令,這樣每個(gè)感興趣的圖元都會(huì)被指定適當(dāng)?shù)拿帧?br>  6、退出選擇模式并處理返回的選擇數(shù)據(jù)(命中記錄)。
              
              后面的段落將描述glSelectBuffer()和glRenderMode()。下一節(jié)則講解名字棧的控制。
              
              void glSelectBuffer(GLsizei size, GLuint *buffer);
              指定用于返回選擇數(shù)據(jù)的數(shù)組。參數(shù)buffer是指向無(wú)符號(hào)整數(shù)(unsigned integer)數(shù)組的指針,數(shù)據(jù)就存在這個(gè)數(shù)組中,size參數(shù)說(shuō)明數(shù)組中最多能夠保存的值的個(gè)數(shù)。要在進(jìn)入選擇模式之前調(diào)用glSelectBuffer()!
              
              GLint glRenderMode(GLenum mode);
              控制應(yīng)用程序是否進(jìn)入絢染(rendering)、選擇或反饋模式。mode參數(shù)可以是GL_RENDER(默認(rèn))、GL_SELECT或GL_FEEDBACK之一。應(yīng)用程序?qū)⒈3痔幱诮o定模式,直到再次以不同的參數(shù)調(diào)用glRenderMode()。在進(jìn)入選擇模式之前必須調(diào)用glSelectBuffer()指定選擇數(shù)組。類似的,進(jìn)入反饋模式之前要調(diào)用glFeedbackBuffer()指定反饋數(shù)組。如果當(dāng)前模式是GL_SELECT或GL_FEEDBACK之一,那么glRenderMode()的返回值有意義。返回值是當(dāng)前退出當(dāng)前模式時(shí),選擇命中數(shù)或放在反饋數(shù)組中的值的個(gè)數(shù)。(譯者注:調(diào)用此函數(shù)就會(huì)退出當(dāng)前模式);負(fù)值意味著選擇或反饋數(shù)組溢出(overflowed)。你可以用GL_RENDER_MODE調(diào)用glGetIntegerv()獲取當(dāng)前模式。
              
              -------------------------------------------------------------------------------
              建立名字矩陣
              
              正如前面提到的,名字棧是返回給你的選擇信息的基礎(chǔ)。要建立名字棧,首先用glInitNames()初始化它,這將簡(jiǎn)單地清空棧。然后當(dāng)你發(fā)布相應(yīng)的繪制命令時(shí)向其中加入整數(shù)名字。正如你可能想象,棧控制命令允許你壓入名字(glPushName()),彈出名字(glPopName()),替換棧頂?shù)拿郑╣lLoadName())。
              /********************************************************************/
              Example 12-1: Creating a Name Stack
              glInitNames();
              glPushName(-1);
              
              glPushMatrix(); /* save the current transformation state */
              
              /*to do: create your desired viewing volume here */
              
              glLoadName(1);
              drawSomeObject();
              glLoadName(2);
              drawAnotherObject();
              glLoadName(3);
              drawYetAnotherObject();
              drawJustOneMoreObject();
              
              glPopMatrix (); /* restore the previous transformation state*/
              /********************************************************************/
              
              在這個(gè)例子中,前兩個(gè)被繪制的物體有自己的名字,第三和第四個(gè)共用一個(gè)名字。這樣,如果第三或第四個(gè)物體中的一個(gè)或全部引起一個(gè)選擇命中,只有一個(gè)命中記錄返回給你。如果處理命中記錄時(shí)不想?yún)^(qū)分各個(gè)物體的話,可以讓多個(gè)物體共享一個(gè)名字。
              
              void glInitNames(void);
              清空名字棧。
              
              void glPushName(GLuint name);
              將name壓入名字棧。壓入名字超過(guò)棧容量時(shí)將生成一個(gè)GL_STACK_OVERFLOW錯(cuò)誤。名字棧深度因OpenGL實(shí)現(xiàn)(implementations)不同而不同,但最少要能容納64個(gè)名字。你可以用參數(shù)GL_NAME_STACK_DEPTH調(diào)用glGetIntegerv()以獲取名字棧深度。
              
              void glPopName(void);
              彈出名字棧棧頂?shù)哪且粋€(gè)名字。從空棧中彈出名字引發(fā)GL_STACK_UNDERFLOW錯(cuò)誤。
              
              void glLoadName(GLuint name);
              用name取代名字棧棧頂?shù)哪莻€(gè)名字。如果棧是空的,剛調(diào)用過(guò)glInitName()后就是這樣,glLoadName()生成一個(gè)GL_INVALID_OPRATION錯(cuò)。為避免這種情況,如果棧初始時(shí)是空的,那么在調(diào)用glLoadName()之前至少調(diào)用一次glPushName()以在名字棧中放上點(diǎn)東西。
              
              如果不是在選擇模式下,對(duì)glPushName()、glPopName()、glLoadName()的調(diào)用將被忽略。這使得在選擇模式和正常的絢染模式下用相同的繪制代碼大為簡(jiǎn)化。
              
              -------------------------------------------------------------------------------
              命中記錄
              
              在選擇模式下,被視見(jiàn)體裁剪的每個(gè)圖元引起一個(gè)選擇命中。當(dāng)前一個(gè)名字??刂泼畋粓?zhí)行或glRenderMode()被調(diào)用后,OpenGL將一個(gè)命中記錄寫(xiě)進(jìn)選擇數(shù)組,如果從上一次名字棧操縱或glRenderMode()調(diào)用以來(lái)有了一個(gè)命中記錄的話。這個(gè)過(guò)程中,共用同樣名字的物體-例如:由多個(gè)圖元組成的物體-不生成多個(gè)命中記錄。當(dāng)然,命中記錄不保證會(huì)被寫(xiě)進(jìn)數(shù)組中直到glRenderMode()被調(diào)用。
              
              除圖元之外,glRasterPos()產(chǎn)生的有效坐標(biāo)也可以引起選擇命中。在多邊形的情況下,如果它已經(jīng)被消隱掉的話不會(huì)有命中記錄出現(xiàn)。
              
              每個(gè)命中記錄由四項(xiàng)組成,依次是:
              當(dāng)命中出現(xiàn)時(shí)名字棧中的名字?jǐn)?shù)
              至上次記錄的命中以來(lái),被視見(jiàn)體裁剪后的圖元的所有頂點(diǎn)的窗口Z坐標(biāo)的 最大和最小值
              本次命中時(shí)名字棧的內(nèi)容,最底元素最前。
              
              當(dāng)前你進(jìn)入選擇模式時(shí),OpenGL初始化一個(gè)指針指向選擇數(shù)組的起點(diǎn)。每寫(xiě)入一個(gè)命中記錄,指針相應(yīng)更新。如果寫(xiě)入一個(gè)命中記錄會(huì)使數(shù)組中值的個(gè)數(shù)超過(guò)glSelectBuffer()的size參數(shù)時(shí),OpenGL會(huì)寫(xiě)入盡可能多的記錄并設(shè)置一個(gè)溢出標(biāo)志。當(dāng)用glRenderMode()退出選擇模式時(shí),這條命令返回被寫(xiě)入的記錄的個(gè)數(shù)(包括一條部分記錄如果有的話),清除名字棧,復(fù)位溢出標(biāo)識(shí),重置棧指針。如設(shè)定溢了出標(biāo)識(shí)則返回值是-1。

            本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/Crazyjumper/archive/2007/10/18/1830865.aspx

            posted @ 2009-09-01 06:28 RedLight 閱讀(528) | 評(píng)論 (0)編輯 收藏

            OpenGL中的Alpha測(cè)試,深度測(cè)試,模板測(cè)試,裁減測(cè)試

            大家好。現(xiàn)在因?yàn)閰⒓庸ぷ鞯年P(guān)系,又是長(zhǎng)時(shí)間沒(méi)有更新。趁著國(guó)慶的空閑,總算是又寫(xiě)出了一課。我感覺(jué)入門(mén)的知識(shí)已經(jīng)快要介紹完畢,這課之后再有一課,就可以告一段落了。以后我可能會(huì)寫(xiě)一些自己在這方面的體會(huì),做一份進(jìn)階課程。

            現(xiàn)在即將放出的是第十二課的內(nèi)容。

            首先還是以前課程的連接:

            第一課,編寫(xiě)第一個(gè)OpenGL程序
            第二課,繪制幾何圖形
            第三課,繪制幾何圖形的一些細(xì)節(jié)問(wèn)題
            第四課,顏色的選擇
            第五課,三維的空間變換
            第六課,動(dòng)畫(huà)的制作
            第七課,使用光照來(lái)表現(xiàn)立體感
            第八課,使用顯示列表
            第九課,使用混合來(lái)實(shí)現(xiàn)半透明效果
            第十課,BMP文件與像素操作
            第十一課,紋理的使用入門(mén)
            第十二課,OpenGL片斷測(cè)試  ——→  本次課程的內(nèi)容

            片斷測(cè)試其實(shí)就是測(cè)試每一個(gè)像素,只有通過(guò)測(cè)試的像素才會(huì)被繪制,沒(méi)有通過(guò)測(cè)試的像素則不進(jìn)行繪制。OpenGL提供了多種測(cè)試操作,利用這些操作可以實(shí)現(xiàn)一些特殊的效果。
            我們?cè)谇懊娴恼n程中,曾經(jīng)提到了“深度測(cè)試”的概念,它在繪制三維場(chǎng)景的時(shí)候特別有用。在不使用深度測(cè)試的時(shí)候,如果我們先繪制一個(gè)距離較近的物體,再繪制距離較遠(yuǎn)的物體,則距離遠(yuǎn)的物體因?yàn)楹罄L制,會(huì)把距離近的物體覆蓋掉,這樣的效果并不是我們所希望的。
            如果使用了深度測(cè)試,則情況就會(huì)有所不同:每當(dāng)一個(gè)像素被繪制,OpenGL就記錄這個(gè)像素的“深度”(深度可以理解為:該像素距離觀察者的距離。深度值越大,表示距離越遠(yuǎn)),如果有新的像素即將覆蓋原來(lái)的像素時(shí),深度測(cè)試會(huì)檢查新的深度是否會(huì)比原來(lái)的深度值小。如果是,則覆蓋像素,繪制成功;如果不是,則不會(huì)覆蓋原來(lái)的像素,繪制被取消。這樣一來(lái),即使我們先繪制比較近的物體,再繪制比較遠(yuǎn)的物體,則遠(yuǎn)的物體也不會(huì)覆蓋近的物體了。
            實(shí)際上,只要存在深度緩沖區(qū),無(wú)論是否啟用深度測(cè)試,OpenGL在像素被繪制時(shí)都會(huì)嘗試將深度數(shù)據(jù)寫(xiě)入到緩沖區(qū)內(nèi),除非調(diào)用了glDepthMask(GL_FALSE)來(lái)禁止寫(xiě)入。這些深度數(shù)據(jù)除了用于常規(guī)的測(cè)試外,還可以有一些有趣的用途,比如繪制陰影等等。

            除了深度測(cè)試,OpenGL還提供了剪裁測(cè)試、Alpha測(cè)試和模板測(cè)試。

            1、剪裁測(cè)試
            剪裁測(cè)試用于限制繪制區(qū)域。我們可以指定一個(gè)矩形的剪裁窗口,當(dāng)啟用剪裁測(cè)試后,只有在這個(gè)窗口之內(nèi)的像素才能被繪制,其它像素則會(huì)被丟棄。換句話說(shuō),無(wú)論怎么繪制,剪裁窗口以外的像素將不會(huì)被修改。
            有的朋友可能玩過(guò)《魔獸爭(zhēng)霸3》這款游戲。游戲時(shí)如果選中一個(gè)士兵,則畫(huà)面下方的一個(gè)方框內(nèi)就會(huì)出現(xiàn)該士兵的頭像。為了保證該頭像無(wú)論如何繪制都不會(huì)越界而覆蓋到外面的像素,就可以使用剪裁測(cè)試。

            可以通過(guò)下面的代碼來(lái)啟用或禁用剪裁測(cè)試:
            glEnable(GL_SCISSOR_TEST);  // 啟用剪裁測(cè)試
            glDisable(GL_SCISSOR_TEST); // 禁用剪裁測(cè)試

            可以通過(guò)下面的代碼來(lái)指定一個(gè)位置在(x, y),寬度為width,高度為height的剪裁窗口。
            glScissor(x, y, width, height);

            注意,OpenGL窗口坐標(biāo)是以左下角為(0, 0),右上角為(width, height)的,這與Windows系統(tǒng)窗口有所不同。

            還有一種方法可以保證像素只繪制到某一個(gè)特定的矩形區(qū)域內(nèi),這就是視口變換(在第五課第3節(jié)中有介紹)。但視口變換和剪裁測(cè)試是不同的。視口變換是將所有內(nèi)容縮放到合適的大小后,放到一個(gè)矩形的區(qū)域內(nèi);而剪裁測(cè)試不會(huì)進(jìn)行縮放,超出矩形范圍的像素直接忽略掉。


            2、Alpha測(cè)試
            在前面的課程中,我們知道像素的Alpha值可以用于混合操作。其實(shí)Alpha值還有一個(gè)用途,這就是Alpha測(cè)試。當(dāng)每個(gè)像素即將繪制時(shí),如果啟動(dòng)了Alpha測(cè)試,OpenGL會(huì)檢查像素的Alpha值,只有Alpha值滿足條件的像素才會(huì)進(jìn)行繪制(嚴(yán)格的說(shuō),滿足條件的像素會(huì)通過(guò)本項(xiàng)測(cè)試,進(jìn)行下一種測(cè)試,只有所有測(cè)試都通過(guò),才能進(jìn)行繪制),不滿足條件的則不進(jìn)行繪制。這個(gè)“條件”可以是:始終通過(guò)(默認(rèn)情況)、始終不通過(guò)、大于設(shè)定值則通過(guò)、小于設(shè)定值則通過(guò)、等于設(shè)定值則通過(guò)、大于等于設(shè)定值則通過(guò)、小于等于設(shè)定值則通過(guò)、不等于設(shè)定值則通過(guò)。
            如果我們需要繪制一幅圖片,而這幅圖片的某些部分又是透明的(想象一下,你先繪制一幅相片,然后繪制一個(gè)相框,則相框這幅圖片有很多地方都是透明的,這樣就可以透過(guò)相框看到下面的照片),這時(shí)可以使用Alpha測(cè)試。將圖片中所有需要透明的地方的Alpha值設(shè)置為0.0,不需要透明的地方Alpha值設(shè)置為1.0,然后設(shè)置Alpha測(cè)試的通過(guò)條件為:“大于0.5則通過(guò)”,這樣便能達(dá)到目的。當(dāng)然也可以設(shè)置需要透明的地方Alpha值為1.0,不需要透明的地方Alpha值設(shè)置為0.0,然后設(shè)置條件為“小于0.5則通過(guò)”。Alpha測(cè)試的設(shè)置方式往往不只一種,可以根據(jù)個(gè)人喜好和實(shí)際情況需要進(jìn)行選擇。

            可以通過(guò)下面的代碼來(lái)啟用或禁用Alpha測(cè)試:


            glEnable(GL_ALPHA_TEST);  // 啟用Alpha測(cè)試
            glDisable(GL_ALPHA_TEST); // 禁用Alpha測(cè)試


            可以通過(guò)下面的代碼來(lái)設(shè)置Alpha測(cè)試條件為“大于0.5則通過(guò)”:


            glAlphaFunc(GL_GREATER, 0.5f);


            該函數(shù)的第二個(gè)參數(shù)表示設(shè)定值,用于進(jìn)行比較。第一個(gè)參數(shù)是比較方式,除了GL_LESS(小于則通過(guò))外,還可以選擇:
            GL_ALWAYS(始終通過(guò)),
            GL_NEVER(始終不通過(guò)),
            GL_LESS(小于則通過(guò)),
            GL_LEQUAL(小于等于則通過(guò)),
            GL_EQUAL(等于則通過(guò)),
            GL_GEQUAL(大于等于則通過(guò)),
            GL_NOTEQUAL(不等于則通過(guò))。
            現(xiàn)在我們來(lái)看一個(gè)實(shí)際例子。一幅照片圖片,一幅相框圖片,如何將它們組合在一起呢?為了簡(jiǎn)單起見(jiàn),我們使用前面兩課一直使用的24位BMP文件來(lái)作為圖片格式。(因?yàn)榘l(fā)布到網(wǎng)絡(luò)上,為了節(jié)約容量,我所發(fā)布的是JPG格式。大家下載后可以用Windows XP自帶的畫(huà)圖工具打開(kāi),并另存為24位BMP格式)

            注:第一幅圖片是著名網(wǎng)絡(luò)游戲《魔獸世界》的一幅桌面背景,用在這里希望沒(méi)有涉及版權(quán)問(wèn)題。如果有什么不妥,請(qǐng)及時(shí)指出,我會(huì)立即更換。

            在24位的BMP文件格式中,BGR三種顏色各占8位,沒(méi)有保存Alpha值,因此無(wú)法直接使用Alpha測(cè)試。注意到相框那幅圖片中,所有需要透明的位置都是白色,所以我們?cè)诔绦蛑性O(shè)置所有白色(或很接近白色)的像素Alpha值為0.0,設(shè)置其它像素Alpha值為1.0,然后設(shè)置Alpha測(cè)試的條件為“大于0.5則通過(guò)”即可。這種使用某種特殊顏色來(lái)代表透明顏色的技術(shù),有時(shí)又被成為Color Key技術(shù)。
            利用前面第11課的一段代碼,將圖片讀取為紋理,然后利用下面這個(gè)函數(shù)來(lái)設(shè)置“當(dāng)前紋理”中每一個(gè)像素的Alpha值。


            /* 將當(dāng)前紋理BGR格式轉(zhuǎn)換為BGRA格式
             * 紋理中像素的RGB值如果與指定rgb相差不超過(guò)absolute,則將Alpha設(shè)置為0.0,否則設(shè)置為1.0
             */
            void texture_colorkey(GLubyte r, GLubyte g, GLubyte b, GLubyte absolute)
            {
                GLint width, height;
                GLubyte* pixels = 0;

                // 獲得紋理的大小信息
                glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
                glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);

                // 分配空間并獲得紋理像素
                pixels = (GLubyte*)malloc(width*height*4);
                if( pixels == 0 )
                    return;
                glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);

                // 修改像素中的Alpha值
                // 其中pixels[i*4], pixels[i*4+1], pixels[i*4+2], pixels[i*4+3]
                //   分別表示第i個(gè)像素的藍(lán)、綠、紅、Alpha四種分量,0表示最小,255表示最大
                {
                    GLint i;
                    GLint count = width * height;
                    for(i=0; i<count; ++i)
                    {
                        if( abs(pixels[i*4] - b) <= absolute
                         && abs(pixels[i*4+1] - g) <= absolute
                         && abs(pixels[i*4+2] - r) <= absolute )
                            pixels[i*4+3] = 0;
                        else
                            pixels[i*4+3] = 255;
                    }
                }

                // 將修改后的像素重新設(shè)置到紋理中,釋放內(nèi)存
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
                    GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
                free(pixels);
            }

            有了紋理后,我們開(kāi)啟紋理,指定合適的紋理坐標(biāo)并繪制一個(gè)矩形,這樣就可以在屏幕上將圖片繪制出來(lái)。我們先繪制相片的紋理,再繪制相框的紋理。程序代碼如下:


            void display(void)
            {
                static int initialized   = 0;
                static GLuint texWindow  = 0;
                static GLuint texPicture = 0;

                // 執(zhí)行初始化操作,包括:讀取相片,讀取相框,將相框由BGR顏色轉(zhuǎn)換為BGRA,啟用二維紋理
                if( !initialized )
                {
                    texPicture = load_texture("pic.bmp");
                    texWindow  = load_texture("window.bmp");
                    glBindTexture(GL_TEXTURE_2D, texWindow);
                    texture_colorkey(255, 255, 255, 10);

                    glEnable(GL_TEXTURE_2D);

                    initialized = 1;
                }

                // 清除屏幕
                glClear(GL_COLOR_BUFFER_BIT);

                // 繪制相片,此時(shí)不需要進(jìn)行Alpha測(cè)試,所有的像素都進(jìn)行繪制
                glBindTexture(GL_TEXTURE_2D, texPicture);
                glDisable(GL_ALPHA_TEST);
                glBegin(GL_QUADS);
                    glTexCoord2f(0, 0);     glVertex2f(-1.0f, -1.0f);
                    glTexCoord2f(0, 1);     glVertex2f(-1.0f,  1.0f);
                    glTexCoord2f(1, 1);     glVertex2f( 1.0f,  1.0f);
                    glTexCoord2f(1, 0);     glVertex2f( 1.0f, -1.0f);
                glEnd();

                // 繪制相框,此時(shí)進(jìn)行Alpha測(cè)試,只繪制不透明部分的像素
                glBindTexture(GL_TEXTURE_2D, texWindow);
                glEnable(GL_ALPHA_TEST);
                glAlphaFunc(GL_GREATER, 0.5f);
                glBegin(GL_QUADS);
                    glTexCoord2f(0, 0);     glVertex2f(-1.0f, -1.0f);
                    glTexCoord2f(0, 1);     glVertex2f(-1.0f,  1.0f);
                    glTexCoord2f(1, 1);     glVertex2f( 1.0f,  1.0f);
                    glTexCoord2f(1, 0);     glVertex2f( 1.0f, -1.0f);
                glEnd();

                // 交換緩沖
                glutSwapBuffers();
            }

            其中:load_texture函數(shù)是從第11課中照搬過(guò)來(lái)的(該函數(shù)還使用了一個(gè)power_of_two函數(shù),一個(gè)BMP_Header_Length常數(shù),同樣照搬),無(wú)需進(jìn)行修改。main函數(shù)跟其它課程的基本相同,不再重復(fù)。
            程序運(yùn)行后,會(huì)發(fā)現(xiàn)相框與相片的銜接有些不自然,這是因?yàn)橄嗫蚰承┻吘壊糠蛛m然肉眼看上去是白色,但其實(shí)RGB值與純白色相差并不少,因此程序計(jì)算其Alpha值時(shí)認(rèn)為其不需要透明。解決辦法是仔細(xì)處理相框中的每個(gè)像素,在需要透明的地方涂上純白色,這也許是一件很需要耐心的工作。


                大家可能會(huì)想:前面我們學(xué)習(xí)過(guò)混合操作,混合可以實(shí)現(xiàn)半透明,自然也可以通過(guò)設(shè)定實(shí)現(xiàn)全透明。也就是說(shuō),Alpha測(cè)試可以實(shí)現(xiàn)的效果幾乎都可以通過(guò)OpenGL混合功能來(lái)實(shí)現(xiàn)。那么為什么還需要一個(gè)Alpha測(cè)試呢?答案就是,這與性能相關(guān)。Alpha測(cè)試只要簡(jiǎn)單的比較大小就可以得到最終結(jié)果,而混合操作一般需要進(jìn)行乘法運(yùn)算,性能有所下降。另外,OpenGL測(cè)試的順序是:剪裁測(cè)試、Alpha測(cè)試、模板測(cè)試、深度測(cè)試。如果某項(xiàng)測(cè)試不通過(guò),則不會(huì)進(jìn)行下一步,而只有所有測(cè)試都通過(guò)的情況下才會(huì)執(zhí)行混合操作。因此,在使用Alpha測(cè)試的情況下,透明的像素就不需要經(jīng)過(guò)模板測(cè)試和深度測(cè)試了;而如果使用混合操作,即使透明的像素也需要進(jìn)行模板測(cè)試和深度測(cè)試,性能會(huì)有所下降。還有一點(diǎn):對(duì)于那些“透明”的像素來(lái)說(shuō),如果使用Alpha測(cè)試,則“透明”的像素不會(huì)通過(guò)測(cè)試,因此像素的深度值不會(huì)被修改;而使用混合操作時(shí),雖然像素的顏色沒(méi)有被修改,但它的深度值則有可能被修改掉了。
            因此,如果所有的像素都是“透明”或“不透明”,沒(méi)有“半透明”時(shí),應(yīng)該盡量采用Alpha測(cè)試而不是采用混合操作。當(dāng)需要繪制半透明像素時(shí),才采用混合操作。

               3、模板測(cè)試
            模板測(cè)試是所有OpenGL測(cè)試中比較復(fù)雜的一種。

            首先,模板測(cè)試需要一個(gè)模板緩沖區(qū),這個(gè)緩沖區(qū)是在初始化OpenGL時(shí)指定的。如果使用GLUT工具包,可以在調(diào)用glutInitDisplayMode函數(shù)時(shí)在參數(shù)中加上GLUT_STENCIL,例如:


            glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL);

            在Windows操作系統(tǒng)中,即使沒(méi)有明確要求使用模板緩沖區(qū),有時(shí)候也會(huì)分配模板緩沖區(qū)。但為了保證程序的通用性,最好還是明確指定使用模板緩沖區(qū)。如果確實(shí)沒(méi)有分配模板緩沖區(qū),則所有進(jìn)行模板測(cè)試的像素全部都會(huì)通過(guò)測(cè)試。

            通過(guò)glEnable/glDisable可以啟用或禁用模板測(cè)試。


            glEnable(GL_STENCIL_TEST);  // 啟用模板測(cè)試
            glDisable(GL_STENCIL_TEST); // 禁用模板測(cè)試


            OpenGL在模板緩沖區(qū)中為每個(gè)像素保存了一個(gè)“模板值”,當(dāng)像素需要進(jìn)行模板測(cè)試時(shí),將設(shè)定的模板參考值與該像素的“模板值”進(jìn)行比較,符合條件的通過(guò)測(cè)試,不符合條件的則被丟棄,不進(jìn)行繪制。
            條件的設(shè)置與Alpha測(cè)試中的條件設(shè)置相似。但注意Alpha測(cè)試中是用浮點(diǎn)數(shù)來(lái)進(jìn)行比較,而模板測(cè)試則是用整數(shù)來(lái)進(jìn)行比較。比較也有八種情況:始終通過(guò)、始終不通過(guò)、大于則通過(guò)、小于則通過(guò)、大于等于則通過(guò)、小于等于則通過(guò)、等于則通過(guò)、不等于則通過(guò)。


            glStencilFunc(GL_LESS, 3, mask);

            這段代碼設(shè)置模板測(cè)試的條件為:“小于3則通過(guò)”。glStencilFunc的前兩個(gè)參數(shù)意義與glAlphaFunc的兩個(gè)參數(shù)類似,第三個(gè)參數(shù)的意義為:如果進(jìn)行比較,則只比較mask中二進(jìn)制為1的位。例如,某個(gè)像素模板值為5(二進(jìn)制101),而mask的二進(jìn)制值為00000011,因?yàn)橹槐容^最后兩位,5的最后兩位為01,其實(shí)是小于3的,因此會(huì)通過(guò)測(cè)試。

            如何設(shè)置像素的“模板值”呢?glClear函數(shù)可以將所有像素的模板值復(fù)位。代碼如下:


            glClear(GL_STENCIL_BUFFER_BIT);

            可以同時(shí)復(fù)位顏色值和模板值:


            glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

            正如可以使用glClearColor函數(shù)來(lái)指定清空屏幕后的顏色那樣,也可以使用glClearStencil函數(shù)來(lái)指定復(fù)位后的“模板值”。

            每個(gè)像素的“模板值”會(huì)根據(jù)模板測(cè)試的結(jié)果和深度測(cè)試的結(jié)果而進(jìn)行改變。


            glStencilOp(fail, zfail, zpass);

            該函數(shù)指定了三種情況下“模板值”該如何變化。第一個(gè)參數(shù)表示模板測(cè)試未通過(guò)時(shí)該如何變化;第二個(gè)參數(shù)表示模板測(cè)試通過(guò),但深度測(cè)試未通過(guò)時(shí)該如何變化;第三個(gè)參數(shù)表示模板測(cè)試和深度測(cè)試均通過(guò)時(shí)該如何變化。如果沒(méi)有起用模板測(cè)試,則認(rèn)為模板測(cè)試總是通過(guò);如果沒(méi)有啟用深度測(cè)試,則認(rèn)為深度測(cè)試總是通過(guò))
            變化可以是:
            GL_KEEP(不改變,這也是默認(rèn)值),
            GL_ZERO(回零),
            GL_REPLACE(使用測(cè)試條件中的設(shè)定值來(lái)代替當(dāng)前模板值),
            GL_INCR(增加1,但如果已經(jīng)是最大值,則保持不變),
            GL_INCR_WRAP(增加1,但如果已經(jīng)是最大值,則從零重新開(kāi)始),
            GL_DECR(減少1,但如果已經(jīng)是零,則保持不變),
            GL_DECR_WRAP(減少1,但如果已經(jīng)是零,則重新設(shè)置為最大值),
            GL_INVERT(按位取反)。

            在新版本的OpenGL中,允許為多邊形的正面和背面使用不同的模板測(cè)試條件和模板值改變方式,于是就有了glStencilFuncSeparate函數(shù)和glStencilOpSeparate函數(shù)。這兩個(gè)函數(shù)分別與glStencilFunc和glStencilOp類似,只在最前面多了一個(gè)參數(shù)face,用于指定當(dāng)前設(shè)置的是哪個(gè)面。可以選擇GL_FRONT, GL_BACK, GL_FRONT_AND_BACK。

            注意:模板緩沖區(qū)與深度緩沖區(qū)有一點(diǎn)不同。無(wú)論是否啟用深度測(cè)試,當(dāng)有像素被繪制時(shí),總會(huì)重新設(shè)置該像素的深度值(除非設(shè)置glDepthMask(GL_FALSE);)。而模板測(cè)試如果不啟用,則像素的模板值會(huì)保持不變,只有啟用模板測(cè)試時(shí)才有可能修改像素的模板值。(這一結(jié)論是我自己的實(shí)驗(yàn)得出的,暫時(shí)沒(méi)發(fā)現(xiàn)什么資料上是這樣寫(xiě)。如果有不正確的地方,歡迎指正)
            另外,模板測(cè)試雖然是從OpenGL 1.0就開(kāi)始提供的功能,但是對(duì)于個(gè)人計(jì)算機(jī)而言,硬件實(shí)現(xiàn)模板測(cè)試的似乎并不多,很多計(jì)算機(jī)系統(tǒng)直接使用CPU運(yùn)算來(lái)完成模板測(cè)試。因此在一些老的顯卡,或者是多數(shù)集成顯卡上,大量而頻繁的使用模板測(cè)試可能造成程序運(yùn)行效率低下。即使是當(dāng)前配置比較高端的個(gè)人計(jì)算機(jī),也盡量不要使用glStencilFuncSeparate和glStencilOpSeparate函數(shù)。

            從前面所講可以知道,使用剪裁測(cè)試可以把繪制區(qū)域限制在一個(gè)矩形的區(qū)域內(nèi)。但如果需要把繪制區(qū)域限制在一個(gè)不規(guī)則的區(qū)域內(nèi),則需要使用模板測(cè)試。
            例如:繪制一個(gè)湖泊,以及周?chē)臉?shù)木,然后繪制樹(shù)木在湖泊中的倒影。為了保證倒影被正確的限制在湖泊表面,可以使用模板測(cè)試。具體的步驟如下:
            (1) 關(guān)閉模板測(cè)試,繪制地面和樹(shù)木。
            (2) 開(kāi)啟模板測(cè)試,使用glClear設(shè)置所有像素的模板值為0。
            (3) 設(shè)置glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);繪制湖泊水面。這樣一來(lái),湖泊水面的像素的“模板值”為1,而其它地方像素的“模板值”為0。
            (4) 設(shè)置glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);繪制倒影。這樣一來(lái),只有“模板值”為1的像素才會(huì)被繪制,因此只有“水面”的像素才有可能被倒影的像素替換,而其它像素則保持不變。


               我們?nèi)匀粊?lái)看一個(gè)實(shí)際的例子。這是一個(gè)比較簡(jiǎn)單的場(chǎng)景:空間中有一個(gè)球體,一個(gè)平面鏡。我們站在某個(gè)特殊的觀察點(diǎn),可以看到球體在平面鏡中的鏡像,并且鏡像處于平面鏡的邊緣,有一部分因?yàn)槠矫骁R大小的限制,而無(wú)法顯示出來(lái)。整個(gè)場(chǎng)景的效果如下圖:


            繪制這個(gè)場(chǎng)景的思路跟前面提到的湖面倒影是接近的。
            假設(shè)平面鏡所在的平面正好是X軸和Y軸所確定的平面,則球體和它在平面鏡中的鏡像是關(guān)于這個(gè)平面對(duì)稱的。我們用一個(gè)draw_sphere函數(shù)來(lái)繪制球體,先調(diào)用該函數(shù)以繪制球體本身,然后調(diào)用glScalef(1.0f, 1.0f, -1.0f); 再調(diào)用draw_sphere函數(shù),就可以繪制球體的鏡像。
            另外需要注意的地方就是:因?yàn)槭抢L制三維的場(chǎng)景,我們開(kāi)啟了深度測(cè)試。但是站在觀察者的位置,球體的鏡像其實(shí)是在平面鏡的“背后”,也就是說(shuō),如果按照常規(guī)的方式繪制,平面鏡會(huì)把鏡像覆蓋掉,這不是我們想要的效果。解決辦法就是:設(shè)置深度緩沖區(qū)為只讀,繪制平面鏡,然后設(shè)置深度緩沖區(qū)為可寫(xiě)的狀態(tài),繪制平面鏡“背后”的鏡像。
            有的朋友可能會(huì)問(wèn):如果在繪制鏡像的時(shí)候關(guān)閉深度測(cè)試,那鏡像不就不會(huì)被平面鏡遮擋了嗎?為什么還要開(kāi)啟深度測(cè)試,又需要把深度緩沖區(qū)設(shè)置為只讀呢?實(shí)際情況是:雖然關(guān)閉深度測(cè)試確實(shí)可以讓鏡像不被平面鏡遮擋,但是鏡像本身會(huì)出現(xiàn)若干問(wèn)題。我們看到的鏡像是一個(gè)球體,但實(shí)際上這個(gè)球體是由很多的多邊形所組成的,這些多邊形有的代表了我們所能看到的“正面”,有的則代表了我們不能看到的“背面”。如果關(guān)閉深度測(cè)試,而有的“背面”多邊形又比“正面”多邊形先繪制,就會(huì)造成球體的背面反而把正面擋住了,這不是我們想要的效果。為了確保正面可以擋住背面,應(yīng)該開(kāi)啟深度測(cè)試。
            繪制部分的代碼如下:


            void draw_sphere()
            {
                // 設(shè)置光源
                glEnable(GL_LIGHTING);
                glEnable(GL_LIGHT0);
                {
                    GLfloat
                        pos[]     = {5.0f, 5.0f, 0.0f, 1.0f},
                        ambient[] = {0.0f, 0.0f, 1.0f, 1.0f};
                    glLightfv(GL_LIGHT0, GL_POSITION, pos);
                    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
                }

                // 繪制一個(gè)球體
                glColor3f(1, 0, 0);
                glPushMatrix();
                glTranslatef(0, 0, 2);
                glutSolidSphere(0.5, 20, 20);
                glPopMatrix();
            }

            void display(void)
            {
                // 清除屏幕
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                // 設(shè)置觀察點(diǎn)
                glMatrixMode(GL_PROJECTION);
                glLoadIdentity();
                gluPerspective(60, 1, 5, 25);
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
                gluLookAt(5, 0, 6.5, 0, 0, 0, 0, 1, 0);

                glEnable(GL_DEPTH_TEST);

                // 繪制球體
                glDisable(GL_STENCIL_TEST);
                draw_sphere();

                // 繪制一個(gè)平面鏡。在繪制的同時(shí)注意設(shè)置模板緩沖。
                // 另外,為了保證平面鏡之后的鏡像能夠正確繪制,在繪制平面鏡時(shí)需要將深度緩沖區(qū)設(shè)置為只讀的。
                // 在繪制時(shí)暫時(shí)關(guān)閉光照效果
                glClearStencil(0);
                glClear(GL_STENCIL_BUFFER_BIT);
                glStencilFunc(GL_ALWAYS, 1, 0xFF);
                glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
                glEnable(GL_STENCIL_TEST);

                glDisable(GL_LIGHTING);
                glColor3f(0.5f, 0.5f, 0.5f);
                glDepthMask(GL_FALSE);
                glRectf(-1.5f, -1.5f, 1.5f, 1.5f);
                glDepthMask(GL_TRUE);

                // 繪制一個(gè)與先前球體關(guān)于平面鏡對(duì)稱的球體,注意光源的位置也要發(fā)生對(duì)稱改變
                // 因?yàn)槠矫骁R是在X軸和Y軸所確定的平面,所以只要Z坐標(biāo)取反即可實(shí)現(xiàn)對(duì)稱
                // 為了保證球體的繪制范圍被限制在平面鏡內(nèi)部,使用模板測(cè)試
                glStencilFunc(GL_EQUAL, 1, 0xFF);
                glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
                glScalef(1.0f, 1.0f, -1.0f);
                draw_sphere();

                // 交換緩沖
                glutSwapBuffers();

                // 截圖
                grab();
            }


            其中display函數(shù)的末尾調(diào)用了一個(gè)grab函數(shù),它保存當(dāng)前的圖象到一個(gè)BMP文件。這個(gè)函數(shù)本來(lái)是在第十課和第十一課中都有所使用的。但是我發(fā)現(xiàn)它有一個(gè)bug,現(xiàn)在進(jìn)行了修改:在函數(shù)最開(kāi)頭的部分加上一句:glReadBuffer(GL_FRONT);即可。注意這個(gè)函數(shù)最好是在繪制完畢后(如果是使用雙緩沖,則應(yīng)該在交換緩沖后)立即調(diào)用。


              大家可能會(huì)有這樣的感覺(jué):模板測(cè)試的設(shè)置是如此復(fù)雜,它可以實(shí)現(xiàn)的功能應(yīng)該很多,肯定不止這樣一個(gè)“限制像素的繪制范圍”。事實(shí)上也是如此,不過(guò)現(xiàn)在我們暫時(shí)只講這些。

            其實(shí),如果不需要繪制半透明效果,有時(shí)候可以用混合功能來(lái)代替模板測(cè)試。就繪制鏡像這個(gè)例子來(lái)說(shuō),可以采用下面的步驟:
            (1) 清除屏幕,在glClearColor中設(shè)置合適的值確保清除屏幕后像素的Alpha值為0.0
            (2) 關(guān)閉混合功能,繪制球體本身,設(shè)置合適的顏色(或者光照與材質(zhì))以確保所有被繪制的像素的Alpha值為0.0
            (3) 繪制平面鏡,設(shè)置合適的顏色(或者光照與材質(zhì))以確保所有被繪制的像素的Alpha值為1.0
            (4) 啟用混合功能,用GL_DST_ALPHA作為源因子,GL_ONE_MINUS_DST_ALPHA作為目標(biāo)因子,這樣就實(shí)現(xiàn)了只有原來(lái)Alpha為1.0的像素才能被修改,而原來(lái)Alpha為0.0的像素則保持不變。這時(shí)再繪制鏡像物體,注意確保所有被繪制的像素的Alpha值為1.0。
            在有的OpenGL實(shí)現(xiàn)中,模板測(cè)試是軟件實(shí)現(xiàn)的,而混合功能是硬件實(shí)現(xiàn)的,這時(shí)候可以考慮這樣的代替方法以提高運(yùn)行效率。但是并非所有的模板測(cè)試都可以用混合功能來(lái)代替,并且這樣的代替顯得不自然,復(fù)雜而且容易出錯(cuò)。
            另外始終注意:使用混合來(lái)模擬時(shí),即使某個(gè)像素原來(lái)的Alpha值為0.0,以致于在繪制后其顏色不會(huì)有任何變化,但是這個(gè)像素的深度值有可能會(huì)被修改,而如果是使用模板測(cè)試,沒(méi)有通過(guò)測(cè)試的像素其深度值不會(huì)發(fā)生任何變化。而且,模板測(cè)試和混合功能中,像素模板值的修改方式是不一樣的。
              

              4、深度測(cè)試
            在本課的開(kāi)頭,已經(jīng)簡(jiǎn)單的敘述了深度測(cè)試。這里是完整的內(nèi)容。

            深度測(cè)試需要深度緩沖區(qū),跟模板測(cè)試需要模板緩沖區(qū)是類似的。如果使用GLUT工具包,可以在調(diào)用glutInitDisplayMode函數(shù)時(shí)在參數(shù)中加上GLUT_DEPTH,這樣來(lái)明確指定要求使用深度緩沖區(qū)。
            深度測(cè)試和模板測(cè)試的實(shí)現(xiàn)原理很類似,都是在一個(gè)緩沖區(qū)保存像素的某個(gè)值,當(dāng)需要進(jìn)行測(cè)試時(shí),將保存的值與另一個(gè)值進(jìn)行比較,以確定是否通過(guò)測(cè)試。兩者的區(qū)別在于:模板測(cè)試是設(shè)定一個(gè)值,在測(cè)試時(shí)用這個(gè)設(shè)定值與像素的“模板值”進(jìn)行比較,而深度測(cè)試是根據(jù)頂點(diǎn)的空間坐標(biāo)計(jì)算出深度,用這個(gè)深度與像素的“深度值”進(jìn)行比較。也就是說(shuō),模板測(cè)試需要指定一個(gè)值作為比較參考,而深度測(cè)試中,這個(gè)比較用的參考值是OpenGL根據(jù)空間坐標(biāo)自動(dòng)計(jì)算的。

            通過(guò)glEnable/glDisable函數(shù)可以啟用或禁用深度測(cè)試。
            glEnable(GL_DEPTH_TEST);  // 啟用深度測(cè)試
            glDisable(GL_DEPTH_TEST); // 禁用深度測(cè)試

            至于通過(guò)測(cè)試的條件,同樣有八種,與Alpha測(cè)試中的條件設(shè)置相同。條件設(shè)置是通過(guò)glDepthFunc函數(shù)完成的,默認(rèn)值是GL_LESS。
            glDepthFunc(GL_LESS);

            與模板測(cè)試相比,深度測(cè)試的應(yīng)用要頻繁得多。幾乎所有的三維場(chǎng)景繪制都使用了深度測(cè)試。正因?yàn)檫@樣,幾乎所有的OpenGL實(shí)現(xiàn)都對(duì)深度測(cè)試提供了硬件支持,所以雖然兩者的實(shí)現(xiàn)原理類似,但深度測(cè)試很可能會(huì)比模板測(cè)試快得多。當(dāng)然了,兩種測(cè)試在應(yīng)用上很少有交集,一般不會(huì)出現(xiàn)使用一種測(cè)試去代替另一種測(cè)試的情況。


               小結(jié):
            本次課程介紹了OpenGL所提供的四種測(cè)試,分別是剪裁測(cè)試、Alpha測(cè)試、模板測(cè)試、深度測(cè)試。OpenGL會(huì)對(duì)每個(gè)即將繪制的像素進(jìn)行以上四種測(cè)試,每個(gè)像素只有通過(guò)一項(xiàng)測(cè)試后才會(huì)進(jìn)入下一項(xiàng)測(cè)試,而只有通過(guò)所有測(cè)試的像素才會(huì)被繪制,沒(méi)有通過(guò)測(cè)試的像素會(huì)被丟棄掉,不進(jìn)行繪制。每種測(cè)試都可以單獨(dú)的開(kāi)啟或者關(guān)閉,如果某項(xiàng)測(cè)試被關(guān)閉,則認(rèn)為所有像素都可以順利通過(guò)該項(xiàng)測(cè)試。
            剪裁測(cè)試是指:只有位于指定矩形內(nèi)部的像素才能通過(guò)測(cè)試。
            Alpha測(cè)試是指:只有Alpha值與設(shè)定值相比較,滿足特定關(guān)系條件的像素才能通過(guò)測(cè)試。
            模板測(cè)試是指:只有像素模板值與設(shè)定值相比較,滿足特定關(guān)系條件的像素才能通過(guò)測(cè)試。
            深度測(cè)試是指:只有像素深度值與新的深度值比較,滿足特定關(guān)系條件的像素才能通過(guò)測(cè)試。
            上面所說(shuō)的特定關(guān)系條件可以是大于、小于、等于、大于等于、小于等于、不等于、始終通過(guò)、始終不通過(guò)這八種。
            模板測(cè)試需要模板緩沖區(qū),深度測(cè)試需要深度緩沖區(qū)。這些緩沖區(qū)都是在初始化OpenGL時(shí)指定的。如果使用GLUT工具包,則可以在glutInitDisplayMode函數(shù)中指定。無(wú)論是否開(kāi)啟深度測(cè)試,OpenGL在像素被繪制時(shí)都會(huì)嘗試修改像素的深度值;而只有開(kāi)啟模板測(cè)試時(shí),OpenGL才會(huì)嘗試修改像素的模板值,模板測(cè)試被關(guān)閉時(shí),OpenGL在像素被繪制時(shí)也不會(huì)修改像素的模板值。
            利用這些測(cè)試操作可以控制像素被繪制或不被繪制,從而實(shí)現(xiàn)一些特殊效果。利用混合功能可以實(shí)現(xiàn)半透明,通過(guò)設(shè)置也可以實(shí)現(xiàn)完全透明,因而可以模擬像素顏色的繪制或不繪制。但注意,這里僅僅是顏色的模擬。OpenGL可以為像素保存顏色、深度值和模板值,利用混合實(shí)現(xiàn)透明時(shí),像素顏色不發(fā)生變化,但深度值則會(huì)可能變化,模板值受glStencilFunc函數(shù)中第三個(gè)參數(shù)影響;利用測(cè)試操作實(shí)現(xiàn)透明時(shí),像素顏色不發(fā)生變化,深度值也不發(fā)生變化,模板值受glStencilFunc函數(shù)中前兩個(gè)參數(shù)影響。
            此外,修正了第十課、第十一課中的一個(gè)函數(shù)中的bug。在grab函數(shù)中,應(yīng)該在最開(kāi)頭加上一句glReadBuffer(GL_FRONT);以保證讀取到的內(nèi)容正好就是顯示的內(nèi)容。

             

            本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/Crazyjumper/archive/2007/12/26/1968567.aspx

            posted @ 2009-09-01 06:27 RedLight 閱讀(634) | 評(píng)論 (0)編輯 收藏

            優(yōu)化3D圖形渲染通道負(fù)載(轉(zhuǎn))

            一般來(lái)說(shuō), 定位渲染通道瓶頸的方法就是改變渲染通道每個(gè)步驟的工作量, 如果吞吐量也改變了, 那個(gè)步驟就是瓶頸.。找到了瓶頸就要想辦法消除瓶頸, 可以減少該步驟的工作量, 增加其他步驟的工作量。

               一般在光柵化之前的瓶頸稱作”transform bound”, 三角形設(shè)置處理后的瓶頸稱作”fill bound”定位瓶頸的辦法:
            • 1.改變幀緩沖或者渲染目標(biāo)(Render Target)的顏色深度(16 到 32 位), 如果幀速改變了, 那么瓶頸應(yīng)該在幀緩沖(RenderTarget)的填充率上。
            • 2.否則試試改變貼圖大小和貼圖過(guò)濾設(shè)置, 如果幀速變了,那么瓶頸應(yīng)該是在貼圖這里。
            • 3.否則改變分辨率.如果幀速改變了, 那么改變一下pixel shader的指令數(shù)量, 如果幀速變了, 那么瓶頸應(yīng)該就是pixel shader. 否則瓶頸就在光柵化過(guò)程中。
            • 4.否則, 改變頂點(diǎn)格式的大小, 如果幀速改變了, 那么瓶頸應(yīng)該在顯卡帶寬上。
            • 5.如果以上都不是, 那么瓶頸就在CPU這一邊。
            • 優(yōu)化方法36條:
            • 1.盡量減少無(wú)用的頂點(diǎn)數(shù)據(jù), 比如貼圖坐標(biāo), 如果有Object使用2組有的使用1組, 那么不 要將他們放在一個(gè)vertex buffer中, 這樣可以減少傳輸?shù)臄?shù)據(jù)量。
            • 2.使用多個(gè)streamsource, 比如SkinMesh渲染, 可以把頂點(diǎn)坐標(biāo)和法線這些每一幀都要修改的數(shù)據(jù)放在一個(gè)動(dòng)態(tài)VB中, 其它不需要修改的(如貼圖坐標(biāo))放到一個(gè)靜態(tài)VB中, 這樣就減少了數(shù)據(jù)傳輸量。
            • 3.盡量使用16位的索引緩沖,避免32位的. 一方面浪費(fèi)帶寬, 一方面也不是所有的顯卡都支持32位的索引緩沖。
            • 4.可以考慮使用vertex shader來(lái)計(jì)算靜態(tài)VB中的數(shù)據(jù).比如SkinMesh的頂點(diǎn)可以放到vectex shader中計(jì)算, 這樣就可以避免每一幀都從AGP內(nèi)存中向顯存?zhèn)魉蛿?shù)據(jù). 這樣也可以使用靜態(tài)VB了。
            • 5.堅(jiān)決避免使用Draw**UP一族的函數(shù)來(lái)繪制多邊形。
            • 6.在設(shè)計(jì)程序之前好好規(guī)劃一下顯卡內(nèi)存的使用, 確保framebuffer, 貼圖, 靜態(tài)VB能夠正好放入顯卡的本地內(nèi)存中。
            • 7.盡量使頂點(diǎn)格式大小是32字節(jié)的倍數(shù).可以考慮使用壓縮過(guò)的頂點(diǎn)格式然后用vertex shader去解. 或者留下冗余的部分, 使頂點(diǎn)大小剛好使32字節(jié)的倍數(shù)。
            • 8.頂點(diǎn)在頂點(diǎn)緩沖中的順序盡量符合繪制的順序, 考慮使用strips來(lái)代替list。
            • 9.如果可能盡量多的使用static vertex buffer代替dynamic vertex buffer。
            • 10.動(dòng)態(tài)VB使用DISCARD參數(shù)來(lái)lock更新, 使用NOOVERWRITE來(lái)添加.盡量不要使用不帶參數(shù)的lock調(diào)用(0)。
            • 11.盡量減少lock的次數(shù), 有些東西并不一定非要每一幀都更新VB, 比如人物動(dòng)畫(huà)一般每秒鐘更新30次VB基本上就夠了。
            • 12.如果是因?yàn)樾枰L制的頂點(diǎn)數(shù)據(jù)太多了可以考慮使用LOD, 但是現(xiàn)在的顯卡的繪制能力都很強(qiáng)勁, 所以需要權(quán)衡一下LOD是否能夠帶來(lái)相應(yīng)的好處, 如果過(guò)分的強(qiáng)化LOD很可能將瓶頸轉(zhuǎn)移到CPU這邊。
            • 13.避免過(guò)多的頂點(diǎn)計(jì)算,比如過(guò)多的光源, 過(guò)于復(fù)雜的光照計(jì)算(復(fù)雜的光照模型), 紋理自動(dòng)生成的開(kāi)啟也會(huì)增加頂點(diǎn)的計(jì)算量. 如果貼圖坐標(biāo)變換矩陣不是單位矩陣, 也會(huì)造成頂點(diǎn)計(jì)算量的增加, 所以如果紋理變換已經(jīng)結(jié)束, 記得要將紋理變換矩陣設(shè)為單位矩陣同時(shí)調(diào)整貼圖坐標(biāo)。
            • 14.避免Vertex shader指令數(shù)量太多或者分支過(guò)多, 盡量減少vertex shader的長(zhǎng)度和復(fù)雜程度. 盡量使用swizzling代替mov。
            • 15.如果圖象質(zhì)量方面的計(jì)算(pixel shader)范圍很大, 并且很復(fù)雜, 可以考慮試試全屏反走樣。說(shuō)不定更快。
            • 16.盡量按照f(shuō)ront – back的順序來(lái)繪制。
            • 17.在shader中判斷Z值可以避免繪制不可見(jiàn)的象素, 但是nvidia建議簡(jiǎn)單的shader不要這么做.(Don't do this in a simple shader)。
            • 18.如果可能, 盡量使用vertex shader來(lái)代替pixel shader.將計(jì)算從逐象素變成逐頂點(diǎn)。
            • 19.盡量降低貼圖的大小.過(guò)大的貼圖可能造成貼圖cache過(guò)載, 從而導(dǎo)致貼圖cache命中降低.過(guò)大的貼圖會(huì)導(dǎo)致顯存過(guò)載, 這時(shí)候貼圖是從系統(tǒng)內(nèi)存中取的。
            • 20.只要可能就用16位色的貼圖, 如環(huán)境貼圖或者shadow map.它們用32位色的貼圖實(shí)在是浪費(fèi)。
            • 21.考慮使用DXT 貼圖壓縮。
            • 22.如果可能,使用簡(jiǎn)單的貼圖過(guò)濾或者mip map, 除非必要否則盡量不要使用三線過(guò)濾和各項(xiàng)異性過(guò)濾. light map 和 環(huán)境貼圖基本上都不需要使用它們。
            • 23.只有真正需要修改的貼圖才使用Dynamic, 并且使用DISCRAD和WRITEONLY來(lái)lock。
            • 24.太多的幀緩沖讀寫(xiě)可以考慮關(guān)閉Z-Writes如有些多pass的渲染中的后續(xù)pass或者粒子系統(tǒng)等半透明幾何物體(如果可以)。
            • 25.可能的話盡量使用alpha test代替alpha blending。
            • 26.如果不需要stencil buffer就盡量使用16位的Z buffer。
            • 27.減小RenderTarget 貼圖的大小, 如shadow map 環(huán)境貼圖. 可能根本不需要那么大效果就很好。
            • 28.Stencil 和 Z buffer 盡量一起clear. 他們本來(lái)就是一塊緩沖。
            • 29.盡量減少渲染狀態(tài)的切換, 盡量一次畫(huà)盡可能多的多邊形。(根據(jù)顯卡性能決定最多畫(huà)多少, 不過(guò)一般再多也不會(huì)多到哪里去。 除非你根本不需要貼圖和渲染狀態(tài)的切換)。
            • 30.盡量使用shader來(lái)代替Fixed Pipeline。
            • 31.盡量使用shader來(lái)實(shí)現(xiàn)來(lái)取代Multipass渲染效果。
            • 32.盡量?jī)?yōu)先先建立重要的資源, 如Render target, shaders, 貼圖, VB, IB等等.以免顯存過(guò)載的時(shí)候它們被創(chuàng)建到系統(tǒng)內(nèi)存中。
            • 33.堅(jiān)決不要在渲染循環(huán)中調(diào)用創(chuàng)建資源。
            • 34.按照shader和貼圖分組后再渲染.先按照shaders分組再按貼圖。
            • 35.Color Stencil Z buffer盡量在一次Clear調(diào)用中清除。
            • 36.一個(gè)Vertex buffer 的大小在2M-4M之間最好。

            posted @ 2009-09-01 01:32 RedLight 閱讀(596) | 評(píng)論 (0)編輯 收藏

            OpenGL Performance Optimization(轉(zhuǎn))

            SIGGRAPH '97

            Course 24: OpenGL and Window System Integration

            OpenGL Performance Optimization



            Contents



            1. Hardware vs. Software

            OpenGL may be implemented by any combination of hardware and software. At the high-end, hardware may implement virtually all of OpenGL while at the low-end, OpenGL may be implemented entirely in software. In between are combination software/hardware implementations. More money buys more hardware and better performance.

            Intro-level workstation hardware and the recent PC 3-D hardware typically implement point, line, and polygon rasterization in hardware but implement floating point transformations, lighting, and clipping in software. This is a good strategy since the bottleneck in 3-D rendering is usually rasterization and modern CPU's have sufficient floating point performance to handle the transformation stage.

            OpenGL developers must remember that their application may be used on a wide variety of OpenGL implementations. Therefore one should consider using all possible optimizations, even those which have little return on the development system, since other systems may benefit greatly.

            From this point of view it may seem wise to develop your application on a low-end system. There is a pitfall however; some operations which are cheep in software may be expensive in hardware. The moral is: test your application on a variety of systems to be sure the performance is dependable.



            2. Application Organization

            At first glance it may seem that the performance of interactive OpenGL applications is dominated by the performance of OpenGL itself. This may be true in some circumstances but be aware that the organization of the application is also significant.

            2.1 High Level Organization

            Multiprocessing

            Some graphical applications have a substantial computational component other than 3-D rendering. Virtual reality applications must compute object interactions and collisions. Scientific visualization programs must compute analysis functions and graphical representations of data.

            One should consider multiprocessing in these situations. By assigning rendering and computation to different threads they may be executed in parallel on multiprocessor computers.

            For many applications, supporting multiprocessing is just a matter of partitioning the render and compute operations into separate threads which share common data structures and coordinate with synchronization primitives.

            SGI's Performer is an example of a high level toolkit designed for this purpose.

            Image quality vs. performance

            In general, one wants high-speed animation and high-quality images in an OpenGL application. If you can't have both at once a reasonable compromise may be to render at low complexity during animation and high complexity for static images.

            Complexity may refer to the geometric or rendering attributes of a database. Here are a few examples.

            • During interactive rotation (i.e. mouse button held down) render a reduced-polygon model. When drawing a static image draw the full polygon model.
            • During animation, disable dithering, smooth shading, and/or texturing. Enable them for the static image.
            • If texturing is required, use GL_NEAREST sampling and glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST ).
            • During animation, disable antialiasing. Enable antialiasing for the static image.
            • Use coarser NURBS/evaluator tesselation during animation. Use glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ) to inspect tesselation granularity and reduce if possible.

            Level of detail management and culling

            Objects which are distant from the viewer may be rendered with a reduced complexity model. This strategy reduces the demands on all stages of the graphics pipeline. Toolkits such as Inventor and Performer support this feature automatically.

            Objects which are entirely outside of the field of view may be culled. This type of high level cull testing can be done efficiently with bounding boxes or spheres and have a major impact on performance. Again, toolkits such as Inventor and Performer have this feature.

            2.2 Low Level Organization

            The objects which are rendered with OpenGL have to be stored in some sort of data structure. Some data structures are more efficient than others with respect to how quickly they can be rendered.

            Basically, one wants data structures which can be traversed quickly and passed to the graphics library in an efficient manner. For example, suppose we need to render a triangle strip. The data structure which stores the list of vertices may be implemented with a linked list or an array. Clearly the array can be traversed more quickly than a linked list. The way in which a vertex is stored in the data structure is also significant. High performance hardware can process vertexes specified by a pointer more quickly than those specified by three separate parameters.

            An Example

            Suppose we're writing an application which involves drawing a road map. One of the components of the database is a list of cities specified with a latitude, longitude and name. The data structure describing a city may be:
            	struct city {
            float latitute, longitude;	/* city location */
            char *name;			/* city's name */
            int large_flag;  		/* 0 = small, 1 = large */
            };
            
            A list of cities may be stored as an array of city structs.

            Our first attempt at rendering this information may be:

            	void draw_cities( int n, struct city citylist[] )
            {
            int i;
            for (i=0; i < n; i++) {
            if (citylist[i].large_flag) {
            glPointSize( 4.0 );
            }
            else {
            glPointSize( 2.0 );
            }
            glBegin( GL_POINTS );
            glVertex2f( citylist[i].longitude, citylist[i].latitude );
            glEnd();
            glRasterPos2f( citylist[i].longitude, citylist[i].latitude );
            glCallLists( strlen(citylist[i].name),
            GL_BYTE,
            citylist[i].name );
            }
            }
            
            This is a poor implementation for a number of reasons:
            • glPointSize is called for every loop iteration.
            • only one point is drawn between glBegin and glEnd
            • the vertices aren't being specified in the most efficient manner
            Here's a better implementation:
            	void draw_cities( int n, struct city citylist[] )
            {
            int i;
            /* draw small dots first */
            glPointSize( 2.0 );
            glBegin( GL_POINTS );
            for (i=0; i < n ;i++) {
            if (citylist[i].large_flag==0) {
            glVertex2f( citylist[i].longitude, citylist[i].latitude );
            }
            }
            glEnd();
            /* draw large dots second */
            glPointSize( 4.0 );
            glBegin( GL_POINTS );
            for (i=0; i < n ;i++) {
            if (citylist[i].large_flag==1) {
            glVertex2f( citylist[i].longitude, citylist[i].latitude );
            }
            }
            glEnd();
            /* draw city labels third */
            for (i=0; i < n ;i++) {
            glRasterPos2f( citylist[i].longitude, citylist[i].latitude );
            glCallLists( strlen(citylist[i].name),
            GL_BYTE,
            citylist[i].name );
            }
            }
            
            In this implementation we're only calling glPointSize twice and we're maximizing the number of vertices specified between glBegin and glEnd.

            We can still do better, however. If we redesign the data structures used to represent the city information we can improve the efficiency of drawing the city points. For example:

            	struct city_list {
            int num_cities;		/* how many cities in the list */
            float *position;	/* pointer to lat/lon coordinates */
            char **name;		/* pointer to city names */
            float size;		/* size of city points */
            };
            
            Now cities of different sizes are stored in separate lists. Position are stored sequentially in a dynamically allocated array. By reorganizing the data structures we've eliminated the need for a conditional inside the glBegin/glEnd loops. Also, we can render a list of cities using the GL_EXT_vertex_array extension if available, or at least use a more efficient version of glVertex and glRasterPos.
            	/* indicates if server can do GL_EXT_vertex_array: */
            GLboolean varray_available;
            void draw_cities( struct city_list *list )
            {
            int i;
            GLboolean use_begin_end;
            /* draw the points */
            glPointSize( list->size );
            #ifdef GL_EXT_vertex_array
            if (varray_available) {
            glVertexPointerEXT( 2, GL_FLOAT, 0, list->num_cities, list->position );
            glDrawArraysEXT( GL_POINTS, 0, list->num_cities );
            use_begin_end = GL_FALSE;
            }
            else
            #else
            {
            use_begin_end = GL_TRUE;
            }
            #endif
            if (use_begin_end) {
            glBegin(GL_POINTS);
            for (i=0; i < list->num_cities; i++) {
            glVertex2fv( &position[i*2] );
            }
            glEnd();
            }
            /* draw city labels */
            for (i=0; i < list->num_cities ;i++) {
            glRasterPos2fv( list->position[i*2] );
            glCallLists( strlen(list->name[i]),
            GL_BYTE, list->name[i] );
            }
            }
            
            As this example shows, it's better to know something about efficient rendering techniques before designing the data structures. In many cases one has to find a compromize between data structures optimized for rendering and those optimized for clarity and convenience.

            In the following sections the techniques for maximizing performance, as seen above, are explained.



            3. OpenGL Optimization

            There are many possibilities to improving OpenGL performance. The impact of any single optimization can vary a great deal depending on the OpenGL implementation. Interestingly, items which have a large impact on software renderers may have no effect on hardware renderers, and vice versa! For example, smooth shading can be expensive in software but free in hardware While glGet* can be cheap in software but expensive in hardware.

            After each of the following techniques look for a bracketed list of symbols which relates the significance of the optimization to your OpenGL system:

            • H - beneficial for high-end hardware
            • L - beneficial for low-end hardware
            • S - beneficial for software implementations
            • all - probably beneficial for all implementations

            3.1 Traversal

            Traversal is the sending of data to the graphics system. Specifically, we want to minimize the time taken to specify primitives to OpenGL.
            Use connected primitives
            Connected primitives such as GL_LINES, GL_LINE_LOOP, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, and GL_QUAD_STRIP require fewer vertices to describe an object than individual line, triangle, or polygon primitives. This reduces data transfer and transformation workload. [all]
            Use the vertex array extension
            On some architectures function calls are somewhat expensive so replacing many glVertex/glColor/glNormal calls with the vertex array mechanism may be very beneficial. [all]
            Store vertex data in consecutive memory locations
            When maximum performance is needed on high-end systems it's good to store vertex data in contiguous memory to maximize through put of data from host memory to graphics subsystem. [H,L]
            Use the vector versions of glVertex, glColor, glNormal and glTexCoord
            The glVertex, glColor, etc. functions which take a pointer to their arguments such as glVertex3fv(v) may be much faster than those which take individual arguments such as glVertex3f(x,y,z) on systems with DMA-driven graphics hardware. [H,L]
            Reduce quantity of primitives
            Be careful not to render primitives which are over-tesselated. Experiment with the GLU primitives, for example, to determine the best compromise of image quality vs. tesselation level. Textured objects in particular may still be rendered effectively with low geometric complexity. [all]
            Display lists
            Use display lists to encapsulate frequently drawn objects. Display list data may be stored in the graphics subsystem rather than host memory thereby eliminating host-to-graphics data movement. Display lists are also very beneficial when rendering remotely. [all]
            Don't specify unneeded per-vertex information
            If lighting is disabled don't call glNormal. If texturing is disabled don't call glTexCoord, etc.
            Minimize code between glBegin/glEnd
            For maximum performance on high-end systems it's extremely important to send vertex data to the graphics system as fast as possible. Avoid extraneous code between glBegin/glEnd.

            Example:

            	glBegin( GL_TRIANGLE_STRIP );
            for (i=0; i < n; i++) {
            if (lighting) {
            glNormal3fv( norm[i] );
            }
            glVertex3fv( vert[i] );
            }
            glEnd();
            

            This is a very bad construct. The following is much better:

            	if (lighting) {
            glBegin( GL_TRIANGLE_STRIP );
            for (i=0; i < n ;i++) {
            glNormal3fv( norm[i] );
            glVertex3fv( vert[i] );
            }
            glEnd();
            }
            else {
            glBegin( GL_TRIANGLE_STRIP );
            for (i=0; i < n ;i++) {
            glVertex3fv( vert[i] );
            }
            glEnd();
            }
            
            Also consider manually unrolling important rendering loops to maximize the function call rate.

            3.2 Transformation

            Transformation includes the transformation of vertices from glVertex to window coordinates, clipping and lighting.

            Lighting
            • Avoid using positional lights, i.e. light positions should be of the form (x,y,z,0) [L,S]
            • Avoid using spotlights. [all]
            • Avoid using two-sided lighting. [all]
            • Avoid using negative material and light color coefficients [S]
            • Avoid using the local viewer lighting model. [L,S]
            • Avoid frequent changes to the GL_SHININESS material parameter. [L,S]
            • Some OpenGL implementations are optimized for the case of a single light source.
            • Consider pre-lighting complex objects before rendering, ala radiosity. You can get the effect of lighting by specifying vertex colors instead of vertex normals. [S]
            Two sided lighting
            If you want both the front and back of polygons shaded the same try using two light sources instead of two-sided lighting. Position the two light sources on opposite sides of your object. That way, a polygon will always be lit correctly whether it's back or front facing. [L,S]
            Disable normal vector normalization when not needed
            glEnable/Disable(GL_NORMALIZE) controls whether normal vectors are scaled to unit length before lighting. If you do not use glScale you may be able to disable normalization without ill effects. Normalization is disabled by default. [L,S]
            Use connected primitives
            Connected primitives such as GL_LINES, GL_LINE_LOOP, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, and GL_QUAD_STRIP decrease traversal and transformation load.
            glRect usage
            If you have to draw many rectangles consider using glBegin(GL_QUADS) ... glEnd() instead. [all]

            3.3 Rasterization

            Rasterization is the process of generating the pixels which represent points, lines, polygons, bitmaps and the writing of those pixels to the frame buffer. Rasterization is often the bottleneck in software implementations of OpenGL.
            Disable smooth shading when not needed
            Smooth shading is enabled by default. Flat shading doesn't require interpolation of the four color components and is usually faster than smooth shading in software implementations. Hardware may perform flat and smooth-shaded rendering at the same rate though there's at least one case in which smooth shading is faster than flat shading (E&S Freedom). [S]
            Disable depth testing when not needed
            Background objects, for example, can be drawn without depth testing if they're drawn first. Foreground objects can be drawn without depth testing if they're drawn last. [L,S]
            Disable dithering when not needed
            This is easy to forget when developing on a high-end machine. Disabling dithering can make a big difference in software implementations of OpenGL on lower-end machines with 8 or 12-bit color buffers. Dithering is enabled by default. [S]
            Use back-face culling whenever possible.
            If you're drawing closed polyhedra or other objects for which back facing polygons aren't visible there's probably no point in drawing those polygons. [all]
            The GL_SGI_cull_vertex extension
            SGI's Cosmo GL supports a new culling extension which looks at vertex normals to try to improve the speed of culling.
            Avoid extra fragment operations
            Stenciling, blending, stippling, alpha testing and logic ops can all take extra time during rasterization. Be sure to disable the operations which aren't needed. [all]
            Reduce the window size or screen resolution
            A simple way to reduce rasterization time is to reduce the number of pixels drawn. If a smaller window or reduced display resolution are acceptable it's an easy way to improve rasterization speed. [L,S]

            3.4 Texturing

            Texture mapping is usually an expensive operation in both hardware and software. Only high-end graphics hardware can offer free to low-cost texturing. In any case there are several ways to maximize texture mapping performance.
            Use efficient image formats
            The GL_UNSIGNED_BYTE component format is typically the fastest for specifying texture images. Experiment with the internal texture formats offered by the GL_EXT_texture extension. Some formats are faster than others on some systems (16-bit texels on the Reality Engine, for example). [all]
            Encapsulate texture maps in texture objects or display lists
            This is especially important if you use several texture maps. By putting textures into display lists or texture objects the graphics system can manage their storage and minimize data movement between the client and graphics subsystem. [all]
            Use smaller texture maps
            Smaller images can be moved from host to texture memory faster than large images. More small texture can be stored simultaneously in texture memory, reducing texture memory swapping. [all]
            Use simpler sampling functions
            Experiment with the minification and magnification texture filters to determine which performs best while giving acceptable results. Generally, GL_NEAREST is fastest and GL_LINEAR is second fastest. [all]
            Use the same sampling function for minification and magnification
            If both the minification and magnification filters are GL_NEAREST or GL_LINEAR then there's no reason OpenGL has to compute the lambda value which determines whether to use minification or magnification sampling for each fragment. Avoiding the lambda calculation can be a good performace improvement.
            Use a simpler texture environment function
            Some texture environment modes may be faster than others. For example, the GL_DECAL or GL_REPLACE_EXT functions for 3 component textures is a simple assignment of texel samples to fragments while GL_MODULATE is a linear interpolation between texel samples and incoming fragments. [S,L]
            Combine small textures
            If you are using several small textures consider tiling them together as a larger texture and modify your texture coordinates to address the subtexture you want. This technique can eliminate texture bindings.
            Use glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)
            This hint can improve the speed of texturing when perspective- correct texture coordinate interpolation isn't needed, such as when using a glOrtho() projection.
            Animated textures
            If you want to use an animated texture, perhaps live video textures, don't use glTexImage2D to repeatedly change the texture. Use glTexSubImage2D or glTexCopyTexSubImage2D. These functions are standard in OpenGL 1.1 and available as extensions to 1.0.

            3.5 Clearing

            Clearing the color, depth, stencil and accumulation buffers can be time consuming, especially when it has to be done in software. There are a few tricks which can help.
            Use glClear carefully [all]
            Clear all relevant color buffers with one glClear.

            Wrong:

              glClear( GL_COLOR_BUFFER_BIT );
            if (stenciling) {
            glClear( GL_STENCIL_BUFFER_BIT );
            }
            
            Right:

              if (stenciling) {
            glClear( GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
            }
            else {
            glClear( GL_COLOR_BUFFER_BIT );
            }
            
            Disable dithering
            Disable dithering before clearing the color buffer. Visually, the difference between dithered and undithered clears is usually negligable.
            Use scissoring to clear a smaller area
            If you don't need to clear the whole buffer use glScissor() to restrict clearing to a smaller area. [L].
            Don't clear the color buffer at all
            If the scene you're drawing opaquely covers the entire window there is no reason to clear the color buffer.
            Eliminate depth buffer clearing
            If the scene you're drawing covers the entire window there is a trick which let's you omit the depth buffer clear. The idea is to only use half the depth buffer range for each frame and alternate between using GL_LESS and GL_GREATER as the depth test function.

            Example:

               int EvenFlag;
            /* Call this once during initialization and whenever the window
            * is resized.
            */
            void init_depth_buffer( void )
            {
            glClearDepth( 1.0 );
            glClear( GL_DEPTH_BUFFER_BIT );
            glDepthRange( 0.0, 0.5 );
            glDepthFunc( GL_LESS );
            EvenFlag = 1;
            }
            /* Your drawing function */
            void display_func( void )
            {
            if (EvenFlag) {
            glDepthFunc( GL_LESS );
            glDepthRange( 0.0, 0.5 );
            }
            else {
            glDepthFunc( GL_GREATER );
            glDepthRange( 1.0, 0.5 );
            }
            EvenFlag = !EvenFlag;
            /* draw your scene */
            }
            
            Avoid glClearDepth( d ) where d!=1.0
            Some software implementations may have optimized paths for clearing the depth buffer to 1.0. [S]

            3.6 Miscellaneous

            Avoid "round-trip" calls
            Calls such as glGetFloatv, glGetIntegerv, glIsEnabled, glGetError, glGetString require a slow, round trip transaction between the application and renderer. Especially avoid them in your main rendering code.

            Note that software implementations of OpenGL may actually perform these operations faster than hardware systems. If you're developing on a low-end system be aware of this fact. [H,L]

            Avoid glPushAttrib
            If only a few pieces of state need to be saved and restored it's often faster to maintain the information in the client program. glPushAttrib( GL_ALL_ATTRIB_BITS ) in particular can be very expensive on hardware systems. This call may be faster in software implementations than in hardware. [H,L]
            Check for GL errors during development
            During development call glGetError inside your rendering/event loop to catch errors. GL errors raised during rendering can slow down rendering speed. Remove the glGetError call for production code since it's a "round trip" command and can cause delays. [all]
            Use glColorMaterial instead of glMaterial
            If you need to change a material property on a per vertex basis, glColorMaterial may be faster than glMaterial. [all]
            glDrawPixels
            • glDrawPixels often performs best with GL_UNSIGNED_BYTE color components [all]
            • Disable all unnecessary raster operations before calling glDrawPixels. [all]
            • Use the GL_EXT_abgr extension to specify color components in alpha, blue, green, red order on systems which were designed for IRIS GL. [H,L].
            Avoid using viewports which are larger than the window
            Software implementations may have to do additional clipping in this situation. [S]
            Alpha planes
            Don't allocate alpha planes in the color buffer if you don't need them. Specifically, they are not needed for transparency effects. Systems without hardware alpha planes may have to resort to a slow software implementation. [L,S]
            Accumulation, stencil, overlay planes
            Do not allocate accumulation, stencil or overlay planes if they are not needed. [all]
            Be aware of the depth buffer's depth
            Your OpenGL may support several different sizes of depth buffers- 16 and 24-bit for example. Shallower depth buffers may be faster than deep buffers both for software and hardware implementations. However, the precision of of a 16-bit depth buffer may not be sufficient for some applications. [L,S]
            Transparency may be implemented with stippling instead of blending
            If you need simple transparent objects consider using polygon stippling instead of alpha blending. The later is typically faster and may actually look better in some situations. [L,S]
            Group state changes together
            Try to mimimize the number of GL state changes in your code. When GL state is changed, internal state may have to be recomputed, introducing delays. [all]
            Avoid using glPolygonMode
            If you need to draw many polygon outlines or vertex points use glBegin with GL_POINTS, GL_LINES, GL_LINE_LOOP or GL_LINE_STRIP instead as it can be much faster. [all]

            3.7 Window System Integration

            Minimize calls to the make current call
            The glXMakeCurrent call, for example, can be expensive on hardware systems because the context switch may involve moving a large amount of data in and out of the hardware.
            Visual / pixel format performance
            Some X visuals or pixel formats may be faster than others. On PCs for example, 24-bit color buffers may be slower to read/write than 12 or 8-bit buffers. There is often a tradeoff between performance and quality of frame buffer configurations. 12-bit color may not look as nice as 24-bit color. A 16-bit depth buffer won't have the precision of a 24-bit depth buffer.

            The GLX_EXT_visual_rating extension can help you select visuals based on performance or quality. GLX 1.2's visual caveat attribute can tell you if a visual has a performance penalty associated with it.

            It may be worthwhile to experiment with different visuals to determine if there's any advantage of one over another.

            Avoid mixing OpenGL rendering with native rendering
            OpenGL allows both itself and the native window system to render into the same window. For this to be done correctly synchronization is needed. The GLX glXWaitX and glXWaitGL functions serve this purpose.

            Synchronization hurts performance. Therefore, if you need to render with both OpenGL and native window system calls try to group the rendering calls to minimize synchronization.

            For example, if you're drawing a 3-D scene with OpenGL and displaying text with X, draw all the 3-D elements first, call glXWaitGL to synchronize, then call all the X drawing functions.

            Don't redraw more than necessary
            Be sure that you're not redrawing your scene unnecissarily. For example, expose/repaint events may come in batches describing separate regions of the window which must be redrawn. Since one usually redraws the whole window image with OpenGL you only need to respond to one expose/repaint event. In the case of X, look at the count field of the XExposeEvent structure. Only redraw when it is zero.

            Also, when responding to mouse motion events you should skip extra motion events in the input queue. Otherwise, if you try to process every motion event and redraw your scene there will be a noticable delay between mouse input and screen updates.

            It can be a good idea to put a print statement in your redraw and event loop function so you know exactly what messages are causing your scene to be redrawn, and when.

            SwapBuffer calls and graphics pipe blocking
            On systems with 3-D graphics hardware the SwapBuffers call is synchronized to the monitor's vertical retrace. Input to the OpenGL command queue may be blocked until the buffer swap has completed. Therefore, don't put more OpenGL calls immediately after SwapBuffers. Instead, put application computation instructions which can overlap with the buffer swap delay.

            3.8 Mesa-specific

            Mesa is a free library which implements most of the OpenGL API in a compatible manner. Since it is a software library, performance depends a great deal on the host computer. There are several Mesa-specific features to be aware of which can effect performance.

            Double buffering
            The X driver supports two back color buffer implementations: Pixmaps and XImages. The MESA_BACK_BUFFER environment variable controls which is used. Which of the two that's faster depends on the nature of your rendering. Experiment.
            X Visuals
            As described above, some X visuals can be rendered into more quickly than others. The MESA_RGB_VISUAL environment variable can be used to determine the quickest visual by experimentation.
            Depth buffers
            Mesa may use a 16 or 32-bit depth buffer as specified in the src/config.h configuration file. 16-bit depth buffers are faster but may not offer the precision needed for all applications.
            Flat-shaded primitives
            If one is drawing a number of flat-shaded primitives all of the same color the glColor command should be put before the glBegin call.

            Don't do this:

            	glBegin(...);
            glColor(...);
            glVertex(...);
            ...
            glEnd();
            

            Do this:

            	glColor(...);
            glBegin(...);
            glVertex(...);
            ...
            glEnd();
            
            glColor*() commands
            The glColor[34]ub[v] are the fastest versions of the glColor command.
            Avoid double precision valued functions
            Mesa does all internal floating point computations in single precision floating point. API functions which take double precision floating point values must convert them to single precision. This can be expensive in the case of glVertex, glNormal, etc.


            4. Evaluation and Tuning

            To maximize the performance of an OpenGL applications one must be able to evaluate an application to learn what is limiting its speed. Because of the hardware involved it's not sufficient to use ordinary profiling tools. Several different aspects of the graphics system must be evaluated.

            Performance evaluation is a large subject and only the basics are covered here. For more information see "OpenGL on Silicon Graphics Systems".

            4.1 Pipeline tuning

            The graphics system can be divided into three subsystems for the purpose of performance evaluation:
            • CPU subsystem - application code which drives the graphics subsystem
            • Geometry subsystem - transformation of vertices, lighting, and clipping
            • Rasterization subsystem - drawing filled polygons, line segments and per-pixel processing
            At any given time, one of these stages will be the bottleneck. The bottleneck must be reduced to improve performance. The strategy is to isolate each subsystem in turn and evaluate changes in performance. For example, by decreasing the workload of the CPU subsystem one can determine if the CPU or graphics system is limiting performance.

            4.1.1 CPU subsystem

            To isosulate the CPU subsystem one must reduce the graphics workload while presevering the application's execution characteristics. A simple way to do this is to replace glVertex() and glNormal calls with glColor calls. If performance does not improve then the CPU stage is the bottleneck.

            4.1.2 Geometry subsystem

            To isoslate the geometry subsystem one wants to reduce the number of primitives processed, or reduce the transformation work per primitive while producing the same number of pixels during rasterization. This can be done by replacing many small polygons with fewer large ones or by simply disabling lighting or clipping. If performance increases then your application is bound by geometry/transformation speed.

            4.1.3 Rasterization subsystem

            A simple way to reduce the rasterization workload is to make your window smaller. Other ways to reduce rasterization work is to disable per-pixel processing such as texturing, blending, or depth testing. If performance increases, your program is fill limited.

            After bottlenecks have been identified the techniques outlined in section 3 can be applied. The process of identifying and reducing bottlenecks should be repeated until no further improvements can be made or your minimum performance threshold has been met.

            4.2 Double buffering

            For smooth animation one must maintain a high, constant frame rate. Double buffering has an important effect on this. Suppose your application needs to render at 60Hz but is only getting 30Hz. It's a mistake to think that you must reduce rendering time by 50% to achive 60Hz. The reason is the swap-buffers operation is synchronized to occur during the display's vertical retrace period (at 60Hz for example). It may be that your application is taking only a tiny bit too long to meet the 1/60 second rendering time limit for 60Hz.

            Measure the performance of rendering in single buffer mode to determine how far you really are from your target frame rate.

            4.3 Test on several implementations

            The performance of OpenGL implementations varies a lot. One should measure performance and test OpenGL applications on several different systems to be sure there are no unexpected problems.


            posted @ 2009-08-25 06:05 RedLight 閱讀(907) | 評(píng)論 (0)編輯 收藏

            游戲Entity設(shè)計(jì)不完全整理(轉(zhuǎn))

            在游戲引擎中,Entity通常被翻譯成實(shí)體,也常用諸如GameObject、Actor、SimulationObject、Unit、Character等名字。相比于對(duì)圖像聲音引擎的熱情,Entity層多年來(lái)一直備受冷遇,但最近幾年隨著大型游戲的發(fā)展,Entity層設(shè)計(jì)的重要性已經(jīng)達(dá)到和圖像聲音的同等水平,而且已經(jīng)出現(xiàn)了多種通用型Entity架構(gòu)。當(dāng)然,這里伴隨著爭(zhēng)議和分歧。

            直接模式(The C Approach

            這是最早、最簡(jiǎn)單、也是任何人都能直接想到的模式。這種方式下一個(gè)Entity就是一個(gè)簡(jiǎn)單的struct:

            struct Mob
            {
            int level, hp, mp, attack, …;
            };

            這種情況下往往需要對(duì)不同類型的Entity定義不同的struct,比如Player、Mob、ItemDoodad等。Entity的數(shù)據(jù)庫(kù)可以直接使用現(xiàn)成的數(shù)據(jù)庫(kù)系統(tǒng)或者從數(shù)據(jù)文件讀取,比如csv文件。一般會(huì)選擇Excel編輯數(shù)據(jù)庫(kù),然后導(dǎo)出csvExcel的強(qiáng)大表格和統(tǒng)計(jì)計(jì)算功能是調(diào)節(jié)游戲數(shù)據(jù)平衡的得力工具。以致這種最古老而簡(jiǎn)單的Entity模式以強(qiáng)大的生命力一直活到現(xiàn)在。

            那么為什么Developers會(huì)要去探索其他方式呢?最大的問(wèn)題是這種方式下各種Entity完全不同質(zhì)。比如Player、MobDoodad都有位置,都要做碰撞檢測(cè),但他們卻是不同的類型,不能使用同一份代碼;PlayerMob都有hpmp,也有基本相同的處理邏輯……當(dāng)然,這個(gè)可以用hack的方法解決:只要各個(gè)struct前若干個(gè)成員類型和順序完全相同,就可以將指針cast成統(tǒng)一的一個(gè)Entity類型來(lái)處理。不過(guò),任何人都能想到更好的辦法,用類!

            繼承模式(Inheritage

            這也是EntityGameObject等這些名字的由來(lái),他們就是基類。于是我們可以得到一顆繼承關(guān)系樹(shù),例如:

            Entity

                   Character

                          Player

                          Mob

                   Missile

                          Laser

                          GuidedMissile

                   Item

                  

            Entity對(duì)象的邏輯大多也是直接包含在類里的。但也有人采用了數(shù)據(jù)對(duì)象和邏輯對(duì)象的分離,其好處是對(duì)相同的數(shù)據(jù)可以替換不同的邏輯。不過(guò),個(gè)人比較懷疑這種分離是否值得,因?yàn)轭惖呐缮旧砭褪强梢該碛胁煌倪壿嫛?/span>

            另外,Entity間的交互除了用標(biāo)準(zhǔn)的直接訪問(wèn)方式外,經(jīng)常使用消息模式。消息模式和Windows的消息模式類似,Entity間通過(guò)消息交互。雖說(shuō)窗口編程畫(huà)了多年時(shí)間才擺脫了當(dāng)年肥大的switch的消息處理模式,在Entity層使用消息模式還是有意義的,因?yàn)橄⒑苋菀讖V播且可以直接在網(wǎng)絡(luò)上發(fā)送。執(zhí)著于OO的人會(huì)將消息寫(xiě)成Command對(duì)象,但原理仍然是一樣的。

            同時(shí),聯(lián)網(wǎng)游戲出現(xiàn),指針不能在不同的機(jī)器上標(biāo)識(shí)對(duì)象,我們必須用穩(wěn)定的ID來(lái)標(biāo)識(shí)對(duì)象,于是我們有了EntityManager來(lái)分配ID和管理對(duì)象集合,或者叫GameObjectManager、ObjectManager等。這在一段時(shí)期內(nèi)幾乎成了完美的方案。

            隨著游戲內(nèi)容的豐富性的迅速膨脹,傳統(tǒng)的由程序員來(lái)實(shí)現(xiàn)游戲邏輯功能的模式也越來(lái)越力不從心。腳本語(yǔ)言的集成將大部分創(chuàng)意性工作從程序員的擔(dān)子上拿了下來(lái),交還給游戲設(shè)計(jì)人員。為了給腳本提供足夠的控制權(quán),Entity結(jié)構(gòu)上必須有充分的靈活性。

            數(shù)據(jù)驅(qū)動(dòng)(Data-Driven

            現(xiàn)在有句很流行的話,“唯一不變的是變化。(The only constant is change.)”數(shù)據(jù)驅(qū)動(dòng)使得變化對(duì)引擎的影響最小化。數(shù)據(jù)驅(qū)動(dòng)不能算是一種獨(dú)立的Entity模式,不如說(shuō)它是一種設(shè)計(jì)思想,其目的就是將內(nèi)容制作和游戲引擎的制作分離開(kāi)來(lái)。與上面所說(shuō)的填充Entity屬性數(shù)據(jù)庫(kù)的不同之處在于,它還要能通過(guò)數(shù)據(jù)來(lái)設(shè)計(jì)游戲邏輯。

            游戲設(shè)計(jì)人員需要的一項(xiàng)最基本功能就是自定義人物屬性,所以與其在類里寫(xiě)死屬性成員,不如使用屬性表(Attributes/Properties)。通常使用一個(gè)哈希表(Hashtable),或者std::map,或者Dictionary,或者就是個(gè)數(shù)組,隨個(gè)人喜好,其實(shí)就是要一個(gè)key-value的映射表。然后為腳本和編輯器提供對(duì)屬性表的操作。

            動(dòng)態(tài)的邏輯主要就靠腳本了,必須為腳本提供足夠的事件和方法。個(gè)人推薦用Lua腳本,因?yàn)樗窃谟螒蝾I(lǐng)域內(nèi)用得最多的通用腳本語(yǔ)言,其引擎很小、速度很快、易于集成,盡管語(yǔ)法過(guò)于松散。不要迷信宣傳去用龐大、極慢、難于集成的Python。為腳本提供事件,其實(shí)也就是調(diào)用腳本里的函數(shù),這里如果使用了前面所述的消息模式,那么就只要調(diào)用一個(gè)腳本方法,傳遞不同的消息參數(shù)就行了。當(dāng)然也有人覺(jué)得這樣很丑陋而更愿意為不同的事件注冊(cè)不同的函數(shù)。

            當(dāng)有了數(shù)據(jù)驅(qū)動(dòng)后,Entity的繼承樹(shù)就基本失去意義了,因?yàn)橐粋€(gè)Entity是什么已經(jīng)不是程序里決定的了,而是通過(guò)數(shù)據(jù)和腳本設(shè)計(jì)出來(lái)的。但數(shù)據(jù)和腳本又不是全部,一個(gè)Entity的核心內(nèi)容和需要高效處理的部分,如碰撞檢測(cè),還是要程序來(lái)完成。于是我們需要重新設(shè)計(jì)Entity類,困難的局面也就由此開(kāi)始。

            一個(gè)直觀的想法是一個(gè)統(tǒng)一且唯一的Entity類,它包含了所有的基本功能,如顯示、碰撞檢測(cè)、運(yùn)動(dòng)、背包等,然后由數(shù)據(jù)決定哪些組件被啟用。比如一個(gè)玩家角色可能會(huì)啟用絕大部分組件,而一顆樹(shù)只啟用顯示和碰撞檢測(cè)組件。但也伴隨著缺點(diǎn):一、這個(gè)類太大了;二、對(duì)于樹(shù)木等一些簡(jiǎn)單的Entity也要浪費(fèi)其他組件的私有數(shù)據(jù)所占的內(nèi)存。那么一個(gè)簡(jiǎn)單的折中是部分使用繼承、部分使用數(shù)據(jù)定制。例如Entity只提供最基本的組件,再派生出CharactorEntity提供足夠人物角色使用的組件。

            組件模式(Component-Based Entity

            提到組件,那么很自然的就過(guò)渡到組件模式,就是把顯示、運(yùn)動(dòng)、攻擊、背包、隊(duì)伍、聲音等基本功能都做成獨(dú)立的組件,由數(shù)據(jù)來(lái)決定向Entity里添加哪些組件。由此可以得到另外一個(gè)擴(kuò)展,就是既然可以有引擎內(nèi)置的組件,那就也可以有腳本制作的組件,實(shí)現(xiàn)腳本模塊的復(fù)用。這種模式在GDC2002正式提出,到現(xiàn)在主流的引擎都有這種設(shè)計(jì)。

            這種模式在理論上很完美,但實(shí)踐上還是有不少疑問(wèn)。最常見(jiàn)的問(wèn)題就是組件間的依賴關(guān)系。理想情況下,各個(gè)組件是完全獨(dú)立的,但實(shí)踐中必然有所依賴。比如運(yùn)動(dòng)速度、攻擊強(qiáng)度等和角色的基本屬性有關(guān),運(yùn)動(dòng)組件需要角色的包圍盒來(lái)測(cè)試是否碰撞,AI組件需要分析角色當(dāng)前狀態(tài)和發(fā)出運(yùn)動(dòng)、攻擊命令,角色動(dòng)作狀態(tài)變化時(shí)改變顯示組件屬性,攻擊組件需要訪問(wèn)隊(duì)伍信息組件以禁止攻擊隊(duì)友等等。處理這種依賴關(guān)系主要要解決兩個(gè)問(wèn)題:

            <!--[if !supportLists]-->一、              <!--[endif]-->誰(shuí)依賴誰(shuí)。比如是敏捷屬性改變而去修改移動(dòng)速度,還是運(yùn)動(dòng)組件讀取敏捷屬性來(lái)計(jì)算移動(dòng)速度。如果要游戲設(shè)計(jì)人員自由定義基本屬性的話,就要選擇前者,因?yàn)榛緦傩越M件會(huì)是腳本組件。

            <!--[if !supportLists]-->二、              <!--[endif]-->如何取得另一組件的指針/引用。常見(jiàn)的方法是給每個(gè)組件類型一個(gè)唯一ID,然后用該IDEntity上查詢注冊(cè)了的組件,如果找到返回其指針/引用,否則返回null。當(dāng)然,每次訪問(wèn)都做這個(gè)查詢會(huì)很浪費(fèi)CPU,如果Entity的組件不會(huì)在運(yùn)行時(shí)動(dòng)態(tài)添加刪除的話(除非在編輯器里,否則很少有人會(huì)這么做),可以在Entity初始化后讓每個(gè)組件緩存它所要用的其他組件指針。那么當(dāng)所依賴的組件不存在怎么辦,一般情況下都是無(wú)聲地忽略。

            當(dāng)Entity由很多組件組成后,交互的消息需要發(fā)給每一個(gè)組件。這里又一次體現(xiàn)出消息機(jī)制的優(yōu)勢(shì),你不需要在Entity里為每一個(gè)事件函數(shù)寫(xiě)一個(gè)loop來(lái)調(diào)用組件的相應(yīng)事件函數(shù)。但這里也出現(xiàn)了一個(gè)問(wèn)題,消息到達(dá)各個(gè)組件的順序。很多時(shí)候這個(gè)順序不會(huì)有什么影響,但個(gè)別時(shí)候不同的順序會(huì)導(dǎo)致完全不同的邏輯發(fā)展方向。

            此外,Entity的序列化存儲(chǔ)也變得比較復(fù)雜,經(jīng)典的Excel導(dǎo)出csv的模式難以奏效,因?yàn)檫@里需要結(jié)構(gòu)化的存儲(chǔ),所以需要結(jié)構(gòu)化的數(shù)據(jù)文件如XML來(lái)存儲(chǔ),或者完全用腳本來(lái)包含所有數(shù)據(jù)和構(gòu)造Entity。

            據(jù)個(gè)人經(jīng)驗(yàn),使用數(shù)據(jù)驅(qū)動(dòng)的繼承模式時(shí)很是向往組件模式,感覺(jué)上它一個(gè)非常自然的擴(kuò)展方向,但顧忌其引入的額外的復(fù)雜性,尤其是需要游戲設(shè)計(jì)人員具有一定的編程能力,所以一直不敢全盤(pán)接過(guò)使用。但退一步,在引擎里仍然使用組件思想,但Entity的組件構(gòu)成在編譯時(shí)固定,可以達(dá)到某種妥協(xié),這和采用繼承與數(shù)據(jù)驅(qū)動(dòng)的折中類似。

            混入模式(Mix-in

            這是又一種常見(jiàn)的折中模式,即使用C++的多重繼承,將各個(gè)組件類混入一個(gè)Entity類。如:

            class Mob: public GameObject, public Renderable, public Movable, public Attackable
            {

            }

            這種方法因其簡(jiǎn)單而且非常符合多重繼承設(shè)計(jì)思想而被很多引擎采用。當(dāng)然缺點(diǎn)也是只能在支持多重繼承的語(yǔ)言里使用,而且當(dāng)組件很豐富時(shí),dynamic_cast就變成一個(gè)代價(jià)高昂的操作。

            功能性與復(fù)雜性(Functionality vs Complexity

            編程領(lǐng)域最古老的原則之一就是要“簡(jiǎn)單快速”。但隨著問(wèn)題的復(fù)雜化,程序也隨之變得越來(lái)越復(fù)雜。好的方法應(yīng)該能有效的降低或隱藏復(fù)雜性。但是,沒(méi)有不帶副作用的藥(No silver bullet.),在取得更強(qiáng)大的功能的同時(shí)總會(huì)帶來(lái)額外的復(fù)雜性。我們需要做出權(quán)衡,在必要時(shí)犧牲一些功能,也就是要估算性價(jià)比。

            一般游戲內(nèi)容制作人員不會(huì)或不太會(huì)編程,編程人員也不善于游戲的內(nèi)容創(chuàng)造和數(shù)值平衡,過(guò)于復(fù)雜的系統(tǒng)會(huì)導(dǎo)致需要兩面兼顧的人才,會(huì)大大增加做出一款游戲的難度。

            posted @ 2009-08-18 03:11 RedLight 閱讀(1068) | 評(píng)論 (0)編輯 收藏

            游戲?qū)ο蟮膶?shí)現(xiàn)

            狹義的游戲?qū)ο笫侵赣螒蚴澜缰兴芸吹郊翱山换サ膶?duì)象,如玩家、怪物、物品等,我們這里也主要討論這類對(duì)象在服務(wù)器上的組織及實(shí)現(xiàn)。
              

              在大部分的MMOG中,游戲?qū)ο蟮念愋投即笸‘?,主要有物品、生物、玩家等。比如在wow中,通過(guò)服務(wù)器發(fā)下來(lái)的GUID我們可以了解到,游戲中有9大類對(duì)象,包括物品(Item)、背包(Container)、生物(Unit)、玩家(Player)、游戲?qū)ο?GameObject)、動(dòng)態(tài)對(duì)象(DynamicObject)、尸體(Corpse)等。

              在mangos的實(shí)現(xiàn)中,對(duì)象使用類繼承的方式,由Object基類定義游戲?qū)ο蟮墓薪涌诩皩傩裕℅UID的生成及管理、構(gòu)造及更新UpdateData數(shù)據(jù)的虛接口、設(shè)置及獲取對(duì)象屬性集的方法等。然后分出了兩類派生對(duì)象,一是Item,另一是WorldObject。Item即物品對(duì)象,WorldObject顧名思義,為世界對(duì)象,即可添加到游戲世界場(chǎng)景中的對(duì)象,該對(duì)象類型定義了純虛接口,也就是不可被實(shí)例化,主要是在Object對(duì)象的基礎(chǔ)上又添加了坐標(biāo)設(shè)置或獲取的相關(guān)接口。

              Item類型又派兵出了一類Bag對(duì)象,這是一種特殊的物品對(duì)象,其本身具有物品的所有屬性及方法,但又可作為新的容器類型,并具有自己特有的屬性和方法,所以實(shí)現(xiàn)上采用了派生。mangos在實(shí)現(xiàn)時(shí)對(duì)Bag的類型定義做了點(diǎn)小技巧,Item的類型為2,Bag的類型為6,這樣在通過(guò)位的方式來(lái)表示類型時(shí),Bag類型也就同時(shí)屬于Item類型了。雖然只是很小的一個(gè)技巧,但在很多地方卻帶來(lái)了極大的便利。

              從WorldObject派生出的類型就有好幾種了,Unit、GameObject、DynamicObject和Corpse。Unit為所有生物類型的基類,同WorldObject一樣,也不可被實(shí)例化。它定義了生物類型的公有屬性,如種族、職業(yè)、性別、生命、魔法等,另外還提供了相關(guān)的一些操作接口。游戲中實(shí)際的生物對(duì)象類型為Creature,從Unit派生,另外還有一類派生對(duì)象Player為玩家對(duì)象。Player與Creature在實(shí)現(xiàn)上最大的區(qū)別是玩家的操作由客戶端發(fā)來(lái)的消息驅(qū)動(dòng),而Creature的控制是由自己定義的AI對(duì)象來(lái)驅(qū)動(dòng),另外Player內(nèi)部還包括了很多的邏輯系統(tǒng)實(shí)現(xiàn)。

              另外還有兩類特殊的Creature,Pet和Totem,其對(duì)象類型仍然還是生物類,只是實(shí)現(xiàn)上與會(huì)有些特殊的東西需要處理,所以在mangos中將其作為獨(dú)立的派生類,只是實(shí)現(xiàn)上的一點(diǎn)處理。另外在GameObject中也實(shí)現(xiàn)有派生對(duì)象,最終的繼承關(guān)系圖比較簡(jiǎn)單,就不麻煩地去畫(huà)圖了。

              從我所了解的早期游戲?qū)崿F(xiàn)來(lái)看,大部分的游戲?qū)ο蠼Y(jié)構(gòu)都是采用的類似這種方式??赡芘c早期對(duì)面向?qū)ο蟮睦斫庥嘘P(guān),當(dāng)面向?qū)ο蟮母拍顒偝鰜?lái)時(shí),大家認(rèn)為繼承就是面向?qū)ο蟮娜?,所以處處皆?duì)象,處處皆繼承。

              類實(shí)現(xiàn)的是一種封裝,雖然從云風(fēng)那里出來(lái)的棄C++而轉(zhuǎn)投C的聲音可能會(huì)影響一部分人,但是,使用什么語(yǔ)言本身就是個(gè)人喜好及團(tuán)隊(duì)整體情況決定的。我們所要的也是最終的實(shí)現(xiàn)結(jié)果,至于中間的步驟,完全看個(gè)人。還是用云風(fēng)的話說(shuō),這只是一種信仰問(wèn)題,我依然采用我所熟悉的C++,下面的描述也是如此。

              隨著面向?qū)ο蠹夹g(shù)的深入,以及泛型等概念的相繼提出,軟件程序結(jié)構(gòu)方面的趨勢(shì)也有了很大改變。C++大師們常說(shuō)的話中有一句是這樣說(shuō)的,盡是采用組合而不是繼承。游戲?qū)ο蟮膶?shí)現(xiàn)也有類似的轉(zhuǎn)變,趨向于以組合的方式來(lái)實(shí)現(xiàn)游戲?qū)ο箢愋?,也就是?shí)現(xiàn)一個(gè)通用的entity類型,然后以腳本定義的方式組合出不同的實(shí)際游戲?qū)ο箢愋汀?/p>

              描述的有些抽象,具體實(shí)現(xiàn)下一篇來(lái)仔細(xì)探討下。


            在游戲編程精粹四有三篇文章講到了實(shí)體以及實(shí)體管理的實(shí)現(xiàn)方案,其中一篇文章說(shuō)到了實(shí)體管理系統(tǒng)的四大要素:定義實(shí)體怎樣溝通的實(shí)體消息,實(shí)現(xiàn)一實(shí)體類代碼和數(shù)據(jù)的實(shí)體代碼,維護(hù)已經(jīng)注冊(cè)在案的實(shí)體類列表,和用來(lái)創(chuàng)建、管理、發(fā)送消息的實(shí)體管理器。

              關(guān)于實(shí)體消息的內(nèi)容之前討論事件機(jī)制的時(shí)候做過(guò)一點(diǎn)說(shuō)明,其實(shí)這也就是按接口調(diào)用和按消息驅(qū)動(dòng)的區(qū)別,現(xiàn)在mangos的做法是完全的接口調(diào)用,所以引擎內(nèi)部就沒(méi)有任何的實(shí)體消息。實(shí)體代碼實(shí)現(xiàn)和實(shí)體管理器是我們重點(diǎn)要討論的內(nèi)容。

              另有一篇文章也提到了使用類繼續(xù)的方式實(shí)現(xiàn)游戲?qū)ο蟮膬纱髥?wèn)題,一是它要求系統(tǒng)中的所有對(duì)象都必須從一個(gè)起點(diǎn)衍生而成,也就是說(shuō)所有對(duì)象類在編譯的時(shí)候已經(jīng)確定,這可能是一個(gè)不受歡迎的限制,如果開(kāi)發(fā)者決定添加新的對(duì)象類,則必須要對(duì)基類有所了解,方能支持新類。另一個(gè)問(wèn)題在于所有的對(duì)象類都必須實(shí)現(xiàn)同樣的一些底層函數(shù)。

              對(duì)于第二個(gè)問(wèn)題,可以通過(guò)接口繼承的方式來(lái)避免基類的方法太多。在mangos的實(shí)現(xiàn)中就采用了類似的方法,從Object虛基類派生的Unit和WorldObject仍然還是不可實(shí)例化的類,這兩種對(duì)象定義了不同的屬性和方法,分來(lái)實(shí)現(xiàn)不同類型的對(duì)象。在游戲內(nèi)部可以根據(jù)對(duì)象的實(shí)際類型來(lái)Object指針向下轉(zhuǎn)型為Unit或WorldObject,以調(diào)用需要的接口。方法雖然不夠OO,也還能解決問(wèn)題。但是第一個(gè)問(wèn)題是始終無(wú)法避免的。

              所以我們便有了通用實(shí)體這么一個(gè)概念,其主要方法是將原來(lái)基類的接口進(jìn)行分類,分到一個(gè)個(gè)不同的子類中,然后以對(duì)象組合的方式來(lái)生成我們所需要的實(shí)際游戲?qū)ο箢愋汀_@個(gè)組合的過(guò)程可以通過(guò)腳本定義的方式,這樣便可以在運(yùn)行時(shí)生成為同的對(duì)象類型,也就解決了上面提到的第一個(gè)問(wèn)題。

              通用實(shí)體的實(shí)現(xiàn)方法在目前的游戲引擎及開(kāi)源代碼中也可以看到影子。一個(gè)是BigWorld,從提供的資料來(lái)看,其引擎只提供了一個(gè)entity游戲?qū)ο?,然后由游戲?nèi)容實(shí)現(xiàn)者通過(guò)xml和python腳本來(lái)自由定義不同類型的entity類型,每種類型可有不同的property和不同的方法。這樣原來(lái)由基類定義的接口完全轉(zhuǎn)移到腳本定義,具有非常強(qiáng)的靈活性。

              另外還有一個(gè)是CEL中的entity實(shí)現(xiàn)。按照CEL的描述,entity可以是游戲中的任意對(duì)象,包括玩家可交互的對(duì)象,如鑰匙、武器等,也可以包括不能直接交互的對(duì)象,如游戲世界,甚至任務(wù)鏈中的一部分等。entity本身并沒(méi)有任何特性,具體的功能實(shí)現(xiàn)需要靠附加property來(lái)完成。簡(jiǎn)單來(lái)說(shuō),property才定義了entity可以做什么,至于該怎么做,那又是依靠behavior來(lái)定義。所以,最終在CEL中一個(gè)游戲?qū)ο笃鋵?shí)是由entity組合了多個(gè)property及多個(gè)behavior而生成的。

              但是CEL中的property與BigWorld中的property意義不大一樣,在CEL中可定義的property其實(shí)是引擎內(nèi)部要先提供的,比如其示例中所舉的pcobject.mesh、pcmove.linear、pctools.inventory等,而B(niǎo)igWorld中的property是完全的自由定制。從這個(gè)角度來(lái)講,其實(shí)可以把CEL中的property看作是游戲的邏輯系統(tǒng),也就是我們上面所描述的,接口分類后所定義的子類。

              由引擎內(nèi)部提供可選擇的property與BigWorld所采用的完全自由定制property其實(shí)本質(zhì)上是相同的。在用BigWorld實(shí)現(xiàn)的游戲中,也不可能為每種游戲?qū)ο箢愋投纪耆珡念^定義property,基于代碼利用的原則,也會(huì)先定義一些小類,然后在entity類型定義時(shí)以自定義property的方式來(lái)包含這些小類。當(dāng)然,我沒(méi)有使用過(guò)BigWorld,上面的描述也只是基于游戲?qū)崿F(xiàn)的大原則所做出來(lái)的。

              描述的依然有些抽象,我們可以用wow及mangos代碼來(lái)說(shuō)明一下。mangos中為object定義了一個(gè)屬性集合,根據(jù)對(duì)象類型的不同,這個(gè)屬性集的大小及保存數(shù)據(jù)也會(huì)有差異,另外游戲?qū)ο髢?nèi)部含有處理不同游戲邏輯的系統(tǒng),如RestSystem、FloodFilterSystem、VariousSystem等等,在player.h中以接口組的方式進(jìn)行定義。

              如果要將這種結(jié)構(gòu)改為我們描述的通用entity系統(tǒng),可以讓object只提供property注冊(cè)和刪除的接口,這里的property定義與CEL中的相同,放在mangos中也就是上面說(shuō)的RestSystem、FloodFilterSystem、VariousSystem這些。然后也通過(guò)xml文件的方式定義我們所需要的游戲?qū)ο箢愋?,如player,creature,item等,不同的對(duì)象類型可以選擇加載不同的property,加載的原則是需要哪些功能就加載哪些property。

              對(duì)象的定義按上面的方法完成后,對(duì)象的實(shí)現(xiàn)也需要做一些修改。以前客戶端的消息是直接交由player來(lái)處理,AI也是直接調(diào)用creature的接口來(lái)完成一些功能,現(xiàn)在通用的entity內(nèi)部已經(jīng)沒(méi)有任何可用的方法,所有的實(shí)現(xiàn)都轉(zhuǎn)到了property中,所以需要由各個(gè)property實(shí)現(xiàn)自己來(lái)注冊(cè)感興趣的事件及消息,entity實(shí)現(xiàn)一個(gè)消息的轉(zhuǎn)發(fā),轉(zhuǎn)給對(duì)此感興趣的property來(lái)處理。其余的實(shí)現(xiàn)就沒(méi)有什么不同了。

              當(dāng)然,我們?cè)僮鲆稽c(diǎn)擴(kuò)展,讓property不光由引擎來(lái)提供,用腳本本身也能定義property,并且可以通過(guò)xml來(lái)注冊(cè)這些property,這樣便實(shí)現(xiàn)了與BigWorld一樣的完全自由特性。這其實(shí)也就是將很多用C++實(shí)現(xiàn)的功能轉(zhuǎn)移到了python中,這種做法可作為參考,但不一定對(duì)所有人合適,至少在我看來(lái),這樣的實(shí)現(xiàn)也基本只能由程序員來(lái)做,所以讓程序員選擇自己最擅長(zhǎng)的語(yǔ)言可能會(huì)更易于開(kāi)發(fā)和調(diào)試。

            有關(guān)游戲?qū)ο髮?shí)現(xiàn)的描述,前面兩篇文章中說(shuō)的不甚清楚,主要是一直都要引用網(wǎng)上能夠找到的資料來(lái)進(jìn)行描述,以避免與公司引起不必要的麻煩。所以語(yǔ)言有些拼湊的感覺(jué),舉的例子也很不恰當(dāng),今天正好看到了游戲編程精粹五和六上的兩篇文章,內(nèi)容都差不多,<<基于組件的對(duì)象管理>>和<<基于組件的游戲?qū)ο笙到y(tǒng)>>,說(shuō)的也是我上兩篇文章想要描述的內(nèi)容,所以再補(bǔ)一篇,引用其中的部分文字進(jìn)行明確的說(shuō)明。

             

              傳統(tǒng)的游戲?qū)ο蠊芾硐到y(tǒng)采用繼承的方式來(lái)實(shí)現(xiàn),例如,所有的子類都從CObject派生。大多數(shù)情況下,直接派生的也是抽象類,其中帶一些功能而另一些子類則不帶這些功能,比如可控制/不可控制,可動(dòng)畫(huà)/不可動(dòng)畫(huà)等。mangos的實(shí)現(xiàn)中基本就是這種情況,從Object直接派生的Unit和WorldObject都是不可直接實(shí)例化的類。

              傳統(tǒng)方法的問(wèn)題在于無(wú)法應(yīng)對(duì)需求的變化,如要求武器也有動(dòng)畫(huà)效果時(shí)就無(wú)法處理了。如果硬要是這樣做,那隨著需求的嗇,很多的方法會(huì)被放到基類中,最終的結(jié)果是繼承樹(shù)變得越來(lái)越頭重腳輕,這樣的類會(huì)喪失它的內(nèi)聚性,因?yàn)樗鼈冊(cè)噲D為所有對(duì)象完成所有的事。

              就是說(shuō)到最后,基類會(huì)有一個(gè)很長(zhǎng)的接口列表,而很多的游戲?qū)ο箢愋透静恍枰獙?shí)現(xiàn)其中的一些甚至大部分接口,但是按照這種結(jié)構(gòu)卻又必須去實(shí)現(xiàn)。以至于于實(shí)現(xiàn)一個(gè)非常龐大的對(duì)象,而且想要修改一點(diǎn)功能會(huì)導(dǎo)致系統(tǒng)的大調(diào)整。

              我們希望的系統(tǒng)是可以將現(xiàn)有的功能組合到新的對(duì)象中,并且在將新的功能添加到現(xiàn)有的對(duì)象中時(shí)不需要重構(gòu)大量的代碼和調(diào)整繼承樹(shù)的結(jié)構(gòu)。

              實(shí)現(xiàn)的方法就是從組件來(lái)創(chuàng)建一個(gè)對(duì)象。組件是一個(gè)包含所有相關(guān)數(shù)據(jù)成員和方法的類,它完成某個(gè)特定的任務(wù)。把幾個(gè)組件組合在一起就可以創(chuàng)建一個(gè)新的對(duì)象。如把Entity組件、Render組件和Collectable組件組合在一起生成了一個(gè)Spoon對(duì)象。Entity組件讓我們可以把對(duì)象放到游戲世界中,Render組件讓我們可以為對(duì)象指定一個(gè)模型進(jìn)行渲染,而Collectable組件讓我們可以拾取這個(gè)對(duì)象。

              關(guān)于組件的實(shí)現(xiàn),所有的組件都從一個(gè)基礎(chǔ)組件接口派生,可稱其為IComponent。每個(gè)組件也有自己的接口定義,并且這個(gè)接口也需要從IComponent派生,類似于這樣:IComponent -- ICmpRender -- CCmpRender

              這里的每個(gè)組件也就是我在上一篇中所說(shuō)的由引擎提供的屬性,或者說(shuō)在BigWorld中自己實(shí)現(xiàn)然后定義的屬性,或者使用mangos中的定義,就是一個(gè)個(gè)的System,雖然mangos并沒(méi)有將其完全做成組件,但是通過(guò)其代碼注釋可以看到,接口也是按功能組進(jìn)行了分類,如果要拆分成組件也是比較方便的。

              組件之間的通信有兩種方法,一是用組件ID查詢到組件接口指針,然后調(diào)用接口方法;二是使用消息的方式,向?qū)ο笾兴薪M件發(fā)消息。在初始化的時(shí)候,每一個(gè)組件類型都會(huì)告訴對(duì)象管理器應(yīng)該接收什么樣的消息。

              查詢接口的方法也就是直接的方法調(diào)用,只不過(guò)接口不是全部在基類中,所以必須先查詢到指定的組件然后才能調(diào)用其接口。消息的使用前面已經(jīng)說(shuō)過(guò)多次,其實(shí)現(xiàn)方案也有過(guò)說(shuō)明。

              最后是關(guān)于游戲?qū)ο蠊δ艿臄U(kuò)展和游戲?qū)ο蟮亩x。需要擴(kuò)展功能也就是需要實(shí)現(xiàn)一個(gè)新的組件,或者修改現(xiàn)在組件。在大多數(shù)情況下,擴(kuò)展都不會(huì)引起結(jié)構(gòu)的很大調(diào)整,受影響的最多只是使用到該組件的部分代碼。

              游戲?qū)ο蠖x可采用完全數(shù)據(jù)驅(qū)動(dòng)的方式,使用xml或者腳本語(yǔ)言來(lái)定義對(duì)象類型,以及每個(gè)類型需要加載的組件。對(duì)象類型注冊(cè)到對(duì)象管理器后,由管理器提供創(chuàng)建指定類型的對(duì)象的方法。數(shù)據(jù)驅(qū)動(dòng)的方式能夠讓策劃自由定義游戲?qū)ο箢愋?,并且隨時(shí)可自由創(chuàng)建新的對(duì)象類型。


            posted @ 2009-07-29 14:04 RedLight 閱讀(2460) | 評(píng)論 (1)編輯 收藏

            虛擬貨幣可能引發(fā)現(xiàn)實(shí)風(fēng)險(xiǎn) 金融部門(mén)緊急應(yīng)對(duì)

             

            adsense
            中國(guó)高速發(fā)展的互聯(lián)網(wǎng)市場(chǎng)讓無(wú)數(shù)的游戲廠商看到這是一個(gè)即將到來(lái)的金蛋。

              據(jù)中國(guó)互聯(lián)網(wǎng)絡(luò)信息中心(CNNIC)最近的一次《中國(guó)互聯(lián)網(wǎng)絡(luò)發(fā)展?fàn)顩r統(tǒng)計(jì)報(bào)告》顯示,中國(guó)網(wǎng)民人數(shù)達(dá)到了1.23億人,與去年同期相比增長(zhǎng)了19.4%,調(diào)查結(jié)果表明,人們對(duì)互聯(lián)網(wǎng)的使用越來(lái)越頻繁,本次調(diào)查網(wǎng)民平均每周上網(wǎng)16.5小時(shí),達(dá)到了新的歷史高度,這一數(shù)據(jù)已經(jīng)超過(guò)了許多互聯(lián)網(wǎng)發(fā)達(dá)國(guó)家和地區(qū)的網(wǎng)民平均上網(wǎng)時(shí)長(zhǎng)。

              總體而言,中國(guó)互聯(lián)網(wǎng)正處于一個(gè)新的高速增長(zhǎng)時(shí)期,與GDP增長(zhǎng)率相近的印度相比,中國(guó)的互聯(lián)網(wǎng)普及率高了一倍。但在這些喜人成績(jī)背后卻無(wú)法掩飾中國(guó)互聯(lián)網(wǎng)經(jīng)濟(jì)尤其是虛擬貨幣帶來(lái)的不合理問(wèn)題。

              網(wǎng)絡(luò)催生虛擬貨幣

              不知不覺(jué)之中,伴隨著中國(guó)互聯(lián)網(wǎng)成長(zhǎng)起來(lái)的還有大量的網(wǎng)絡(luò)游戲廠商等。隨著互聯(lián)網(wǎng)的發(fā)展壯大,在給廣大網(wǎng)民提供大量免費(fèi)服務(wù)的同時(shí),根據(jù)公司盈利需要和用戶多樣化需求,各個(gè)網(wǎng)站紛紛推出了收費(fèi)服務(wù)項(xiàng)目。這也推動(dòng)了虛擬貨幣的產(chǎn)生。

              不少門(mén)戶網(wǎng)站、網(wǎng)絡(luò)游戲運(yùn)營(yíng)商為了提供更好的服務(wù),很早就開(kāi)始提供虛擬貨幣以供使用。據(jù)不完全統(tǒng)計(jì),目前市面流通的網(wǎng)絡(luò)虛擬貨幣(簡(jiǎn)稱網(wǎng)幣)不下10種,如Q幣、百度幣、酷幣、魔獸幣、天堂幣、盛大(游戲區(qū))點(diǎn)券等。以Q幣為例,使用者超過(guò)兩億人。業(yè)內(nèi)人士估計(jì),國(guó)內(nèi)互聯(lián)網(wǎng)已具備每年幾十億元的虛擬貨幣市場(chǎng)規(guī)模,并以15%~20%的速度成長(zhǎng)。

              在市場(chǎng)經(jīng)濟(jì)中,需求會(huì)刺激創(chuàng)新,創(chuàng)新反過(guò)來(lái)能拉動(dòng)需求。虛擬貨幣的日漸火爆正是在用戶的需求和企業(yè)的創(chuàng)新中完成的。目前中國(guó)網(wǎng)絡(luò)市場(chǎng)的虛擬貨幣種類之多,不勝枚舉,其中騰訊公司依托龐大的QQ用戶,隨著即時(shí)通信市場(chǎng)的成熟,也適時(shí)推出了Q幣。

              不可否認(rèn)的是,虛擬貨幣讓我們感受到購(gòu)買(mǎi)網(wǎng)絡(luò)服務(wù)的便利性,這是網(wǎng)絡(luò)經(jīng)濟(jì)發(fā)展的必然產(chǎn)物。但目前網(wǎng)絡(luò)虛擬貨幣已經(jīng)悄然變身,形成龐大的交易市場(chǎng)。

              美國(guó)著名經(jīng)濟(jì)學(xué)家林頓·拉魯什也曾經(jīng)預(yù)言:從2050年開(kāi)始,網(wǎng)絡(luò)的虛擬貨幣將在某種程度上得到官方承認(rèn),成為可以流動(dòng)的通行貨幣。如此規(guī)模的市場(chǎng)和光明前景,使不少公司已經(jīng)躍躍欲試,意圖占領(lǐng)這塊市場(chǎng)?,F(xiàn)在看來(lái),百度、PAYPAL(貝寶)和騰訊處于領(lǐng)先地位。

              虛擬的貨幣體系

              可以說(shuō),如今的網(wǎng)絡(luò)貨幣已經(jīng)成為網(wǎng)絡(luò)上最受人們關(guān)注的一種虛擬經(jīng)濟(jì)現(xiàn)象。

              不少虛擬貨幣都有一整套完整的虛擬貨幣銷售體系。就拿Q幣來(lái)說(shuō),已經(jīng)有了一個(gè)非常大的貨幣銷售體系,可以進(jìn)行聲訊電話充值、可以通過(guò)人民幣直接到代理商處購(gòu)買(mǎi)、也可以用手機(jī)話費(fèi)進(jìn)行購(gòu)買(mǎi)。

              毋庸置疑,在網(wǎng)游世界中,騰訊公司的Q幣已經(jīng)承擔(dān)了許多超出其規(guī)定功用的職能,比如,在虛擬交易中充當(dāng)一般等價(jià)物,成為虛擬財(cái)富與現(xiàn)實(shí)財(cái)富之間的橋梁。

              Q幣之所以成為虛擬世界的硬通貨,這當(dāng)然首先應(yīng)歸功于Q幣的“硬”,與諸多游戲幣相比:它歷時(shí)更長(zhǎng),使用人數(shù)眾多,使用范圍也比較廣,不易貶值……以至于在此之上,網(wǎng)民們又賦予了它新的功用,成為虛擬世界的“美元”,被用來(lái)交易不同虛擬世界以及虛擬世界和現(xiàn)實(shí)世界之間的虛擬財(cái)富。反過(guò)來(lái),Q幣這種網(wǎng)絡(luò)一般等價(jià)物的角色又強(qiáng)化了其早已擁有的那些優(yōu)勢(shì)。

              Q幣之所以有如此“強(qiáng)大”的功能,龐大的用戶群則是其天然的基礎(chǔ)。據(jù)不完全統(tǒng)計(jì),2005年中國(guó)即時(shí)通訊軟件的最高同時(shí)在線人數(shù)已經(jīng)突破千萬(wàn)。在用戶最常用的即時(shí)通訊軟件中,騰訊公司的QQ用戶占據(jù)了絕對(duì)的市場(chǎng)份額。截止到目前為止,QQ用戶已經(jīng)突破4億用戶。

              Q幣能夠成為虛擬世界的硬通貨,對(duì)于騰訊公司來(lái)說(shuō),不但是一種榮譽(yù),更意味著經(jīng)濟(jì)利益的滋生。業(yè)內(nèi)人士分

              析,虛擬交易商在相當(dāng)程度上促進(jìn)了游?分行檳餼玫姆⒄寡貳?

              根據(jù)騰訊公司2006年第二季度財(cái)報(bào)的數(shù)據(jù),其互聯(lián)網(wǎng)增值服務(wù)收入為4.62億元,占總收入近66%,易觀國(guó)際分析認(rèn)為,騰訊互聯(lián)網(wǎng)業(yè)務(wù)很大程度上依賴于虛擬貨幣Q幣來(lái)運(yùn)行。

              淘寶網(wǎng)9月的統(tǒng)計(jì)數(shù)據(jù)顯示,前不久超女投票由短信改為Q幣投票后,專門(mén)從事騰訊產(chǎn)品銷售的賣(mài)家已經(jīng)突破3000家,商品數(shù)量已經(jīng)超過(guò)30萬(wàn),QQ專區(qū)每天的交易額都超過(guò)55萬(wàn)元。

              事實(shí)上,歐美國(guó)家2005年虛擬交易成交超過(guò)42億美元,在網(wǎng)絡(luò)游戲的“圣地”———韓國(guó),虛擬交易的交易額在幾年前就已經(jīng)超過(guò)了網(wǎng)絡(luò)游戲運(yùn)營(yíng)商的收入。

              虛擬貨幣的社會(huì)體系

              盡管網(wǎng)絡(luò)虛擬貨幣大大激發(fā)了網(wǎng)絡(luò)使用者的積極性,但也表現(xiàn)出了一定的社會(huì)危害性。

              這類網(wǎng)絡(luò)貨幣的危險(xiǎn)性也即在于虛擬性,理論上它可以被無(wú)限生成而不像貨幣需要黃金來(lái)支撐。當(dāng)網(wǎng)上存在的貨幣達(dá)到一定程度時(shí),必然引起網(wǎng)上虛擬的通貨膨脹。

              國(guó)家工商部門(mén)有關(guān)人員表示,虛擬貨幣交易是網(wǎng)絡(luò)時(shí)代派生的經(jīng)營(yíng)行為,至今還沒(méi)有明確的法律條文規(guī)范,工商注冊(cè)范圍也沒(méi)有關(guān)于虛擬物品交易的項(xiàng)目。但當(dāng)虛擬財(cái)產(chǎn)交易逐漸人員雇傭化、場(chǎng)所固定化、交易盈利明確化,具有經(jīng)營(yíng)性質(zhì)后,就可能涉及市場(chǎng)秩序、稅收問(wèn)題。

              更有甚者,不少網(wǎng)絡(luò)游戲廠商都選擇了網(wǎng)絡(luò)賭博這樣灰色的產(chǎn)品作支柱。

              網(wǎng)游公司在大量發(fā)行虛擬貨幣并從中牟利時(shí),很容易造成玩家花錢(qián)買(mǎi)來(lái)的虛擬財(cái)產(chǎn)貶值,利益受到損害的現(xiàn)象。這是因?yàn)樵诨ヂ?lián)網(wǎng)上,虛擬貨幣如騰訊Q幣或其他虛擬貨幣,它們的發(fā)行和金屬貨幣儲(chǔ)值沒(méi)有任何關(guān)系,虛擬貨幣發(fā)行商的發(fā)幣行為也不受任何部門(mén)的監(jiān)管。

              甚至,游戲運(yùn)營(yíng)商也沒(méi)有能力來(lái)控制,網(wǎng)絡(luò)中存在大量“偽鈔制造者”,以主營(yíng)棋牌類網(wǎng)游的邊鋒為例,其網(wǎng)幣對(duì)應(yīng)的購(gòu)買(mǎi)力曾在一年內(nèi)縮水近40%。不少人士指出:這樣的通貨膨脹只會(huì)讓網(wǎng)民受損,也會(huì)讓網(wǎng)民喪失對(duì)互聯(lián)網(wǎng)的信心。

              據(jù)悉,正常情況下,現(xiàn)今使用最為廣泛的Q幣只能實(shí)現(xiàn)人民幣→Q幣→游戲幣→增值服務(wù)的單向流通,即在正常渠道中用人民幣兌換成Q幣之后,不可以再將Q幣兌換成人民幣。

              包括騰訊在內(nèi)的提供網(wǎng)絡(luò)虛擬貨幣的游戲運(yùn)營(yíng)商等都表示,提供產(chǎn)品和服

              務(wù)不允許將其虛擬貨幣轉(zhuǎn)換為人民幣。但是在騰訊旗下的拍拍網(wǎng)首頁(yè)就有非常明顯的“騰訊QQ專區(qū)”標(biāo)志,騰訊客服小姐明確告知,設(shè)定類目、制作專題、推薦商品都屬于網(wǎng)站官方權(quán)限,只有拍拍網(wǎng)官方才能進(jìn)行相關(guān)操作。

              盡管目前國(guó)家對(duì)虛擬貨幣也沒(méi)有明確的監(jiān)管辦法,但是在有關(guān)的基本法律法規(guī)里明確了其他形式的代金券等,不能與人民幣進(jìn)行反向兌換,這就等于明確了不允許Q幣這樣的“虛擬貨幣”兌換成人民幣。但是現(xiàn)實(shí)中將Q幣兌換成人民幣并不鮮見(jiàn),還出現(xiàn)了專門(mén)銷售這種“虛擬貨幣”的網(wǎng)站,甚至都出現(xiàn)了專門(mén)的網(wǎng)上“倒?fàn)?#8221;,這些“倒?fàn)?#8221;們的活動(dòng)表現(xiàn)為低價(jià)收購(gòu)各種虛擬貨幣、虛擬產(chǎn)品,然后再高價(jià)賣(mài)出,在一定程度上實(shí)現(xiàn)了虛擬貨幣與人民幣之間的雙向流通,對(duì)外經(jīng)貿(mào)大學(xué)信息學(xué)院院長(zhǎng)陳進(jìn)表示:“虛擬貨幣但凡跟人民幣發(fā)生聯(lián)系,就會(huì)跟現(xiàn)實(shí)中的銀行一樣,可能面對(duì)擠兌等現(xiàn)實(shí)風(fēng)險(xiǎn)。”

              業(yè)內(nèi)人士認(rèn)為,如果要控制上述情況的發(fā)展,最根本的就是要出臺(tái)措施,切斷Q幣等“虛擬貨幣”兌人民幣的途徑,比如主管部門(mén)可以對(duì)那些專門(mén)從事虛擬貨幣兌換的網(wǎng)站進(jìn)行監(jiān)管。

              可喜的是,目前中國(guó)人民銀行辦公廳主任、新聞發(fā)言人李超表示,央行已開(kāi)始關(guān)注虛擬貨幣的發(fā)展,目前正在認(rèn)真研究。

              網(wǎng)絡(luò)交易的發(fā)展,需要虛擬貨幣,虛擬貨幣的發(fā)展是網(wǎng)絡(luò)環(huán)境下不可阻擋的趨勢(shì)。但如何讓虛擬貨幣扮演好在網(wǎng)絡(luò)交易中的角色,無(wú)時(shí)不在考驗(yàn)著網(wǎng)絡(luò)服務(wù)商和中國(guó)金融部門(mén)的智慧。

            posted @ 2009-06-05 02:19 RedLight 閱讀(336) | 評(píng)論 (0)編輯 收藏

            學(xué)3D虛擬現(xiàn)實(shí)技術(shù)有感

            最近想研究一下虛擬現(xiàn)實(shí)(VR)方面的編輯器,  因?yàn)槲易鲞^(guò)游戲地圖編輯器, 所以比較好奇, 都是調(diào)用3D渲染和寫(xiě)3D Max插件, 但畢竟兩種編輯器所偏向領(lǐng)域不同, 不同專業(yè)有些東西是可以互補(bǔ)的。

            初次入門(mén),我選擇了上海一家聽(tīng)說(shuō)比較著名的公司《中視典》,聽(tīng)說(shuō)他們公司的產(chǎn)品很經(jīng)典,已是統(tǒng)治位置了,所以我就下載了個(gè)共享版的VRP編輯器來(lái)試用一下,同時(shí)下載了官方的視頻教程及使用幫助文檔,還有下載了一個(gè)我以后夢(mèng)想中的《二層別墅.exe》來(lái)Look 1 Look,呵呵!





            感覺(jué)VR地圖編輯器想得還是很到位的,還有視頻教程幾百M(fèi), 相當(dāng)精彩,講得很細(xì),包含在使用3D Max插件出現(xiàn)的問(wèn)題也講了,還有3D模型優(yōu)化方面的知識(shí),受益非淺啊,特別是美術(shù)那一塊的東西,其中比較吸引我的是攝相機(jī)實(shí)時(shí)反射貼圖,烘培,還有玻璃材質(zhì)等。我終于知道室內(nèi)場(chǎng)景的一些美術(shù)知識(shí)了,不限于無(wú)邊無(wú)際在游戲野外打怪那么姑燥無(wú)味!

            posted @ 2009-05-29 15:43 RedLight 閱讀(623) | 評(píng)論 (1)編輯 收藏

            僅列出標(biāo)題
            共9頁(yè): 1 2 3 4 5 6 7 8 9 
            <2009年12月>
            293012345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            導(dǎo)航

            統(tǒng)計(jì)

            公告


            Name: Galen
            QQ: 88104725

            常用鏈接

            留言簿(3)

            隨筆分類

            隨筆檔案

            相冊(cè)

            My Friend

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            四虎国产永久免费久久| 午夜精品久久久久久久无码| 72种姿势欧美久久久久大黄蕉| 91久久成人免费| 99久久精品国产一区二区| 伊人久久综合热线大杳蕉下载| 亚洲国产精品无码久久久久久曰 | 欧洲性大片xxxxx久久久| 久久热这里只有精品在线观看| 青青青国产精品国产精品久久久久| 日韩va亚洲va欧美va久久| 久久久综合九色合综国产| 亚洲国产精品无码久久一线| 久久久久久国产精品免费免费| 久久亚洲精精品中文字幕| 免费精品久久天干天干| 久久91精品综合国产首页| 久久夜色精品国产亚洲| 国产精品美女久久久久久2018| 香蕉久久久久久狠狠色| 青青久久精品国产免费看| 91久久精品视频| 欧美精品一本久久男人的天堂| 性欧美大战久久久久久久久| 免费无码国产欧美久久18| 亚洲国产日韩欧美久久| 久久精品这里只有精99品| 亚洲一本综合久久| 久久精品国产99国产电影网| AV无码久久久久不卡网站下载| 人妻精品久久无码区| 一本一本久久aa综合精品| 久久久久亚洲AV无码专区首JN| 欧美久久亚洲精品| 亚洲伊人久久成综合人影院| 欧美粉嫩小泬久久久久久久| 久久久久成人精品无码| 要久久爱在线免费观看| 精品久久久久久久久免费影院| 亚洲欧美日韩中文久久| 亚洲AV无码成人网站久久精品大|