DirectX:渲染到屏幕缓冲区而不使用渲染目标
我在写一个开源的2D游戏引擎,并且我希望支持尽可能多的设备和平台。我目前只有Windows Mobile。我使用DirectX Mobile进行渲染,并将DirectDraw作为后备路径。但是,我遇到了一些麻烦。DirectX:渲染到屏幕缓冲区而不使用渲染目标
似乎虽然参考驱动程序支持createRenderTarget,但很多很多物理设备都不支持createRenderTarget。我需要一些方法来渲染到屏幕而不使用渲染目标,因为我使用纹理四边形渲染精灵,但我也需要能够绘制单个像素。
这是我现在就做:
// save old values
if (Error::Failed(m_D3DDevice->GetRenderTarget(&m_D3DOldTarget)))
{
ERROR_EXPLAIN("Could not retrieve backbuffer.");
return false;
}
// clear render surface
if (Error::Failed(m_D3DDevice->SetRenderTarget(m_D3DRenderSurface, NULL)))
{
ERROR_EXPLAIN("Could not set render target to render texture.");
return false;
}
if (Error::Failed (m_D3DDevice->Clear(
0,
NULL, // target rectangle
D3DMCLEAR_TARGET,
D3DMCOLOR_XRGB(0, 0, 0), // clear color
1.0f,
0
)
)
)
{
ERROR_EXPLAIN("Failed to clear render texture.");
return false;
}
D3DMLOCKED_RECT render_rect;
if (Error::Failed(m_D3DRenderSurface->LockRect(&render_rect, NULL, NULL)))
{
ERROR_EXPLAIN("Failed to lock render surface pixels.");
}
else
{
m_D3DBackSurf->SetBuffer((Pixel*)render_rect.pBits);
m_D3DRenderSurface->UnlockRect();
}
// begin scene
if (Error::Failed(m_D3DDevice->BeginScene()))
{
ERROR_EXPLAIN("Failed to start rendering.");
return false;
}
// =====================
// example rendering
// =====================
// some other stuff, but the most important part of rendering a sprite:
device->SetTexture(0, m_Texture));
device->SetStreamSource(0, m_VertexBuffer, sizeof(Vertex));
device->DrawPrimitive(D3DMPT_TRIANGLELIST, 0, 2);
// plotting a pixel
Surface* target = (Surface*)Device::GetRenderMethod()->GetRenderTarget();
buffer = target->GetBuffer();
buffer[somepixel] = MAKECOLOR(255, 0, 0);
// end scene
if (Error::Failed(device->EndScene()))
{
ERROR_EXPLAIN("Failed to end scene.");
return false;
}
// clear screen
if (Error::Failed(device->SetRenderTarget(m_D3DOldTarget, NULL)))
{
ERROR_EXPLAIN("Couldn't set render target to backbuffer.");
return false;
}
if (Error::Failed(device->GetBackBuffer (
0,
D3DMBACKBUFFER_TYPE_MONO,
&m_D3DBack
)
)
)
{
ERROR_EXPLAIN("Couldn't retrieve backbuffer.");
return false;
}
RECT dest = {
0,
0,
Device::GetWidth(),
Device::GetHeight()
};
if (Error::Failed(device->StretchRect (
m_D3DRenderSurface,
NULL,
m_D3DBack,
&dest,
D3DMTEXF_NONE
)
)
)
{
ERROR_EXPLAIN("Failed to stretch render texture to backbuffer.");
return false;
}
if (Error::Failed(device->Present(NULL, NULL, NULL, NULL)))
{
ERROR_EXPLAIN("Failed to present device.");
return false;
}
我正在寻找一种方式做同样的事情(使用一个缓冲硬件加速和情节像素渲染精灵),而不使用渲染目标。
在此先感谢。
如果您想要与没有硬件3d加速的手持设备(多年来每台台式机都支持渲染目标)进行广泛兼容,那么使用GDI代替DirectX可能会更容易一些。
我并没有完全按照你在发布的代码中试图做的事情,但是我会补充说明渲染目标不支持LockRect(也不支持用渲染目标标志创建的纹理)。虽然DirectX for Windows Mobile与普通DirectX有点不同,所以也许我误解了这一点。如果您真的想在Windows Mobile上使用DirectX,请查看CreateOffscreenPlainSurface或任何其管理的DirectX等价物。该类型的表面将是可锁定的,并且将支持将StretchRect直接用于后台缓冲区。
你没有详细说明如何你想绘制的像素,所以我会开始假设它是真正的复杂性顺序“缓冲区[somepixel] = MAKECOLOR(255,0,0) ;”。
我的建议是,不要回读(这可能是非常昂贵或取决于内存架构相当便宜),修改和写入/上传backbuffer;相反,将您的像素绘制为纹理,并让GPU处理GPU加速精灵和CPU绘制像素的组合。
在基本情况下,这将是这样的:
创建一个4通道的纹理您后备缓冲的大小。如果您的目标系统支持它,请指定LOCKABLE和DYNAMIC使用标志。 (如果没有,或者如果驱动程序更喜欢不可锁定的纹理,则必须通过下面的步骤2的额外系统纹理,并使用UpdateTexture/CopyRects代替上载)
每帧,锁定纹理,绘制像素,解开纹理。确保将覆盖率信息写入像素的alpha通道,以便GPU可以控制一些数据以控制构图。例如。如果您想绘制纯红色,请为该像素写入(255,0,0,255)。确保清除不想实际绘制的像素。
设置GPU以在你的精灵之上组成你绘制的数据。通过渲染带有绘制纹理的全屏四边形纹理(并使用点采样)。对于最简单的不透明构图情况,启用AlphaTestEnable,将AlphaRef设置为128,将AlphaFunc设置为GREATER,并禁用ZEnable。这将在精灵顶部绘制像素,同时保留精灵像素的其余部分不变。
如果您使用的是深度缓存,并且你想获得幻想约获得一些额外的性能,你可以你的精灵之前渲染绘制的纹理,既ZEnable和ZWriteEnabled启用。 (确保你在接*面渲染全屏四边形)然后在你的不透明像素所在的位置填充一个深度缓冲区遮罩,当你以后渲染这些图像时会遮住这些像素。
显然,你不是真的只是覆盖实体像素。您可以使用Alpha混合与创意混合模式和Alpha值的组合来创建其他类型的合成和叠加。
这是一个很好的回复!但是,您的方法仍然存在问题。在一个完美的世界中,我会渲染一个精灵,一个覆盖该精灵的行,然后是另一个精灵。根据画家的算法,该线将在两个精灵之间绘制。获得这个结果的唯一方法(据我所知)是将每一行渲染到它自己的纹理上。 这种方法的一种方法是直接渲染到后缓冲区,但是我的目标设备不支持这一点。 :\ – knight666 2010-03-27 17:17:43
什么阻止你使用DX渲染你的线,例如作为弥漫色四边形?或者,如果您需要它们获取详细的像素信息,也许您可以在应用程序启动时创建纹理,并且以后只渲染纹理?如果你的精灵不透明(或掩盖),确保正确排序的最简单方法就是使用深度缓冲区。如果它们是混合/半透明的,那么是的,你需要将它们排回前面,并将它们与不透明线交错(或者让线条前面写入深度,并且精灵测试深度) – tbone 2010-03-28 03:52:28