D3D9 简单图形的绘制以及显示

程序截图所示:

要想完成这样的程序,首先咱们先得知道以下几点才能进行绘制并且显示:

一、了解什么是D3D9的绘制流水线:

1.局部坐标系:

        主要用于在使用3D建模时,所使用的坐标系,无需考虑它相对于场景中其他物体的位置,大小。通常在创建模型时,建模人员都会将模型围绕原点进行建模,那样将有助于坐标变换,比如让模型旋转起来,在我们将坐标变换时将会进行描述。

2.世界坐标系:

          将每个模型的所在的局部坐标组织在一起就变成了世界坐标系。然而位于局部坐标系的物体通过一个称为世界变换的运算才能变换到世界坐标系中,通常包括平移(translation),旋转(rotation),以及比例运算(scaling)。

          世界变换用一个矩阵来表示,通过IDirect3DDevice9::SetTransform函数便可加以应用,第一个参数表示要变换的类型。

          如:

           Device->SetTransform(D3DTS_WORLD,&xx);

3.观察坐标系:

          在世界空间中,世界坐标系定义了虚拟的3D空间,物体都被放置到这个空间中,在3D游戏中,世界空间中所有的几何体都随着摄像机一同进行,以保证摄像机的视场恒定。一般称为取景变换(view space transformation)。

 

取景变换(view space transformation)也是用IDirect3DDevice9::SetTransform函数来进行设定。

              Device->SetTransform(D3DTS_VIEW,&XX);

 

4.背面消隐:

        由于场景中的大多数物体都是封闭体,而且摄像机是进入不了物体内部的实体空间的,并且在游戏中,如果该场景在渲染过程中多边形越多,要进行处理的内容就越多,就越消费计算机的处理能力,所以背面消隐就很重要了,只看见它的正面,后背面进行渲染时进行跳过,这将减少大约一半的渲染量,提高了游戏的运行速度。

以2D俯视图为例:

           一般通过修改绘制状态(render state)D3DRS_CULLMODE来达到目的。

           Device->SetRenderState(D3DRS_CULLMODE,Value);

           Value的值可以取:

           

            D3DCULL_NONE                 完全禁用背面消隐

            D3DCULL_CW 只对顺时针绕序的三角形进行消隐

            D3DCULL_CCW 对逆时针绕序的三角形进行消隐

            顺时针绕序:Direct3D中认定顶点的排列顺序在“观察坐标系”中的三角形单元是正面朝向的,那就消隐它的背面,反之逆时针绕序一样。


5.光照:

         光源是在世界坐标系中定义的,但必须经过取景变换到观察坐标系方可使用。光照可以照亮场景中的物体,从而可以获得比较逼真的显示效果。

目前本程序没使用光照。


6.裁剪:

          将位于视域体之外的几何体进行剔除。

 

7.投影:

          将所得到的3D场景,进行2D表示。

投影的方法:

        使用D3DX函数,根据视域体中的信息创建一个投影矩阵。

 

 

D3DXMATRIX * D3DXMatrixPerspectiveFovLH(
   D3DXMATRIX & pOut,              //最终生成的投影变换矩阵
   FLOAT fovY,                     //视域角度,角度越大,映射到投影窗口的图像就越小
   FLOAT Aspect,      //屏幕显示区的纵横比(aspect ratio)=屏幕宽度(screen width)/屏幕高度(screen height)
   FLOAT zn,                     //表示视域体中近裁面
   FLOAT zf                       //表示视域体中远裁面
);
//例如:
    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(&proj,D3DX_PI/4,Aspect,1.0f,1000.0f);
    Device->SetTransform(D3DTS_PROJECTION,&proj);

 

 

8.视口变换:

          将顶点坐标从投影窗口转换到屏幕的程序窗口中。

 

      在Direct3D中,视口用结构D3DVIEWPORT9来表示,定义如下:

 

 

  typedef struct D3DVIEWPORT9{
       DWORD   X,               //所表示窗口相对于父窗口的X坐标
       DWORD   Y,               //所表示窗口相对于父窗口的Y坐标
       DWORD   Width,          //表示窗口的宽度
       DWORD   Height,          //表示窗口的高度
       DWORD   MinZ,            //深度缓存的最小值
       DWORD   MaxZ;            //深度缓存的最大值
}D3DVIEWPORT9;
如:
     D3DVIEWPORT9 vp={0,0,640,480,0,1};
     Device->SetViewport(&vp);	
typedef struct D3DVIEWPORT9{
       DWORD   X,               //所表示窗口相对于父窗口的X坐标
       DWORD   Y,               //所表示窗口相对于父窗口的Y坐标
       DWORD   Width,          //表示窗口的宽度
       DWORD   Height,          //表示窗口的高度
       DWORD   MinZ,            //深度缓存的最小值
       DWORD   MaxZ;            //深度缓存的最大值
}D3DVIEWPORT9;
如:
     D3DVIEWPORT9 vp={0,0,640,480,0,1};
     Device->SetViewport(&vp);	

 

9.光栅化:

          计算所构成图形中每个三角形单元的每个像素的颜色值。

 

