1

頂点バッファー(DrawPrimitive)を使用してDX9で2Dスプライトをレンダリングしています。一部のアニメーションには、サイズの異なる異なるテクスチャファイルが含まれています。

ここで、次の問題が発生します。テクスチャファイルが異なる2つのアニメーションを切り替える非常に単一のフレーム(たとえば、歩行を開始するとき、または歩行を終了して立ち始めるとき)で、新しいテクスチャの座標でレンダリングされます。しかし、まだ古いテクスチャを提示しています。これは、新しいアニメーションのテクスチャを設定しなかったかのように見えます。唯一の問題は-私がやったことです。

何が問題なのかをどのように理解したか:そのフレームでスクリーンショットを撮ったところ、一方のテクスチャがもう一方のテクスチャに適合する座標でレンダリングされていることに気付きました。

レンダリング関数では、座標を計算するのではなく、最初に新しいテクスチャを取得して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:レンダーパイプラインはどのように機能しますか?各ドローコールに各テクスチャを設定しますか?-私が探しているのは、テクスチャを一度だけ設定し、perdrawcallを設定しない場合(またはこれをバッチで並べ替える場合)です

2:新しいテクスチャをバインドしてもよろしいですか?

描画関数にコードを投稿できますか?

于 2012-10-08T07:44:41.860 に答える
0

ロックされた頂点バッファにデータをコピーしてから、そのデータをレンダリングしているという問題がわかります。あなたはこれを行うことはできません。ロックされた頂点バッファのデータは、実際にはまだ有効ではありません。ロックを解除すると有効になります。これは、入力するデータがメインメモリにあり、実際にはグラフィックカードのメモリをシャドウイングしている可能性があるためです。ロックを解除すると、データがグラフィックカードにコピーされます。

そのため、ドローコールごとにロック/ロック解除すると、コピーを強制的に戻すため、すべてが正常に機能します。

ただし、ご存知のとおり、これは最適とは言えません。

あなたがすべきことは、1回のパスですべての大腿四頭筋の位置を計算することです。次に、すべてのクワッドを調べてレンダリングする必要があります(理想的には、呼び出しごとにテクスチャ/シェーダーなどを交換する必要はありません)。

これを行う1つの方法は、実行中に頂点バッファーを埋めてから、描画コマンドを頂点バッファーに格納することです。これには、テクスチャ、使用した効果などを保存する必要があります。次に、リストを実行して、すでに入力した頂点バッファからすべてをレンダリングできます。

次に、テクスチャとシェーダーの定数で並べ替えると(状態の変化を最小限に抑えるため)、パフォーマンスが何倍も向上することがわかります。頂点バッファを「動的」としてマークする必要がありますが、頂点バッファをロックするときにD3DLOCK_DISCARDフラグを使用することをお勧めします。これにより、現在頂点バッファにあるデータが破棄されます(基本的にはまったく新しいメモリブロックが返されます) GPUがそれを使用し終えるのをブロックして待つ代わりに、カードを埋めて何もコピーしません)。

お役に立てば幸いです。

于 2012-10-08T10:57:57.920 に答える