【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 1747|回复: 0

Direct3D9游戏编程中的颜色

[复制链接]
发表于 2009-4-12 10:26:07 | 显示全部楼层 |阅读模式
本文译自《Introduction to 3D Game Programming with DirectX 9.0》第四章“Color”,敬请斧正。

本章讨论场景中对象的颜色渲染。通过本章的学习,可以达到如下目标:
l          在Direct3D中如何描述颜色
l          理解颜色是如何被渲染的
4.1. 颜色的表现在Direct3D中颜色使用RGB表示,也就是说,需要指定红、绿、蓝三原色的值,这三个分量的混合颜色就是最终的颜色。
我们使用两种结构表示RGB数据。第一种是D3DCOLOR类型,其实就是DWORD类型。该类型被分成4个8-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;
显然,结构D3DXCOLOR和D3DCOLORVALUE包含四个浮点数成员,所以可以将颜色看作一个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->resent(0, 0, 0, 0);
    }
    return true;
}
4.5. 总结 l          颜色使用红、绿、蓝三原色的强度描述。在Direct3D中可以使用D3DCOLOR、D3DCOLORVALUE、D3DXCOLOR结构描述颜色。
l          有时将颜色看成四元向量(r,g,b,a)。颜色向量可以像普通向量一样进行加、减、放大操作。另外,颜色向量间的点积和叉积是没有含义的,但是分量间相乘却很有用。
l          可以为顶点指定颜色,然后Direct3D根据当前的着色模式决定如何将顶点的颜色转换到像素。
l          平坦着色模式取第一个顶点的颜色作为几何体像素的颜色;高洛德模式则通过线形插值法计算像素的颜色。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 09:47

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表