SweetDream
高歌一壶新酿酒,醉抱青山不必归。
 

1.创建和使用顶点/索引缓冲的步骤如下:

·创建缓冲

顶点:Direct3DDevice9::CreateVertexBuffer

索引:Direct3DDevice9::CreateVertexBuffer && Direct3DDevice9::CreateIndexBuffer

· 锁定缓冲,写入数据再解锁。/**如果不Lock/Unlock 就直接使用会造成使用未定义指针;之所以这样做,而不是事先分配vertex数组是因为这不是在主存中分配空间,而是在显存中分配空间。*/

顶点:IDirect3DVertexBuffer9::Lock

索引: IDirect3DVertexBuffer9::Lock && IDirect3DIndexBuffer9::Lock

·绘制。

Direct3DDevice9::Clear

Direct3DDevice9::BeginScene();

Direct3DDevice9::SetStreamSource

Direct3DDevice9::SetIndices//索引专有

Device->SetFVF(Vertex::FVF);

顶点:Direct3DDevice9::DrawIndexedPrimitive

  索引:Direct3DDevice9::DrawPrimitive

Direct3DDevice9::EndScene();

Direct3DDevice9::Present(0, 0, 0, 0);

 

2.             填充模式

Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);  );默认的是

D3DFILL_SOLID。还可以是D3DFILL_POINT D3DFILL_WIREFRAME

 

3  使用顶点着色时要关闭灯光,否则会变成黑色的。因为没有指定材质。

顶点着色这里指顶点的FVF格式中带有D3DFVF_DIFFUSE成分。

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

 

4.设置灯光的步骤:

·开启灯光。

  Direct3DDevice9::SetRenderState(D3DRS_LIGHTING, true);

·设置材质。顶点结构体不具备材质特性;因此必须设置当前材质。为了设置当前材质,我们使用 IDirect3DDevice9::SetMaterial(CONST D3DMATRIAL9* pMaterial) 方法。

·创建一个光源。

   D3DLIGHT9 myLight;

· 设置状态。

顶点结构体不具备材质特性;因此必须设置当前材质。为了设置当前材质,我们使用 IDirect3DDevice9::SetMaterial(CONST D3DMATRIAL9* pMaterial) 方法。

 

5.纹理

读取纹理:

HRESULT D3DXCreateTextureFromFile(

    LPDIRECT3DDEVICE9 pDevice,    // 创建纹理的设备指针

    LPCSTR pSrcFile,                // 加载图像的文件名

    LPDIRECT3DTEXTURE9* ppTexture // 接收创建的纹理的指针

);

 

设置纹理:

HRESULT IDirect3DDevice9::SetTexture(

    DWORD Stage,                     // 该参数取值范围是0-7,用于确定纹理层

    IDirect3DBaseTexture9* pTexture  // 指向纹理设置的指针

);

 

纹理过滤:

     临近点取样(Nearest point sampling)

Device->SetSamplerState(0, D3DSAMP MAGFILTER, D3DTEXF_POINT);

Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);

     线性过滤(Linear filtering) ──线性过滤推荐用于缩小图像。

Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

     双向过滤(Anisotropic filtering)

Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);

Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);

  当使用双向过滤时,我们必须设置 D3DSAMP_MAXANISOTROPY 等级,它决定了双向过滤的质量。该值越高处理的效果越好。检查 D3DCAPS9 结构体,确认你的显卡是否支持此功能。下面的代码设置该值为4

Device->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 4);

 

Mipmaps

MIP 映射过滤器用于控制 Direct3D 如何使用 MIP 映射。你可以像下面所写代码一样设置 MipMap

Device->SetSamplerState(0, D3DSAMP_MIPFILTER, Filter);

  其中 Filter 是以下三个设置选项中的一种:

     D3DTEXF_NONE ── 不使用 MIP 映射。

     D3DTEXF_POINT ── 通过使用该过滤选项,Direct3D 将选择最接近屏幕三角形大小的 MIP 映射等级。一旦选中该等级,Direct3D就将按照指定的过滤器进行缩小和放大过滤。

     D3DTEXF_LINEAR ── 通过使用该过滤选项,Direct3D 将获得两个最接近的 MIP 映射等级,缩小和放大过滤每个等级,并线性组合两个等级计算得到最终的颜色值。

 

6.混合

默认情况下,混合是被关闭的,你需要通过设置 D3DRS_ALPHABLENDENABLE 渲染状态为 true 来开启混合。

Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

混合是一个开销比较大的操作,只能对那些需要使用的几何体进行混合。当你渲染完了几何体,你应该关闭 Alpha 混合。同样,你应当尝试批量对三角形进行混合并立即渲染他们,避免在渲染和混合之间来回切换,导致绘制每一帧的耗时增加。

