在directx中绘制一个圆圈9

时间:2016-04-25 05:36:13

标签: c++ directx graphics2d

我很难弄清楚如何在directx中绘制圆圈。我能够绘制一个三角形,所以我想我可以通过旋转一个圆形的三角形来画一个。但是,我绝对难过。我已经在网上搜了好几个小时而没有运气。谁能帮我吗?这是我的代码:

Main.cpp的

#include "Engine.h"
#include "Box2D.h"
#include "Triangle2D.h"

class MyApp : public Engine {
public:

    Box2D box2D;
    Triangle2D triangle2D;

    void OnStartup() override {
        box2D.New(10.0f, 10.0f, 100.0f, 100.0f, D3DCOLOR_ARGB(0xff, 0x00, 0x00, 0xff)); 
        triangle2D.New(150.0f, 10.0f, 100.0f, 100.0f, D3DCOLOR_ARGB(0xff, 0xff, 0x00, 0x00));
    }

    void OnShutdown() override {
        box2D.Delete();
        triangle2D.Delete();
    }

    void OnDraw() override {
        box2D.Draw();
        triangle2D.Draw();
    }

    void OnMouseDown(int x, int y) {
        Debug("%d %d\n", x, y);
    }

};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    MyApp app;
    app.Run();
    return 0;
}

Engine.cpp

#include "Engine.h"

// Initialize the classes static variables
Engine* Engine::_ENGINE = NULL;

// Returns the current instance of this class
Engine* Engine::GetInstance()
{
    return _ENGINE;
}

// Constructor
Engine::Engine()
: _exit(false)
, _window(NULL)
, _directx(NULL)
, _device(NULL)
{
    _ENGINE = this;
}

// Deconstructor
Engine::~Engine() {
    _ENGINE = NULL;
}

// Run the core main event loop, start to finish
bool Engine::Run() {

    // Create the Windows class
    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_CLASSDC;
    wc.lpfnWndProc = _WND_PROC;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszClassName = _GetModuleName();
    RegisterClassEx(&wc);

    // Adjust the window rect for the flags
    RECT rect;
    SetRect(&rect, 0, 0, _WIDTH, _HEIGHT);
    const DWORD windowFlags = WS_OVERLAPPED | WS_CAPTION | WS_CLIPCHILDREN | WS_SYSMENU | WS_MINIMIZEBOX;
    AdjustWindowRectEx(&rect, windowFlags, FALSE, 0);

    // Create the window
    _window = CreateWindowEx(0, _GetModuleName(), _GetModuleName(), windowFlags, 0, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandle(NULL), NULL);
    if (_window == NULL)
        return false;

    // Move the window to the center of the screen
    RECT system;
    SystemParametersInfo(SPI_GETWORKAREA, 0, &system, 0);
    MoveWindow(_window, (system.right - system.left) / 2 - (rect.right - rect.left) / 2, (system.bottom - system.top) / 2 - (rect.bottom - rect.top) / 2, rect.right - rect.left, rect.bottom - rect.top, TRUE);

    // Startup Direct X
    if (_DirectXStartup() == false)
        return false;

    // Call our startup callback
    OnStartup();

    // Show the window
    ShowWindow(_window, SW_SHOWNORMAL);

    // Run the event loop
    MSG msg;
    ULONGLONG timer = GetTickCount64();
    while (!_exit) {

        // Handle normal system events
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        // Run the timer at the framerate
        if (timer + 1000 / _FPS < GetTickCount64()) {
            timer = GetTickCount64();

            // Clear the buffer
            _device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0x00, 0xff, 0x00), 1.0f, NULL);

            // Call our draw callback every frame
            OnDraw();

            // Render to screen
            _device->Present(NULL, NULL, NULL, NULL);
        }

    }

    // Hide the window to avoid flicker
    ShowWindow(_window, SW_HIDE);

    // Call our shutdown callback
    OnShutdown();

    // Shutdown Direct X
    _DirectXShutdown();

    // Cleanup and destroy the window
    DestroyWindow(_window);
    UnregisterClass(_GetModuleName(), GetModuleHandle(NULL));

    return true;
}

// Return the DirectX device, needed by other DirectX objects
LPDIRECT3DDEVICE9 Engine::GetDevice() {
    return _device;
}

// Return our width
int Engine::GetWidth() {
    return _WIDTH;
}

// Return our height
int Engine::GetHeight() {
    return _HEIGHT;
}

// Our own custom debug string
void Engine::Debug(const char* message, ...) {
#if _DEBUG
    if (message) {
        va_list args;
        va_start(args, message);
        int size = vsnprintf(NULL, 0, message, args);
        if (size > 0) {
            char* string = new char[size + 1];
            vsnprintf(string, size + 1, message, args);
            OutputDebugStringA(string);
            delete[] string;
        }
        va_end(args);
    }
#endif
}

