1

我正在使用顶点缓冲区(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;
}
4

2 回答 2

1

当你说“新纹理的坐标”时,你指的是这个:http ://en.wikipedia.org/wiki/UV_mapping ?

如果精灵在更新时获得旧纹理,则可能是一些原因。

1:你的渲染管道如何工作?你为每个drawcall设置每个纹理吗?- 我要找的是如果你只设置一次纹理而不是 perdrawcall (或者如果你用批处理排序)

2:你确定你绑定了你的新纹理吗?

你能在你的绘图功能上发布一些代码吗?

于 2012-10-08T07:44:41.860 回答
0

好吧,我可以看到您将数据复制到锁定的顶点缓冲区然后渲染该数据的问题。你不能这样做。锁定的顶点缓冲区中的数据实际上还不是有效的。它只有在您解锁后才生效。这是因为您正在填写的数据在主内存中,实际上可能是图形卡上的阴影内存。当您解锁时,它将数据复制到图形卡。

因此,如果您为每个绘制调用锁定/解锁,一切正常,因为您正在强制复制。

但是,正如您所发现的,这远非最佳。

您应该做的是一次计算所有四边形顶点位置。然后,您需要遍历并渲染所有四边形(理想情况下,每次调用都无需交换纹理/着色器/等)。

一种方法是在你正在做的时候填充你的顶点缓冲区,然后将绘制命令存储在顶点缓冲区中。这将需要您存储诸如纹理、使用的效果等内容。然后您可以遍历列表并渲染您已经填充的顶点缓冲区中的所有内容。

如果您然后按纹理和着色器常量对事物进行排序(以最大程度地减少状态变化),您会发现您的性能要好很多倍。尽管您需要将顶点缓冲区标记为“动态”,并且建议在锁定顶点缓冲区时使用 D3DLOCK_DISCARD 标志,因为这将丢弃当前在顶点缓冲区中的数据(基本上它将返回一个全新的内存块填充并且不会从卡中复制任何内容)而不是阻塞并等待 GPU 完成使用它。

我希望那是一些帮助!

于 2012-10-08T10:57:57.920 回答