终于告一段落了,休息会。

 

二、顶点缓存与索引缓存:

           简介:

                    在Direct3D中,顶点缓存与索引缓存(vertex/index buffer)是两个比较相似的接口。顶点缓存是一个包含顶点数据的连续内存空间;索引缓存是一个包含索引数据的连续内存空间。而且存储的位置比较随意,既可以存在内存中,也可以存在显卡的显存中(video memory),存在显存中,可以在绘制时,使用显存中的数据将会比使用系统内存中的数据快得多许多。

1.创建顶点缓存和索引缓存:

          顶点缓存的结构体格式:

 

   HRESULT IDirect3DDevice9::CreateVertexBuffer(
            UINT       Length,               //缓存分配的字节数
            DWORD      Usage,                //关于缓存的附加属性
            DWORD      FVF,                  //灵活顶点格式
	    D3DPOOL    Pool,                 //缓存的内存池
            IDirect3DVertexBuffer9 ** ppVertexBuffer,       //接收所创建的顶点缓存的指针
            HANDLE*    pSharedHandle                        //为保留参数,一般设为0或NULL
);
    //索引缓存的结构体格式
     HRESULT IDirect3DDevice9::CreateIndexBuffer(
             UINT      Length, 
             DWORD     Usage,
             D3DFORMAT Format,
             D3DPOOL   Pool,
             IDirect3DIndexBuffer9** ppIndexBuffer,
             HANDLE *  pSharedHandle
);

 

 

      可以看出两个缓存的结构体格式都是大同小异的

 注意:
           创建缓存时,设置缓存的附加属性时,如果不需要频繁更新缓存中的内容,就将其设置为动态缓存D3DUSAGE_DYNAMIC,反之就设为静态缓存。

 

USAGE的相关值:

 

    	   //调用:
        //创建静态顶点缓存
        IDirect3DVertexBuffer9 * vb;             
        Device->CreateVertexBuffer(
		8*sizeof(Vertex),            //8个顶点
                0,                           //无附加属性
                D3DFVF_XYZ,                
		D3DPOOL_MANAGED,
                &vb,
                 0);
        //创建动态索引缓存
        IDirect3DIndexBuffer9* ib;
        Device->CreateIndexBuffer(
                36* sizeof(WORD),                
                D3DUSAGE_DYNAMIC|D3DUSAGE WRITEONLY,            //动态缓存和只写模式
                D3DFMT_INDEX16,                       //16位索引大小
                D3DPOOL_MANAGED,
                &ib,
                0);         	   //调用:
        //创建静态顶点缓存
        IDirect3DVertexBuffer9 * vb;             
        Device->CreateVertexBuffer(
		8*sizeof(Vertex),            //8个顶点
                0,                           //无附加属性
                D3DFVF_XYZ,                
		D3DPOOL_MANAGED,
                &vb,
                 0);
        //创建动态索引缓存
        IDirect3DIndexBuffer9* ib;
        Device->CreateIndexBuffer(
                36* sizeof(WORD),                
                D3DUSAGE_DYNAMIC|D3DUSAGE WRITEONLY,            //动态缓存和只写模式
                D3DFMT_INDEX16,                       //16位索引大小
                D3DPOOL_MANAGED,
                &ib,
                0);        

 

 

 

2.访问缓存内容:

               要进行访问缓存内容就要借助Lock与Unlock两个方法进行操作。

注意:

           如果在创建缓存的时候将它的属性设置为只写(D3DUSAGE_WRITEONLY)的话,那就无法进行访问我们的缓存内容。

         

          在Direct3D中,顶点缓存与索引缓存的Lock/Unlock(死锁/解锁)函数完全一致。

          Lock函数:

          

         HRESULT  IDirect3DVertexBuffer9::Lock(
                    UINT    OffsetToLock,                 //缓存的起点位置的偏移量
                    UINT    SizeToLock,                   //所要锁定的字节数
                    BYTE*   ppbData,                      //指向被锁定的存储区起始位置的指针
                    DWORD   Flags                         //描述锁定的方式
                 );   HRESULT  IDirect3DVertexBuffer9::Lock(
                    UINT    OffsetToLock,                 //缓存的起点位置的偏移量
                    UINT    SizeToLock,                   //所要锁定的字节数
                    BYTE*   ppbData,                      //指向被锁定的存储区起始位置的指针
                    DWORD   Flags                         //描述锁定的方式
                 );


 
 

Flags  表示锁定的方式,可以取以下三种值:

       

          D3DLOCK_DISCARD:    仅用于动态缓存。

  

          D3DLOCK_NOOVERWRITE:  仅用于动态缓存

          D3DLOCK_READONLY:  所锁定的缓存只可读而不可写