// This is the Windows callback
LRESULT CALLBACK Engine::_WND_PROC(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    // If we do not have access to an instance of our engine, do nothing
    if (Engine::_ENGINE == NULL)
        return  DefWindowProc(hwnd, uMsg, wParam, lParam);

    // Handle system messages
    switch (uMsg) {
    case WM_LBUTTONDOWN:
        Engine::_ENGINE->OnMouseDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
        return 0;
    case WM_KEYDOWN:
    case WM_SYSKEYDOWN:
        if ((lParam & (1 << 30)) == 0)
            Engine::_ENGINE->OnKeyDown((int)wParam);
        return 0;
    case WM_CHAR:
        if ((int)wParam <= 127 && isprint((int)wParam) && (lParam & (1 << 30)) == 0)
            Engine::_ENGINE->OnASCIIDown((char)wParam);
        return 0;
    case WM_CLOSE:
        Engine::_ENGINE->_exit = true;
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

// Custom function for getting our exe name
WCHAR* Engine::_GetModuleName() {
    static WCHAR* TITLE = NULL;
    static WCHAR BUFFER[MAX_PATH];
    if (TITLE != NULL)
        return TITLE;

    // Remove the path
    GetModuleFileName(NULL, BUFFER, MAX_PATH);
    TITLE = wcsrchr(BUFFER, '\\');
    if (TITLE == NULL) {
        wcscpy(BUFFER, L"Application");
        TITLE = BUFFER;
        return TITLE;
    }
    TITLE++;

    // Remove the extension
    WCHAR* ext = wcsrchr(BUFFER, '.');
    if (ext)
        *ext = 0;

    return TITLE;
}

// Startup DirectX here
bool Engine::_DirectXStartup() {

    // Startup Direct X
    _directx = Direct3DCreate9(D3D_SDK_VERSION);
    if (_directx == NULL)
        return false;

    // Create a Direct X device
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.hDeviceWindow = _window;
    d3dpp.BackBufferWidth = _WIDTH;
    d3dpp.BackBufferHeight = _HEIGHT;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
    d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
    HRESULT result = _directx->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, _window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &_device);
    if (FAILED(result))
        result = _directx->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, _window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &_device);
    if (FAILED(result))
        return false;

    return true;
}

// Shutdown DirectX here
bool Engine::_DirectXShutdown() {
    if (_device) {
        _device->Release();
        _device = NULL;
    }
    if (_directx) {
        _directx->Release();
        _directx = NULL;
    }
    return true;
}

Engine.h

#ifndef _ENGINE_H_
#define _ENGINE_H_

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <d3d9.h>
#include <d3dx9.h>

class Engine {
public:
    // Return the current singleton of this Engine class
    static Engine* GetInstance();

    // Constructor and deconstructor
    Engine();
    virtual ~Engine();

    // Run the Engine class
    bool Run();

    // Return useful information about the class
    LPDIRECT3DDEVICE9 GetDevice();
    int GetWidth();
    int GetHeight();

    // Use for debug output
    static void Debug(const char* message, ...);

    // Virtual callbacks
    virtual void OnStartup() {}
    virtual void OnShutdown() {}
    virtual void OnMouseDown(int x, int y) {}
    virtual void OnKeyDown(int key) {}
    virtual void OnASCIIDown(char key) {}
    virtual void OnDraw() {}

private:
    static Engine* _ENGINE;
    static const int _WIDTH = 854;
    static const int _HEIGHT = 480;
    static const int _FPS = 60;
    bool _exit;
    HWND _window;
    LPDIRECT3D9 _directx;
    LPDIRECT3DDEVICE9 _device;

