Direct3D9游戏编程中的颜色

4.   颜色

本文译自《Introduction to 3D Game Programming with DirectX 9.0》第四章“Color”,敬请斧正。

 

本章讨论场景中对象的颜色渲染。通过本章的学习,可以达到如下目标:

l          Direct3D中如何描述颜色

l          理解颜色是如何被渲染的

4.1. 颜色的表现

Direct3D中颜色使用RGB表示,也就是说,需要指定红、绿、蓝三原色的值,这三个分量的混合颜色就是最终的颜色。

我们使用两种结构表示RGB数据。第一种是D3DCOLOR类型,其实就是DWORD类型。该类型被分成48-bit的部分,分别用于存储颜色的分量。

1个字节表示,所以每种颜色分量的亮度范围为0~~255。关于上图中的Alpha分量,目前可以不用理会,在讲述alpha混合时再详细讨论。

每种颜色分量都是使用

正确的填写D3DCOLOR结构中的各个分量需要进行位操作。为此,D3D提供了一个宏D3DCOLOR_ARGB,每个分量需要在0~~255之内。

D3DCOLOR brightRed = D3DCOLOR_ARGB(255, 255, 0, 0);

D3DCOLOR someColor = D3DCOLOR_ARGB(255, 144, 87, 201);

另外,还有一个宏D3DCOLOR_XRGB,它与上面的宏相似,但是不需要提供alpha参数值,而是将其设定为0xFF

#define D3DCOLOR_XRGB(r,g,b) D3DCOLOR_ARGB(0xff,r,g,b)

Direct3D中表示颜色的另一种结构是D3DCOLORVALUE。该结构使用浮点数表示颜色的各个分量的值,范围为0.0~~1.0

typedef struct _D3DCOLORVALUE {

    float r; // the red component, range 0.0-1.0

    float g; // the green component, range 0.0-1.0

    float b; // the blue component, range 0.0-1.0

    float a; // the alpha component, range 0.0-1.0

} D3DCOLORVALUE;

有时,还使用D3DXCOLOR结构,它包含与D3DCOLORVALUE相同的数据成员,还有很多有用的构造函数和重载的操作符,这使很多颜色操作十分方便。因这两种数据结构具有相同的数据成员,故很容易在二者之间转换。D3DXCOLOR的定义如下:

typedef struct D3DXCOLOR

{

#ifdef __cplusplus

    public:

    D3DXCOLOR() {}

    D3DXCOLOR( DWORD argb );

    D3DXCOLOR( CONST FLOAT * );

    D3DXCOLOR( CONST D3DXFLOAT16 * );

    D3DXCOLOR( CONST D3DCOLORVALUE& );

    D3DXCOLOR( FLOAT r, FLOAT g, FLOAT b, FLOAT a );

    // casting

    operator DWORD () const;

    operator FLOAT* ();

    operator CONST FLOAT* () const;

    operator D3DCOLORVALUE* ();

    operator CONST D3DCOLORVALUE* () const;

    operator D3DCOLORVALUE& ();

    operator CONST D3DCOLORVALUE& () const;

    // assignment operators

    D3DXCOLOR& operator += ( CONST D3DXCOLOR& );

    D3DXCOLOR& operator -= ( CONST D3DXCOLOR& );

    D3DXCOLOR& operator *= ( FLOAT );

    D3DXCOLOR& operator /= ( FLOAT );

    // unary operators

    D3DXCOLOR operator + () const;

    D3DXCOLOR operator - () const;

    // binary operators

    D3DXCOLOR operator + ( CONST D3DXCOLOR& ) const;

    D3DXCOLOR operator - ( CONST D3DXCOLOR& ) const;

    D3DXCOLOR operator * ( FLOAT ) const;

    D3DXCOLOR operator / ( FLOAT ) const;

    friend D3DXCOLOR operator * (FLOAT, CONST D3DXCOLOR& );

    BOOL operator == ( CONST D3DXCOLOR& ) const;

    BOOL operator != ( CONST D3DXCOLOR& ) const;

#endif //__cplusplus

    FLOAT r, g, b, a;

} D3DXCOLOR, *LPD3DXCOLOR;

显然,结构D3DXCOLORD3DCOLORVALUE包含四个浮点数成员,所以可以将颜色看作一个4元向量(r,g,b,a)。颜色向量可以像普通的向量一样进行加、减、乘运算。另外,点积和叉积对颜色向量是没有含义的,而分量相乘却是有意义的。结构D3DXCOLOR定义的颜色与颜色相乘就是颜色分量的相乘,使用符号X表示:

(c1, c2, c3, c4) X (k1, k2, k3, k4) = (c1k1, c2k2, c3k3, c4k4)

4.2. 顶点颜色