调用例子:

             

   Vertex* vertices;
            _vb->Lock(0,0,(void **)&vertices,0);        //锁定缓存
            vertices[0]=Vertex(-1.0f,0.0f,2.0f);                
 	    vertices[1]=Vertex(0.0f,1.0f,2.0f); 
            vertices[2]=Vertex(1.0f,0.0f,2.0f);
            _vb->Unlock();  Vertex* vertices;
            _vb->Lock(0,0,(void **)&vertices,0);        //锁定缓存
            vertices[0]=Vertex(-1.0f,0.0f,2.0f);                
 	    vertices[1]=Vertex(0.0f,1.0f,2.0f); 
            vertices[2]=Vertex(1.0f,0.0f,2.0f);
            _vb->Unlock(); 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

3.获取缓存当中的信息:



                 通过D3DVERTEXBUFFER_DESC和D3DINDEXBUFFER_DESC结构体创建实例对象,再通过调用GetDesc函数从而获取信息。

         如:

 

   D3DVERTEXBUFFER_DESC  vbDescription;
                      vertexBuffer->GetDesc(&vbDescription);                         //获取顶点缓存的信息
 
                      D3DINDEXBUFFER_DESC    ibDescription;
                      inDescription->GetDesc(&ibDescription);                       //获取索引缓存的信息D3DVERTEXBUFFER_DESC  vbDescription;
                      vertexBuffer->GetDesc(&vbDescription);                         //获取顶点缓存的信息
 
                      D3DINDEXBUFFER_DESC    ibDescription;
                      inDescription->GetDesc(&ibDescription);                       //获取索引缓存的信息
 
 
 

4.进行图形的绘制:

首先是IDirect3DDevice9::SetStreamSource方法,将几何体的信息传输到绘制流水线中。

               HRESULT IDirect3DDevice9::SetStreamSource(
                       UINT     StreamNumber,          //用于指定与该顶点缓存建立连接的数据流
                       IDirect3DVertexBuffer9* pStreamData,                 //包含顶点数据的顶点缓存指针
                       UINT     OffsetInBytes,              //数据流当中的偏移量
                       UINT     Stride                      //顶点缓存中每个顶点结构的大小
);
        //调用例子:
         g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX) );  
                  最后一步利用顶点缓存和索引缓存进行绘制,所调用的函数是IDirect3DDevice9::DrawPrimitive。
                  函数原型为:
                        HRESULT IDirect3Ddevice9::DrawPrimitive(
                                       D3DPRMITIVETYPE PrimitiveType,                  //所需要绘制的图元类型
                                       UINT StartVertex,                                                  //用于指定从顶点缓存中读取顶点数据的起始索引位置
                                       UINT  PrimitiveCount                                           //所要绘制的图元数量
);       HRESULT IDirect3DDevice9::SetStreamSource(
                       UINT     StreamNumber,          //用于指定与该顶点缓存建立连接的数据流
                       IDirect3DVertexBuffer9* pStreamData,                 //包含顶点数据的顶点缓存指针
                       UINT     OffsetInBytes,              //数据流当中的偏移量
                       UINT     Stride                      //顶点缓存中每个顶点结构的大小
);
        //调用例子:
         g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX) );  
                  最后一步利用顶点缓存和索引缓存进行绘制,所调用的函数是IDirect3DDevice9::DrawPrimitive。
                  函数原型为:
                        HRESULT IDirect3Ddevice9::DrawPrimitive(
                                       D3DPRMITIVETYPE PrimitiveType,                  //所需要绘制的图元类型
                                       UINT StartVertex,                                                  //用于指定从顶点缓存中读取顶点数据的起始索引位置
                                       UINT  PrimitiveCount                                           //所要绘制的图元数量
);

 

  
 

调用实例:                     g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 8 );  

终于告一段落了,再休息一会。

           

              哎呦,不错哦。

三、最后一步了,进行颜色的上色。

                   在Direct3D中,颜色使用RGB三原色来表示,分解为红色(Red),绿色(Green),蓝色(Blue)。RGB数据可以用两种不同的结构来保存,第一种是D3DCOLOR,它实际上与DWORD类型完全相同,共32位,且可分为四个8位项,每项存储一种颜色的分量的亮度值,R,G,B各占8位,剩下8位,一个字节分配给Alpha分量,Alpha分量主要用于后面的融合;第二种结构是D3DCOLORVALUE,该结构中,用单精度浮点数来度量每个颜色分量的亮度值,而亮度值的取值范围为0~1.

                  D3DCOLORVALUE的函数结构:

        

        Typedef struct D3DCOLORVALUE{
                  float r;               //red
                  float g;               //green;
                  float b;               //blue
                  float a;               //alpha
}D3DCOLORVALUE;   Typedef struct D3DCOLORVALUE{
                  float r;               //red
                  float g;               //green;
                  float b;               //blue
                  float a;               //alpha
}D3DCOLORVALUE;

 

     
 

                   

                   开始着色:

                 在光栅化的过程中,有两种着色模式(shading mode):平面着色(flat shading)与Gouraud着色也称为(smooth shading)。

        在绘制状态调用函数里面便可进行着色的设置:

        如:

  //平面着色(flat shading)
       Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_FLAT);
  
      //Gouraud着色(smooth shading)
      Device->SetRenderState(D3DRS_SHADEMODE,D3DSHADE_GOURAUD);

 

 

样例:

四边形的简单绘制和上色:点击打开链接

截图所示:

 

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值