Device->SetRenderState(D3DRS_SRCBLEND, Source);

Device->SetRenderState(D3DRS_DESTBLEND, Destination);

默认状况下,源混合要素与目标混合要素分别设置为 D3DBLEND_SRCALPHA D3DBLEND_INVSRCALPHA

     D3DBLEND_SRCALPHA ── blendFactor = (as, as, as, as)

     D3DBLEND_INVSRCALPHA ── blendFactor = (1-as, 1-as, 1-as, 1-as)

 

默认情况下,假如设置一个有 alpha 通道的纹理,alpha 值从在 alpha 通道中获得。假如没有 alpha 通道,那么 alpha 值是通过顶点颜色获得。你可以通过下面的渲染状态来指定使用哪一个资源:

// 在着色期间从漫射色计算 alpha

Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);

Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

 

// 通过 Alpha 通道获得 alpha

Device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);

Device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

 

7.模板缓冲

使用步骤:

1. 清空模板缓冲

先清空模板缓冲使得整个模板缓冲的画面为一个指定值,例如:

Device->Clear(0, 0,

D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,

0xff000000, 1.0f, 0 );

就指定了清空模板缓冲为0

2启用模板缓冲

Device->SetRenderState(D3DRS_STENCILENABLE, true);

这样我们就可以使用模板缓冲了。

3. 在模板缓冲中标记需要绘制的区域

这里要涉及到模板测试,然后更新模板缓冲入口(value)

模板测试:

( ref & mask )  ComparisonOperation ( value & mask )

模板测试是针对每个像素的,不过先假定模板是开启的(enabled),而且它获得两个操作数:

·左边的操作数( LHS = ref & mask ),表明应用程序定义的模板参考值(ref应用程序定义的掩码值(mask)的与操作

·右边的操作数( RHS = value & mask )表明模板缓冲中我们将要测试的特定像素(value)应用程序定义的掩码值(mask)的与操作。

模板测试将通过指定的比较运算来比较LHSRHS,这整个表达式的最终结果是一个布尔值(true false)。如果测试结果为true我们将把像素写入后台缓冲,如果是false我们就阻止像素的写入。当然,如果像素没有被写入后台缓冲,它也将不会被写入深度缓冲。

 

     ( ref & mask )  ComparisonOperation ( value & mask )

模板参考值Stencil Reference Value

模板参考值 ref默认为0,但是我们可以通过D3DRS_STENCILREF渲染状态来改变它。

例如,以下的代码设置模板参考值为1:

Device->SetRenderState ( D3DRS_STENCILREF,0x1 );

 

( ref & mask )  ComparisonOperation ( value & mask )

模板掩码值mask用来 遮盖refvalue变量的位。默认的mask0xffffffff,它不会掩盖任何位。我们可以通过设置D3DRS_STENCILMASK渲染状态来改变mask.以下例子表明掩盖高16位:

Device->SetRenderState(D3DRS_STENCILMASK,0x0000ffff);

 

( ref & mask )  ComparisonOperation ( value & mask )

typedef enum _D3DCMPFUNC {

D3DCMP_NEVER = 1,   模板测试永远不能成功

D3DCMP_LESS = 2,   如果LHS < RHS的话,模板测试成功

D3DCMP_EQUAL = 3,  如果LHS = RHS,模板测试成功

D3DCMP_LESSEQUAL = 4,  如果LHS <= RHS 模板测试成功

D3DCMP_GREATER = 5,   如果LHS>RHS 模板测试成功

D3DCMP_NOTEQUAL = 6,  如果LHS !=RHS模板测试成功

D3DCMP_GREATEREQUAL = 7, 如果LHS >= RHS模板测试成功

D3DCMP_ALWAYS = 8,      模板测试永远成功

D3DCMP_FORCE_DWORD = 0x7fffffff

} D3DCMPFUNC;

 

更新模板缓冲

除了决定是否写入或阻止一个特定像素被写入后台缓冲,我们还能通过3种方法来更新定义模板缓冲入口将如何被更新:

1.[i][j]处像素模板缓冲测试失败:

我们可以设置D3DRS_STENCILFAIL渲染状态来定义如何更新模板缓冲中的[i][j]来响应这种情况。

Device->SetRenderState(D3DRS_STENCILFAIL,StencilOperation);

2.[i][j]处像素深度缓冲测试失败:

我们可以设置D3DRS_STENCILZFAIL渲染状态来定义如何更新[i][j]入口来响应这种情况。

Device->SetRenderState(D3DRS_STENCILZFAIL,StencilOperation);

3.[i][j]处像素深度缓冲和模板缓冲测试均成功:

我们可以设置D3DRS_STENCILPASS渲染状态来定义如何更新[i][j]入口来响应这种情况。

Device->SetRenderState( D3DRS_STENCILPASS,StencilOperation);

其中StencilOperation可以是以下预定义常数之一:

· D3DSTENCILOP_KEEP指定不改变模板缓冲

· D3DSTENCILOP_ZERO指定设置模板缓冲为0

· D3DSTENCILOP_REPLACE指定用模板引用值来代替模板缓冲

· D3DSTENCILOP_INCRSAT指定增加模板缓冲入口. 如果增加后的值大于最大值,我们就把它限定为那个最大值。

· D3DSTENCILOP_DECRSAT指定减少模板缓冲入口. 如果减少后的值小于0,我们就把它限定为0

· D3DSTENCILOP_INVERT指定取模板缓冲入口的逆。

· D3DSTENCILOP_INCR指定增加模板缓冲入口. 如果增加后的值大于最大值,我们把它限定为0

· D3DSTENCILOP_DECR指定减少模板缓冲入口. 如果减少后的值小于0,我们就把它限定为无穷大 (maximum allowed value.)

 

以下代码使得模板缓冲中镜子区域为0x1,其它地方为0x0

Device->SetRenderState(D3DRS_STENCILENABLE, true);//开启模板缓冲

//设置比较运算符,指定模板缓冲测试将一直成功

Device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);

