我使用顶点缓冲区(DrawPrimitive)使用DX9渲染2D精灵。 一些动画获得了不同大小的不同纹理文件。
现在我遇到了以下问题:在我在两个具有不同纹理文件的动画之间切换的单帧上(例如,当开始行走或完成行走并开始站立时),它使用坐标进行渲染新纹理,但仍呈现旧纹理。这看起来好像我没有为新动画设置纹理。唯一的问题是 - 我做了。
我如何理解问题所在:我在该帧上截取了一个截图,并注意到它渲染了一个纹理,坐标适合另一个纹理。
在我的渲染功能中,我首先获得新纹理并将其发送到DX,而不是计算坐标,最后我使用坐标和新纹理集渲染我的顶点。我检查并调试了数百万次并且所有值都是正确的,但是错误发生了。
为什么会发生这种情况的任何想法?
谢谢!
编辑:添加了一些代码:
// Render a quad using the vertex buffer
void CGraphicsManager::RenderQuadViaVertexBuffer(const SVertex* pVertices) const
{
// Increase renders count
this->m_RenderCount++;
// vb_vertices now points to our vertices inside the Vertex buffer, so
// to fill in our VB, we copy to vb_vertices.
memcpy(this->m_pVertexBufferBuffPtr + this->m_OffsetInVertexBuffer, pVertices, sizeof(SVertex) * (VERTICES_IN_QUAD));
// Render the rectanlge using the vertices we got.
this->m_pD3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, this->m_OffsetInVertexBuffer, PRIMITIVES_IN_QUAD);
// Increment the offset in the vertex buffer
this->m_OffsetInVertexBuffer += VERTICES_IN_QUAD;
}
// Render a quad
void CGraphicsManager::Render(const STexture& p_Texture, SLocation p_RenderLocation, SSize p_RenderSize, const SQuad& p_TextureQuad, SfColor p_RenderColor, ERenderEffects p_RenderEffect) const
{
// Set render effect
this->SetRenderEffect(p_RenderEffect);
// Set texture
this->SetTexture(p_Texture);
// Set the vertex needed for the rendering
VerticesForQuadRender[0].Position.x = p_RenderLocation.x;
VerticesForQuadRender[0].Position.y = p_RenderLocation.y;
VerticesForQuadRender[0].Position.z = 0.0f;
VerticesForQuadRender[0].color = p_RenderColor;
VerticesForQuadRender[0].tv = p_TextureQuad.left;
VerticesForQuadRender[0].tu = p_TextureQuad.top;
VerticesForQuadRender[1].Position.x = p_RenderLocation.x + p_RenderSize.x;
VerticesForQuadRender[1].Position.y = p_RenderLocation.y;
VerticesForQuadRender[1].Position.z = 0.0f;
VerticesForQuadRender[1].color = p_RenderColor;
VerticesForQuadRender[1].tv = p_TextureQuad.right;
VerticesForQuadRender[1].tu = p_TextureQuad.top;
VerticesForQuadRender[2].Position.x = p_RenderLocation.x;
VerticesForQuadRender[2].Position.y = p_RenderLocation.y + p_RenderSize.y;
VerticesForQuadRender[2].Position.z = 0.0f;
VerticesForQuadRender[2].color = p_RenderColor;
VerticesForQuadRender[2].tv = p_TextureQuad.left;
VerticesForQuadRender[2].tu = p_TextureQuad.bottom;
VerticesForQuadRender[3].Position.x = p_RenderLocation.x + p_RenderSize.x;
VerticesForQuadRender[3].Position.y = p_RenderLocation.y + p_RenderSize.y;
VerticesForQuadRender[3].Position.z = 0.0f;
VerticesForQuadRender[3].color = p_RenderColor;
VerticesForQuadRender[3].tv = p_TextureQuad.right;
VerticesForQuadRender[3].tu = p_TextureQuad.bottom;
this->RenderQuadViaVertexBuffer(VerticesForQuadRender);
}
// Starts a rendering frame
bool CGraphicsManager::StartFrame()
{
// Clear texture
this->ClearTexture();
// Zero renders count
this->m_RenderCount = 0;
// Clear screen
if (!this->ClearScreen())
{
this->ResetDevice();
return false;
}
// Begin new rendering scene
if (FAILED(this->m_pD3dDevice->BeginScene()))
{
this->ResetDevice();
return false;
}
// Set render from our vertex buffer
this->BeginRenderFromVertexBuffer();
return true;
}
// Finish rendering
bool CGraphicsManager::EndFrame()
{
// Unlock vertex buffer
this->m_pVertexBuffer->Unlock();
// Notify the device that we're finished rendering for this frame
if (FAILED(this->m_pD3dDevice->EndScene()))
{
this->ResetDevice();
return false;
}
// Present scene
if(FAILED(this->m_pD3dDevice->Present(NULL, //Source rectangle to display, NULL for all of it
NULL, //Destination rectangle, NULL to fill whole display
NULL, //Target window, if NULL uses device window set in CreateDevice
NULL ))) //Dirty Region, set it to NULL
{
this->ResetDevice();
return false;
}
// Finish rendering
return true;
}
// This function must be called before rendering textured surfaces
void CGraphicsManager::BeginRenderFromVertexBuffer() const
{
// Lock the vertex buffer (unlock on release) and get the pointer to the begining of the buffer
HRESULT hr = this->m_pVertexBuffer->Lock
(0, // Offset, we want to start at the beginning
0, //SizeToLock, 0 means lock the whole thing
(void**)&this->m_pVertexBufferBuffPtr, //If successful, this will point to the data in the vertex buffer
0);
ASSERT(SUCCEEDED(hr), "Failed to lock vertex buffer! (err: " << hr << ")");
// Set offset in vertex buffer back to 0
this->m_OffsetInVertexBuffer = 0;
}
答案 0 :(得分:1)
当你说“新纹理的坐标”时,你是否正在考虑这个问题:http://en.wikipedia.org/wiki/UV_mapping?
如果精灵在更新时获得旧纹理,可能会有一些事情。
1:您的renderpipeline的剂量如何?你为每个drawcall设置每个纹理? - 我想要的是你只需设置一次纹理而不是perdrawcall(或者如果你用批次对它进行排序)
2:你确定绑定了新纹理吗?
你可以在你的绘图功能上发布一些代码吗?答案 1 :(得分:0)
我可以看到您将数据复制到锁定的顶点缓冲区然后渲染该数据的问题。你不能这样做。锁定顶点缓冲区中的数据实际上尚未生效。只有解锁后它才会生效。这是因为您填写的数据位于主内存中,实际上可能是显卡上的内存。解锁后,将数据复制到图形卡上。
因此,如果您为每次绘制调用锁定/解锁,一切正常,因为您正在强制复制。
但是,正如您所发现的那样,这远非最佳。
您应该做的是在一次通过中计算所有四个顶点位置。然后你需要经历并渲染所有的四边形(理想情况下,不需要交换每次调用的纹理/着色器/等)。
执行此操作的一种方法是在执行时填充顶点缓冲区,然后将绘制命令存储在顶点缓冲区中。这将需要您存储纹理,使用的效果等内容。然后您可以运行列表并从已填充的顶点缓冲区渲染所有内容。
如果你按照纹理和着色器常量对事物进行排序(以最小化状态变化),你会发现你的表现要好很多倍。虽然您需要将顶点缓冲区标记为“动态”,并且建议在锁定顶点缓冲区时使用D3DLOCK_DISCARD标志,因为这会丢弃当前在顶点缓冲区中的数据(基本上它会返回一个全新的内存块)填写并且不会从卡中复制任何内容)而不是阻止并等待GPU完成使用它。
我希望有所帮助!