D3D9绘图精灵看起来很慢

时间:2019-01-18 08:04:18

标签: c++ directx sprite directx-9

我的应用程序需要绘制许多精灵。但这似乎有点慢(30架正在互相战斗的飞机,意味着+ 30枚动画火箭和爆炸)。

如何解决此问题,使其动画流畅?预先感谢您的帮助!

不知道如何解决这个问题。

struct d3dsprite_s {
    std::wstring wszFile; //File name
    LPD3DXSPRITE pSprite; //Pointer to the sprite object
    LPDIRECT3DTEXTURE9 pTexture; //Pointer to the sprite texture
    int iFrameCount; //Total amount of frames
    int iFramesPerLine; //Amount of frames per line
    int iFrameWidth; //Single frame width
    int iFrameHeight; //Single frame height
};

std::vector<d3dsprite_s> m_vSprites;

HD3DSPRITE LoadSprite(const std::wstring& wszTexture, int iFrameCount, int iFrameWidth, int iFrameHeight, int iFramesPerLine, const bool bForceCustomSize = false)
    {
        //Load sprite

        if (!wszTexture.length())
            return GFX_INVALID_SPRITE_ID;

        d3dsprite_s sSpriteData;

        //Create sprite
        if (FAILED(D3DXCreateSprite(this->m_pDevice, &sSpriteData.pSprite)))
            return GFX_INVALID_SPRITE_ID;

        //Load texture from file
        if (FAILED(D3DXCreateTextureFromFileEx(this->m_pDevice, wszTexture.c_str(), (bForceCustomSize) ? iFrameWidth : D3DX_DEFAULT_NONPOW2, (bForceCustomSize) ? iFrameHeight : D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT, 0, D3DFMT_FROM_FILE, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0xFF000000, nullptr, nullptr, &sSpriteData.pTexture))) {
            sSpriteData.pSprite->Release();
            return GFX_INVALID_SPRITE_ID;
        }

        //Save further data
        sSpriteData.wszFile = wszTexture;
        sSpriteData.iFrameCount = iFrameCount;
        sSpriteData.iFramesPerLine = iFramesPerLine;
        sSpriteData.iFrameWidth = iFrameWidth;
        sSpriteData.iFrameHeight = iFrameHeight;

        //Add to list
        this->m_vSprites.push_back(sSpriteData);

        //Return handle
        return sSpriteData.pSprite;
    }

bool DrawSprite(const HD3DSPRITE hSprite, int x, int y, int iFrame, float fRotation, int rotx, int roty, float fScale1, float fScale2, const bool bUseCustomColorMask, byte r, byte g, byte b, byte a)
    {
        //Add sprite to drawing list

        if (!hSprite)
            return false;

        //Find sprite
        size_t uiSprite = this->FindSprite(hSprite);
        if (uiSprite == GFX_INVALID_LIST_ID)
            return false;

        if ((!this->m_vSprites[uiSprite].pTexture) || (!this->m_vSprites[uiSprite].pSprite))
            return false;

        //Calculate horizontal line ID
        int iFrameLineId = (this->m_vSprites[uiSprite].iFramesPerLine > 0) ? iFrame / this->m_vSprites[uiSprite].iFramesPerLine : 0;
        //Calculate vertical frame ID
        int iFrameVerticalId = (this->m_vSprites[uiSprite].iFramesPerLine > 0) ? iFrame % this->m_vSprites[uiSprite].iFramesPerLine : 0;

        //Calculate x position of frame
        int iFrameXPos = iFrameVerticalId * this->m_vSprites[uiSprite].iFrameWidth;
        //Calculate y position of frame
        int iFrameYPos = iFrameLineId * this->m_vSprites[uiSprite].iFrameHeight;

        //Setup rectangle info
        RECT sRect;
        sRect.top = iFrameYPos;
        sRect.left = iFrameXPos;
        sRect.bottom = iFrameYPos + this->m_vSprites[uiSprite].iFrameHeight;
        sRect.right = iFrameXPos + this->m_vSprites[uiSprite].iFrameWidth;

        //Begin drawing sprite
        if (FAILED(this->m_vSprites[uiSprite].pSprite->Begin(D3DXSPRITE_ALPHABLEND)))
            return false;

        //Setup vector with position
        D3DXVECTOR2 vPosition = { (float)x, (float)y };

        //Setup vector with sprite center
        D3DXVECTOR2 vRotCenter;
        if ((rotx != -1) && (roty != -1))
            vRotCenter = { (float)(rotx), (float)(roty) };
        else
            vRotCenter = { (float)(this->m_vSprites[uiSprite].iFrameWidth / 2) , (float)(this->m_vSprites[uiSprite].iFrameHeight / 2) };

        D3DXMATRIX vNewMatrix;

        //Setup scale vector
        D3DXVECTOR2 vScale(fScale1, fScale2);

        //Calculate transformation matrix
        if (!D3DXMatrixTransformation2D(&vNewMatrix, ((fScale1 != 0.0f) && (fScale2 != 0.0f)) ? &vRotCenter : nullptr, 0.0f, ((fScale1 != 0.0f) && (fScale2 != 0.0f)) ? &vScale : nullptr, (D3DXVECTOR2*)&vRotCenter, fRotation, &vPosition))
            return false;

        //Apply transformation
        if (FAILED(this->m_vSprites[uiSprite].pSprite->SetTransform(&vNewMatrix)))
            return false;

        //Add sprite to batch list
        if (FAILED(this->m_vSprites[uiSprite].pSprite->Draw(this->m_vSprites[uiSprite].pTexture, &sRect, nullptr, nullptr, (bUseCustomColorMask) ? D3DCOLOR_RGBA(r, g, b, a) : 0xFFFFFFFF)))
            return false;

        //End drawing sprite
        return SUCCEEDED(this->m_vSprites[uiSprite].pSprite->End());
    }

const size_t FindSprite(const HD3DSPRITE hSprite)
    {
        //Get list ID of sprite handle if exists

        for (size_t i = 0; i < this->m_vSprites.size(); i++) {
            if (this->m_vSprites[i].pSprite == hSprite)
                return i;
        }

        return GFX_INVALID_LIST_ID;
    }

预期:快速绘制精灵 实际:子画面绘制缓慢

1 个答案:

答案 0 :(得分:0)

主要问题是,至少根据上面的代码,您为每个精灵使用了不同的ID3DX11Sprite实例。这消除了Sprite机制批量渲染的机会,因此您浪费了最大的渲染时间。它必须捕获状态,更新VB / IB,设置VB / IB和所有渲染状态,绘制4个点,然后在每个精灵上恢复状态。那样会很慢。

您应该为所有绘图使用ID3DX11Sprite一个实例,并在调用Begin one 之间绘制尽可能多的精灵。并打给End

  

Direct3D 9是旧版。 ID3DX11Sprite是已弃用的D3DX9的一部分,仅在寿命终止的DirectX SDK中可用。参见Microsoft Docs

     

对于任何现代应用程序,使用Direct3D 11或Direct3D 12都会更好。 DirectX Tool Kit中的SpriteBatch提供了有效绘制精灵所需的功能,以及纹理加载器等。请参见Living without D3DX