2016-04-25 447 views
1

我很难搞清楚如何在directx中绘制一个圆。我可以绘制一个三角形,所以我想象一下,我可以通过在圆圈中旋转一个三角形来绘制一个三角形。但是,我绝对难住。我一直在网上冲浪几个小时,但没有运气。谁能帮我吗?这里是我的代码:在directx中绘制一个圆圈9

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(); 
} 

回答

0

的Direct3D不画 “圈”。它只能自然绘制三个基本图元:点,线和三角形。它如何绘制这些东西有很多选项,但这只是本地绘制的。 OpenGL也是如此(它有时也可以绘制“四边形”,但是您总是可以绘制具有两个三角形的四边形)。

通常通过“矢量图形”库完成绘图圆圈和其他平滑对象。这些可以以正确的分辨率呈现光滑物体(如圆圈)的高质量近似值。这就是传统的GDI库所做的,以及Direct2D可以做什么。你可以编写你自己的圆圈近似值,但你可能不会和Direct2D一样好。这些库最终为Direct3D执行的实际绘图操作生成点,线和三角形。

因为这个原因,如果你正在做'演示'图形,你应该看看使用Direct2D而不是Direct3D。大多数游戏实际上从不画真实的圈子他们使用一个由艺术家在Photoshop或Paint等东西上绘制的圆圈图像,将2D精灵绘制为带有Direct3D的两个带纹理的三角形。

如果您坚持使用Direct3D,请参阅适用于Direct3D的助手,该助手可以绘制“环”(即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,否则如果您确实在使用2D演示图形,则应该使用Direct3D 11或Direct2D。

+0

这是一个班级任务,教授希望我们使用directx9。那么我在这方面主要是SOL? – Godfried23

+0

然后教授要你找出如何去做。它和上面的代码基本相同,用于将顶点排列成一个圆。旧版DirectX SDK包含[XNAMath](https://blogs.msdn.microsoft.com/chuckw/2012/06/22/xna-math-version-2-05-smoothing-the-transition-to-directxmath/)您可以使用它,因为它具有与DirectXMath相同的功能。 –