//( ref & mask )  ComparisonOperation ( value & mask )

 

//设置模板模板参考值为0x1

Device->SetRenderState(D3DRS_STENCILREF, 0x1);

//设置模板掩码值,mask0xffffffff,它不会掩盖任何位

Device->SetRenderState(D3DRS_STENCILMASK,0xffffffff);   

//设置模板掩码写入值,它可以屏蔽任何我们写入模板的值,

//设置为0xffffffff,它不会屏蔽任何位

Device->SetRenderState(D3DRS_STENCILWRITEMASK, 0xffffffff);   

//深度缓冲测试失败不改变模板缓冲

Device->SetRenderState(D3DRS_STENCILZFAIL,     D3DSTENCILOP_KEEP); 

//模板缓冲测试失败不改变模板缓冲

Device->SetRenderState(D3DRS_STENCILFAIL,      D3DSTENCILOP_KEEP);  

//如果测试通过,用模板引用值0x1来代替模板缓冲入口

Device->SetRenderState(D3DRS_STENCILPASS,      D3DSTENCILOP_REPLACE);

//接下来的代码块是渲染镜子,但是仅仅是渲染模板缓冲中的镜子.

//所以可以屏蔽深度缓冲中的渲染

Device->SetRenderState(D3DRS_ZWRITEENABLE, false);//阻止写入深度缓冲  

//我们可以用设置混合来阻止更新后台缓冲,   

//因为如果测试结果为true我们将把像素写入后台缓冲,

//但此时的pass不是为了写入后台缓冲而是使镜子和墙壁那个面在模板缓冲的值为//0x1

//但后面我们只渲染镜子到模板缓冲,所以只有镜子的值为0x1

Device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

Device->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_ZERO);//源混合因子   

Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);//目标混合因子

//混合结果和目标混合因子相同

 

// 把镜子画入模板缓冲

Device->SetStreamSource(0, VB, 0, sizeof(Vertex));

Device->SetFVF(Vertex::FVF);

Device->SetMaterial(&MirrorMtrl);

Device->SetTexture(0, MirrorTex);

D3DXMATRIX I;

D3DXMatrixIdentity(&I);

Device->SetTransform(D3DTS_WORLD, &I);

Device->DrawPrimitive(D3DPT_TRIANGLELIST, 18, 2);

// 重新开启深度缓冲

Device->SetRenderState( D3DRS_ZWRITEENABLE, true );

 

4.  根据模板测试在后台缓冲中绘制场景

//以下表示仅仅在模板测试成功的地方才会绘制茶壶的倒影。

//即只在镜子区域才会绘制场景。

//如果LHS = RHS,模板测试成功,此时ref0x1,镜子的所在的地方也为0x1

    Device->SetRenderState(D3DRS_STENCILFUNC,  D3DCMP_EQUAL);

//

Teapot->DrawSubset(0);

//

 

5.  恢复状态设置

    Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);

    Device->SetRenderState( D3DRS_STENCILENABLE, false);//关闭模板缓冲

    Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);

 

绘制阴影的时候可以通过设置

Device->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_INCR); // increment to 1

来使得同一个地方只被绘制一次

posted on 2006-02-04 11:19  SweetDream  阅读(3177)  评论(1编辑  收藏  举报