D3D9 рисование спрайтов кажется медленным - PullRequest
0 голосов
/ 18 января 2019

Мое приложение должно рисовать много спрайтов. Но почему-то это кажется медленным (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 голосов
/ 19 января 2019

Основная проблема заключается в том, что вы используете отдельный экземпляр ID3DX11Sprite для каждого спрайта, по крайней мере, на основе приведенного выше кода. Это исключает любую возможность для спрайтового механизма пакетного рендеринга, и поэтому вы тратите максимальное время рендеринга. Он должен захватить состояние, обновить VB / IB, установить VB / IB и все состояния рендеринга, нарисовать 4 точки, а затем восстановить состояние на каждом спрайте. Это будет медленно.

Вы должны иметь один экземпляр ID3DX11Sprite для всего вашего рисунка и рисовать столько спрайтов, сколько сможете между одним вызовом Begin и одним вызовом End.

Direct3D 9 является устаревшим. ID3DX11Sprite является частью D3DX9, которая устарела и доступна только в DirectX SDK с истекшим сроком эксплуатации. См. Документы Microsoft .

Вам гораздо лучше использовать Direct3D 11 или Direct3D 12 для любого современного приложения. SpriteBatch в DirectX Tool Kit обеспечивает функциональность, необходимую для эффективного рисования спрайтов, а также загрузчиков текстур и т. Д. См. Жизнь без D3DX .

...