Масштабирование текстуры

Как с помощью Direct-X9 масштабировать текстуру до точного размера в файле?

Я просматриваю свою текстуру в MSPaint, и она имеет размер 261 x 210. В MSPaint отображается нормально. Однако, когда я рисую свою текстуру, она рисуется намного больше, чем обычно. По какой-то причине он растянут, хотя я установил масштабирование на 0f.

Мой код выглядит следующим образом:

#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif

#include <tchar.h>
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9tex.h>

IDirect3D9* d3d = nullptr;
IDirect3DDevice9* device = nullptr;
IDirect3DTexture9* Texture = nullptr;
ID3DXSprite* Sprite = nullptr;

const int Width = 800;
const int Height = 600;

void init(HWND hwnd, IDirect3D9* &d3d, IDirect3DDevice9* &device, int Width, int Height);
void render(IDirect3DDevice9* device);
void cleanup(IDirect3D9* &d3d, IDirect3DDevice9* &device);
void LoadTexture(const char* FilePath, IDirect3DTexture9* &Texture, ID3DXSprite* &Sprite);
void LoadTexture(unsigned char* buffer, int width, int height, IDirect3DTexture9* &Texture, ID3DXSprite* &Sprite);


LRESULT __stdcall WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return 0;
}

int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg = {0};

    WNDCLASSEX wc =
    {
        sizeof(WNDCLASSEX), CS_VREDRAW | CS_HREDRAW | CS_OWNDC,
        WindowProcedure, 0, 0, hInstance, nullptr, nullptr, (HBRUSH)(COLOR_WINDOW+1),
        nullptr, _T("DXClass"), nullptr
    };

    if(RegisterClassEx(&wc))
    {
        HWND hwnd = CreateWindow(_T("DXClass"), _T("DirectX Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, nullptr, nullptr, hInstance, nullptr);
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
        init(hwnd, d3d, device, Width, Height);
        LoadTexture("C:/Users/School/Desktop/Test.bmp", Texture, Sprite);

        while(true)
        {
            while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }

            if(msg.message == WM_QUIT)
                break;

            render(device);
        }

        cleanup(d3d, device);
        return msg.wParam;
    }
    return 0;
}


void init(HWND hwnd, IDirect3D9* &d3d, IDirect3DDevice9* &device, int Width, int Height)
{
    d3d = Direct3DCreate9(D3D_SDK_VERSION);
    D3DPRESENT_PARAMETERS parameters = {0};
    ZeroMemory(&parameters, sizeof(parameters));
    parameters.Windowed = true;
    parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
    parameters.hDeviceWindow = hwnd;
    parameters.BackBufferFormat = D3DFMT_X8R8G8B8;
    parameters.BackBufferWidth = Width;
    parameters.BackBufferHeight = Height;
    d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &parameters, &device);
}

void render(IDirect3DDevice9* device)
{
    device->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
    device->BeginScene();

    if (Sprite && Texture)
    {
        D3DXMATRIX world = {0}, rotation = {0}, scale = {0}, translation = {0};
        D3DXMatrixIdentity(&world);

        D3DXMatrixScaling(&scale, 1.0f, 1.0f, 1.0f);
        D3DXMatrixRotationYawPitchRoll(&rotation, 0.0f, 0.0f, 0.0f);
        D3DXMatrixTranslation(&translation, 0.0f, 0.0f, 0.0f);
        world = rotation * scale * translation;

        Sprite->SetTransform(&world);
        D3DXVECTOR3 Position = D3DXVECTOR3(0, 0, 0);

        Sprite->Begin(D3DXSPRITE_ALPHABLEND);
        Sprite->Draw(Texture, nullptr, nullptr, &Position, 0xFFFFFFFF);
        Sprite->End();
    }

    device->EndScene();
    device->Present(nullptr, nullptr, nullptr, nullptr);
}

void cleanup(IDirect3D9* &d3d, IDirect3DDevice9* &device)
{
    if (Sprite) Sprite->Release();
    if (Texture) Texture->Release();
    if (device) device->Release();
    if (d3d) d3d->Release();
}

void LoadTexture(const char* FilePath, IDirect3DTexture9* &Texture, ID3DXSprite* &Sprite)
{
    D3DXCreateTextureFromFile(device, FilePath, &Texture);
    D3DXCreateSprite(device, &Sprite);
}

void LoadTexture(unsigned char* buffer, int width, int height, IDirect3DTexture9* &Texture, ID3DXSprite* &Sprite)
{
    device->CreateTexture(width, height, 1, 0, D3DFMT_X8B8G8R8, D3DPOOL_MANAGED, &Texture, 0);
    D3DXCreateSprite(device, &Sprite);

    D3DLOCKED_RECT rect;
    Texture->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD);
    unsigned char* dest = static_cast<unsigned char*>(rect.pBits);
    memcpy(dest, buffer, width * height * 4);
    Texture->UnlockRect(0);
}

Есть идеи? Кроме того, есть ли лучший способ нарисовать мою текстуру? Например, может быть, без спрайта? Я новичок в Direct-X.


person Brandon    schedule 24.01.2014    source источник


Ответы (1)


Для эффективности текстурные поверхности обычно должны иметь размерность, равную степени 2: например. 64, 512 и т. д. Хотя разное оборудование реализует растеризацию по-разному, обращение к отдельным пикселям текстуры потребует значительного умножения. Например, чтобы обратиться к текселу в изображении, вы можете использовать этот код:

texel = PixelDataArray[y * texture_width + x];

однако, если 'texture_width' является степенью двойки, скажем, 256, тогда будет выполняться та же работа:

int texture_width_shift_by = 8;
texel = PixelDataArray[y << texture_width_shift_by + x];

Преимущество заключается в том, что для реализации аппаратного сдвига требуется намного меньше, кремний может работать намного быстрее, чем умножение. Когда вы выполняете миллионы таких операций в каждом кадре с использованием параллельного оборудования, выигрыш может быть значительным.

В любом случае, в результате вы должны сохранить это изображение со степенью двух измерений, а затем, если вы хотите использовать обрезанную область на этой поверхности, сделайте это, используя координаты UV.

person Luther    schedule 24.01.2014