DirectX-带实例化模具体积的延迟着色
DirectX - Deferred Shading w/Instanced Stencil Volumes
我正在使用DXUT使用DirectX9创建一个图形应用程序。在我的应用程序中,我希望实现延迟着色。这种照明方法要求我为场景中的每个灯光渲染一个模具体积(遮罩)。为了避免单独渲染卷,我希望使用DirectX的实例化功能。使用顶点着色器3.0和像素着色器3.0,我已经成功地绘制了任何给定模型的多个实例,但是,当我尝试绘制实例化的模具体积时,似乎没有数据写入后缓冲区的深度模具表面。
我在伪代码中实现的延迟着色如下:
将所有场景几何体(实例化几何体过程)绘制到后台缓冲区:
- 启用Z(D3DRS_ZENABLE,TRUE)
- 启用ZWrites(D3DRS_ZWRITENABLE,TRUE)
- 禁用模具(D3DRS_STENCILENABLE,FALSE)
- 设置CullMode(D3DRS_CullMode、D3DCULL_CCW)
- 禁用ColorWrites(D3DRS_COLORWRITENABLE,0)
- 禁用字母混合(D3DRS_ALPHABLENDENABLE,FALSE)
- 渲染场景
获取指向后台缓冲区的指针:
- IDirect3DDevice9::GetRenderTarget(0,pBackbufferSurface)
设置3个渲染目标(COLOR(0)、NORMAL(1)、POSITION(2)):
- IDirect3DDevice9::SetRenderTarget(0->2,COLOR->POSITION)
绘制3个渲染目标的所有场景几何体:
- 启用ColorWrites(D3DRS_COLORWRITENABLE、CW_RED、CW_GREEN、,CW_BLUE,CW_ALPHA)
- 渲染场景
将后台缓冲区重置为设备RenderTarget 0:
- IDirect3DDevice9::SetRenderTarget(0,pBackbufferSurface)
将效果纹理(SrcColor)设置为COLOR渲染目标
- ID3DXEffect::SetTexture("g_TextureSrcColor",pRTColor)
从COLOR渲染目标渲染全屏四边形和采样(绘制场景)
使用实例化技术(此处为实际代码)对所有场景灯光进行模板处理:
// set the instance buffer vertex declaration
hr = pd3dDevice->SetVertexDeclaration( CContentManager::GetInstanceBufferVertexDeclaration() );
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to IDirect3DDevice9::SetVertexDeclaration( instances )at RenderScene()", __LINE__, hr );
return hr;
}
// render instances of each light( sphere and cone )
for( UINT i = 0; i < 2; ++i )
{
// point to base model
CXModel *pXBase = ( CXModel* )pCM->GetAppObject( i );
if( !pXBase )
{
DebugStringDX( ClassName,
"Failed to retrieve the base light model at index( " + ToString( i ) + " ) at Render()",
__LINE__,
E_POINTER );
continue;
}
// if the model has no instances
// there is no reason to try and draw
UINT ucInstances = pXBase->GetNumInstances();
if( ucInstances < 1 )
continue;
// Set up the geometry data stream
hr = pd3dDevice->SetStreamSourceFreq( 0,
( D3DSTREAMSOURCE_INDEXEDDATA | ucInstances ) );
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to IDirect3DDevice9::SetStreamSourceFreq( source )( index - " + ToString( i ) + " ) at RenderScene()", __LINE__, hr );
continue;
}
// Set up the instance data stream
IDirect3DVertexBuffer9 *pVBInstances = pXBase->GetInstanceBuffer();
hr = pd3dDevice->SetStreamSource( 1, pVBInstances, 0,
sizeof( CXModel::sInstanceEntry ) );
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to IDirect3DDevice9::SetStreamSource( instances )( index - " + ToString( i ) + " ) at RenderScene()", __LINE__, hr );
continue;
}
hr = pd3dDevice->SetStreamSourceFreq( 1,
( D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) );
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to IDirect3DDevice9::SetStreamSourceFreq( instances )( index - " + ToString( i ) + " ) at Render()", __LINE__, hr );
continue;
}
// get light model frame root
pFrame = pXBase->GetFrameRoot();
if( !pFrame )
{
DebugStringDX( ClassName, "Failed to CXModel::GetFrameRoot( Light Model ) at Render()", __LINE__, hr );
continue;
}
//------------------------------------------------------------------------------------------------------------
// Stencil Volume Mask Pass
//------------------------------------------------------------------------------------------------------------
dev.SetRenderState( D3DRS_ZENABLE, TRUE );
dev.SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
dev.SetRenderState( D3DRS_STENCILENABLE, TRUE );
dev.SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
dev.SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );
dev.SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_INCR );
dev.SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
dev.SetRenderState( D3DRS_STENCILWRITEMASK, 0xffffffff );
dev.SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
dev.SetRenderState( D3DRS_COLORWRITEENABLE, 0 );
hr = BeginPass( CFXDeferred::STENCIL );
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to BeginPass( StencilVolumeMask ) at Render()", __LINE__, hr );
continue;
}
// draw the light model
hr = DrawStaticModel( pd3dDevice, pFrame, &mWorld, pmView, pmProjection, true, bRenderStrips );
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to DrawStaticModel( Light Model ) at Render()", __LINE__, hr );
continue;
}
hr = pE->EndPass();
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to ID3DXEffect::EndPass() at Render()", __LINE__, hr );
continue;
}
//------------------------------------------------------------------------------------------------------------
// Diffuse Light Pass
//------------------------------------------------------------------------------------------------------------
dev.SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
dev.SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
dev.SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
dev.SetRenderState( D3DRS_ZENABLE, FALSE );
dev.SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );
dev.SetRenderState( D3DRS_COLORWRITEENABLE,
D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
dev.SetRenderState( D3DRS_STENCILENABLE, TRUE );
dev.SetRenderState( D3DRS_STENCILFUNC, D3DCMP_EQUAL );
dev.SetRenderState( D3DRS_STENCILMASK, 0x1 );
dev.SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_ZERO );
dev.SetRenderState( D3DRS_STENCILREF, 0x1 );
dev.SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
dev.SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_ZERO );
hr = BeginPass( CFXDeferred::DIFFUSELIGHTSTENCIL );
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to BeginPass( DiffuseSpecularLightStencilPass ) at Render()", __LINE__, hr );
continue;
}
// draw light model
hr = DrawStaticModel( pd3dDevice, pFrame, &mWorld, pmView, pmProjection, true, bRenderStrips );
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to DrawStaticModel( Light Model ) at Render()", __LINE__, hr );
continue;
}
hr = pE->EndPass();
if( FAILED( hr ) )
{
DebugStringDX( ClassName, "Failed to ID3DXEffect::EndPass() at Render()", __LINE__, hr );
continue;
}
}
以下是实例缓冲区顶点声明:
// create instance vertex declaration
D3DVERTEXELEMENT9 pElements[] = {
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 1, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
{ 1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },
{ 1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },
{ 1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 },
{ 1, 64, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 5 },
D3DDECL_END()
};
这种方法在不实例化的情况下运行良好。。。实例化是否阻止深度模具写入?当我使用PIX进行调试时,它表示"Pixel未通过模具测试"。以下是在渲染前清除后台缓冲区的调用:
pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_ARGB( 0, 0, 0, 0 ), 1.0f, 0 ) );
在创建设备的过程中,我修改设置以使用AutoDepthStencilFormat D3DFMT_D24S8,如下所示:
// check for D3DFMT_D24S8 AutoDepthStencilFormat
// if present set the AutoDepthStencilFormat to D3DFMT_D24S8
if( DXUTGetD3D9Enumeration()->GetPossibleDepthStencilFormatList()->Contains( D3DFMT_D24S8 ) )
{
pDeviceSettings->d3d9.pp.AutoDepthStencilFormat = D3DFMT_D24S8;
}
如果我将IDirect3DDevice9::Clear()的模具参数(最后一个参数)更改为1。模具卷通过了模具测试。。。这是因为我设置了模板操作,如果体积掩模的像素与后缓冲区上的像素相交,则将模板值增加1,并且在该事件中,允许灯光的像素颜色。这表明存在两个问题之一:
- 在"实例化几何体过程"期间绘制场景(对象)时。。。backbuffer没有在绘制对象时存储对象的深度(因此模具测试有一个"0"值用于比较或
- 绘制模具体积(灯光)时,后台缓冲区不会在绘制时存储体积的深度
这是因为我的实例化方法吗?是由于着色器版本(vs3、ps3)还是DX版本?
问题是我用vs_3_0编译了顶点着色器(用于模具体积遮罩)……我把它改为vs_2_0,现在它工作得很好。。。我不明白,因为我认为有必要使用顶点着色器模型3.0和实例化。。。
- 从C++实例化QML
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 约束和显式模板实例化
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 对象实例化调用构造函数的次数太多
- 如何使用非默认构造函数实例化模板化类
- 静态数据成员模板专用化的实例化点在哪里
- 错误的cv::face FacemarkLBF实例化
- C++的解析器在可以区分比较和模板实例化之前会做什么?
- 为什么 gcc 和 clang 为函数模板的实例化生成不同的符号名称?
- 检查某些类型是否是模板类 std::optional 的实例化
- 模板化类中静态成员的延迟初始化
- 在声明或实现中延迟初始化C++单一实例
- 延迟 crtp 基类中的成员函数实例化
- 使用静态成员实例的 C++ 中的线程安全单一实例(无延迟实例化)
- DirectX-带实例化模具体积的延迟着色
- 实例化的点是否可以延迟到翻译单元结束
- 延迟函数模板实例化