几何体的颜色由组成它的顶点的颜色决定。因此,可以我们必须向顶点数据结构中添加颜色成员。在这里,没有采用D3DCOLORVALUE结构描述颜色,因为Direct3D希望使用32-bit的整型数表示颜色。另外,当使用顶点着色器(Vertex Shader)时,将会使用四元向量描述顶点颜色,这是一个128-bit的颜色。到讨论顶点着色器时会详细说明。

struct ColorVertex

{

    float _x, _y, _z;

    D3DCOLOR _color;

    static const DWORD FVF;

}

const DWORD ColorVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;

4.3. 着色模式

着色发生在光栅化和通过顶点颜色计算像素颜色时。目前常用的有两种着色模式:平坦模式和高洛德模式。

在平坦模式下,像素的颜色一律取组成几何体的第一个顶点的颜色。所以,由下面三个顶点构成的三角形是红色的,因为第一个顶点的颜色是红色,令外两个顶点的颜色会被忽略。

ColorVertex t[3];

t[0]._color = D3DCOLOR_XRGB(255, 0, 0);

t[1]._color = D3DCOLOR_XRGB(0, 255, 0);

t[2]._color = D3DCOLOR_XRGB(0, 0, 255);

平坦模式往往是几何体看起来菱角分明,颜色间缺少平滑的过渡。另外一种较自然的着色模式就是高洛德模式,也叫平滑模式,在这种模式下,顶点的颜色以线形插值方式渲染表面。

Direct3D中可以使用如下方法设置着色模式:

// set flat shading

Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);

// set Gouraud shading

Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);

4.4. 应用举例:彩色三角形

这个例子用以说明怎样使用平坦模式和高洛德模式渲染彩色三角形。首先,声明如下全局变量:

D3DXMATRIX World;

IDirect3DVertexBuffer9* Triangle = 0;

这里,World是三角形的世界坐标系转换矩阵,Triangle是存储三角形顶点数据的顶点缓冲区指针。这里只存储一个三角形的顶点信息,我们将使用World矩阵在坐标系中不同的位置多次渲染该三角形。

函数setup创建顶点缓冲区,并且填充三角形的顶点数据,最后禁用光照。例子中使用上面所声明的顶点结构ColorVertex,代码如下:

bool Setup()

{

    // create vertex buffer

    Device->CreateVertexBuffer(

        3 * sizeof(ColorVertex),

        D3DUSAGE_WRITEONLY,

        ColorVertex::FVF,

        D3DPOOL_MANAGED,

        &Triangle,

        0);

    // fill the buffers with the triangle data

    ColorVertex* v;

    Triangle->Lock(0, 0, (void**)&v, 0);

    v[0] = ColorVertex(-1.0f, 0.0f, 2.0f, D3DCOLOR_XRGB(255, 0,  0));

    v[1] = ColorVertex( 0.0f, 1.0f, 2.0f, D3DCOLOR_XRGB( 0, 255, 0));

    v[2] = ColorVertex( 1.0f, 0.0f, 2.0f, D3DCOLOR_XRGB( 0, 0, 255));

    Triangle->Unlock();

    // set projection matrix

    D3DXMATRIX proj;

    D3DXMatrixPerspectiveFovLH(

        &proj,

        D3DX_PI * 0.5f, // 90 - degree

        (float)Width / (float)Height,

        1.0f,

        1000.0f);

    Device->SetTransform(D3DTS_PROJECTION, &proj);

    // set the render states

    Device->SetRenderState(D3DRS_LIGHTING, false);

    return true;

}

函数Display使用不同的着色模式在不同的位置渲染该三角形两次,其位置由World矩阵控制:

bool Display(float timeDelta)

{

    if( Device )

    {

        Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);

        Device->BeginScene();

        Device->SetFVF(ColorVertex::FVF);

        Device->SetStreamSource(0, Triangle, 0, sizeof(ColorVertex));

        // draw the triangle to the left with flat shading

        D3DXMatrixTranslation(&World, -1.25f, 0.0f, 0.0f);

        Device->SetTransform(D3DTS_WORLD, &World);

        Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_FLAT);

        Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

        // draw the triangle to the right with gouraud shading

        D3DXMatrixTranslation(&World, 1.25f, 0.0f, 0.0f);

        Device->SetTransform(D3DTS_WORLD, &World);

        Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);

        Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

        Device->EndScene();

        Device->Present(0, 0, 0, 0);

    }

    return true;

}

4.5. 总结

l          颜色使用红、绿、蓝三原色的强度描述。在Direct3D中可以使用D3DCOLORD3DCOLORVALUED3DXCOLOR结构描述颜色。

l          有时将颜色看成四元向量(rgba)。颜色向量可以像普通向量一样进行加、减、放大操作。另外,颜色向量间的点积和叉积是没有含义的,但是分量间相乘却很有用。

l          可以为顶点指定颜色,然后Direct3D根据当前的着色模式决定如何将顶点的颜色转换到像素。

l          平坦着色模式取第一个顶点的颜色作为几何体像素的颜色;高洛德模式则通过线形插值法计算像素的颜色。

 

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页