我正在编写一个开源2D游戏引擎,我希望尽可能多地支持设备和平台。我目前只有Windows Mobile。我使用DirectX Mobile渲染,DirectDraw作为后备路径。但是,我遇到了一些麻烦。
虽然参考驱动程序支持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;
}
我正在寻找一种方法来做同样的事情(使用硬件加速渲染精灵并在缓冲区上绘制像素)而不使用渲染目标。
提前致谢。
答案 0 :(得分:2)
你没有详细说明想要绘制像素的 ,所以我要假设它真的是在“buffer [somepixel] = MAKECOLOR(255, 0,0);“。
我的建议是,不是回读(根据内存架构可能非常昂贵或相当便宜),修改,写入/上传后备缓冲区;相反,将像素绘制为纹理,让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值组合使用,以创建其他类型的合成和叠加。
答案 1 :(得分:0)
如果您希望与没有硬件3D加速的手持设备(多年来每台台式计算机都支持渲染目标)具有广泛的兼容性,那么您可以更轻松地使用GDI而不是DirectX。
我并不完全遵循您在发布的代码中尝试做的事情,但我会补充说,渲染目标不支持LockRect(也不支持使用渲染目标标志创建的纹理)。 DirectX for Windows mobile虽然与普通的DirectX有点不同,所以也许我误解了这个。如果你真的想在Windows Mobile上使用DirectX,请查看CreateOffscreenPlainSurface,或者其管理的任何东西 - 与DirectX等价。这种类型的表面是可锁定的,并且支持将StretchRect直接用于后台缓冲区。