    static LRESULT CALLBACK _WND_PROC(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    WCHAR* _GetModuleName();
    bool _DirectXStartup();
    bool _DirectXShutdown();
};

#endif // _ENGINE_H_

Triangle2D.h

#ifndef _TRIANGLE_2D_H_
#define _TRIANGLE_2D_H_

#include "Engine.h"

class Triangle2D {
public:
    Triangle2D();
    bool New(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color);
    void Delete();
    void Draw();
    void Draw(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color);

private:
    struct CustomVertex {
        FLOAT x, y, z, w;
        DWORD color;
    };
    static const DWORD _FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE;
    LPDIRECT3DVERTEXBUFFER9 _vb;
};

#endif // _BOX_2D_H_

Triangle2D.cpp

#include "Triangle2D.h"

Triangle2D::Triangle2D()
: _vb(NULL)
{
}

bool Triangle2D::New(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color) {

    if (FAILED(Engine::GetInstance()->GetDevice()->CreateVertexBuffer(sizeof(CustomVertex)* 4, D3DUSAGE_WRITEONLY, _FVF, D3DPOOL_DEFAULT, &_vb, NULL)))
        return false;

    CustomVertex* vertices;
    _vb->Lock(0, 0, (void**)&vertices, 0);
    vertices[0].x = x;
    vertices[0].y = y;
    vertices[0].z = 0.0f;
    vertices[0].w = 1.0f;
    vertices[0].color = color;
    vertices[1].x = x + width;
    vertices[1].y = y;
    vertices[1].z = 0.0f;
    vertices[1].w = 1.0f;
    vertices[1].color = color;
    vertices[2].x = x;
    vertices[2].y = y + height;
    vertices[2].z = 0.0f;
    vertices[2].w = 1.0f;
    vertices[2].color = color;
    _vb->Unlock();

    return true;
}

void Triangle2D::Delete(){
    if (_vb) {
        _vb->Release();
        _vb = NULL;
    }
}

void Triangle2D::Draw() {
    Engine::GetInstance()->GetDevice()->BeginScene();
    Engine::GetInstance()->GetDevice()->SetFVF(_FVF);
    Engine::GetInstance()->GetDevice()->SetStreamSource(0, _vb, 0, sizeof(CustomVertex));
    Engine::GetInstance()->GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
    Engine::GetInstance()->GetDevice()->EndScene();
}

void Triangle2D::Draw(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color) {
    CustomVertex* vertices;
    _vb->Lock(0, 0, (void**)&vertices, 0);
    vertices[0].x = x;
    vertices[0].y = y;
    vertices[0].z = 0.0f;
    vertices[0].w = 1.0f;
    vertices[0].color = color;
    vertices[1].x = x + width;
    vertices[1].y = y;
    vertices[1].z = 0.0f;
    vertices[1].w = 1.0f;
    vertices[1].color = color;
    vertices[2].x = x;
    vertices[2].y = y + height;
    vertices[2].z = 0.0f;
    vertices[2].w = 1.0f;
    vertices[2].color = color;
    _vb->Unlock();

    Draw();
}

1 个答案:

答案 0 :(得分:0)

Direct3D不会画&#34;圈&#34;。它只能原生绘制三个基本图元:点,线和三角形。它如何绘制这些东西有很多选择,但它可以原生绘制。 OpenGL也是如此(有时也可以绘制四边形,但你总是可以绘制一个带有两个三角形的四边形)。

通常,绘制圆形和其他光滑物体最好通过&#34;矢量图形&#34;库。这些可以以正确的分辨率渲染高质量的平滑物体近似值,如圆圈。这就是传统的GDI库所做的,以及Direct2D可以做什么。您可以为圆形编码自己的近似值,但您可能不会像Direct2D那样做。这些库最终为Direct3D执行的实际绘制操作生成点,线和三角形。

出于这个原因,如果你正在做演讲&#39;图形,你应该看看使用Direct2D而不是Direct3D。大多数游戏实际上从未画过真正的圆他们使用Direct3D将2D精灵绘制为两个带纹理的三角形,使用Photoshop或Paint等艺术家在其上绘制的圆圈图像。

如果您坚持使用Direct3D,请参阅DirectX Tool Kit以获取可以绘制&#39;戒指的Direct3D 11 DebugDraw帮助器。 (即3D空间中的线段圆圈)。这应该可以让您了解如何完成此操作。此代码总是使用32个段来形成环,但是一个“矢量图形”。库将根据它将在屏幕上显示的像素数量来确定要分解的段数:

void XM_CALLCONV DX::DrawRing(PrimitiveBatch<VertexPositionColor>* batch,
    FXMVECTOR origin,
    FXMVECTOR majorAxis,
    FXMVECTOR minorAxis,
    GXMVECTOR color)
{
    static const size_t c_ringSegments = 32;

    VertexPositionColor verts[c_ringSegments + 1];

    FLOAT fAngleDelta = XM_2PI / float(c_ringSegments);
    // Instead of calling cos/sin for each segment we calculate
    // the sign of the angle delta and then incrementally calculate sin
    // and cosine from then on.
    XMVECTOR cosDelta = XMVectorReplicate(cosf(fAngleDelta));
    XMVECTOR sinDelta = XMVectorReplicate(sinf(fAngleDelta));
    XMVECTOR incrementalSin = XMVectorZero();
    static const XMVECTORF32 s_initialCos =
    {
        1.f, 1.f, 1.f, 1.f
    };
    XMVECTOR incrementalCos = s_initialCos.v;
    for (size_t i = 0; i < c_ringSegments; i++)
    {
        XMVECTOR pos = XMVectorMultiplyAdd(majorAxis, incrementalCos, origin);
        pos = XMVectorMultiplyAdd(minorAxis, incrementalSin, pos);
        XMStoreFloat3(&verts[i].position, pos);
        XMStoreFloat4(&verts[i].color, color);
        // Standard formula to rotate a vector.
        XMVECTOR newCos = incrementalCos * cosDelta - incrementalSin * sinDelta;
        XMVECTOR newSin = incrementalCos * sinDelta + incrementalSin * cosDelta;
        incrementalCos = newCos;
        incrementalSin = newSin;
    }
    verts[c_ringSegments] = verts[0];

    batch->Draw(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, verts, c_ringSegments + 1);
}
  

Direct3D 9是传统的,除非你专门针对Windows XP,否则你应该使用Direct3D 11或Direct2D,如果你真的在做2D演示图形。