在 directx 9 中画一个圆
Drawing a circle in directx 9
我很难弄清楚如何在directx中画一个圆。我能够画一个三角形,所以我想象我可以通过将三角形旋转成一个圆来画一个三角形。但是,我完全被难住了。我已经在网上搜索了几个小时,但没有运气。谁能帮我?这是我的代码:
主.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 %dn", x, y);
}
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MyApp app;
app.Run();
return 0;
}
引擎.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;
}
发动机.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_
三角形2D.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_
三角形2D.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();
}
Direct3D 不绘制"圆圈"。它本身只绘制三个基本基元:点、线和三角形。对于它如何绘制这些东西,有很多选项,但这就是它可以原生绘制的全部内容。OpenGL也是如此(它有时也可以画"四边形",但你总是可以画一个带有两个三角形的四边形)。
通常,绘制圆圈和其他平滑对象最好通过"矢量图形"库来完成。这些可以在正确的分辨率下渲染光滑对象(如圆)的高质量近似值。这是旧版 GDI 库的功能,也是 Direct2D 可以执行的操作。你可以为圆编写自己的近似值,但效果可能不如 Direct2D。这些库最终会为 Direct3D 执行的实际绘图操作生成点、线和三角形。
因此,如果你正在执行"演示"图形,则应考虑使用 Direct2D 而不是 Direct3D。大多数游戏实际上从未画过真正的圆圈。他们使用 Direct3D 将 2D 精灵绘制为两个带纹理的三角形,使用艺术家在 Photoshop 或 Paint 等东西中绘制的圆圈图像。
如果你坚持使用 Direct3D,请参阅 Direct3D 11 DebugDraw 帮助程序的 DirectX 工具包,该工具包可以绘制"环"(即 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);
}
Direct3D9是旧版的,除非你专门针对Windows XP,否则如果你真的在做2D演示图形,你应该使用Direct3D 11或Direct2D。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 运行同一解决方案的另一个项目的项目
- 挂起和取消挂起一个文件DLL
- 用C++中的一个变量定义一个常量
- 函数向量_指针有不同的原型,我可以构建一个吗
- 在c++中用vector填充一个简单的动态数组
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 预处理器:插入结构名称中的前一个行号
- 我在c++代码中生成了一个运行时#3异常
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 创建一个绿色三角形C Directx
- 我有非常量ID3D11ShaderResourceView*,而DirectX函数需要常量一个
- 在 directx 9 中画一个圆
- DirectX 11制作一个正方形
- DirectX SDK与Windows SDK:使用哪一个
- 在DirectX中围绕质心旋转一个等边三角形
- DirectX屏幕截图:为什么GetBackBuffer总是给我一个黑色的图像
- 有一个好的DirectX (3D) DirectWrite教程的地方