One way to use 2D coord is to create an orthographic projection matrix and use it to transform the vertices. Research the XMMatrixOrthographicOffCenter[LH/RH] function (or a similar function in other math libraries).
Draw a rectangle with DX11
Aerodactyl55 said:
One way to use 2D coord is to create an orthographic projection matrix and use it to transform the vertices. Research the XMMatrixOrthographicOffCenter[LH/RH] function (or a similar function in other math libraries).
Thats not true, but a projection camera does add distortion to the image so you get the sense of depth in the view. If you screen align your objects in a projection camera the object will seem like they are 2D too, but you still have depth effects on them.
If you purely want the outline of the rectangle you should use a line list with 8 vertices which are the corners of your rectangle.
Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion
@NightCreature83 Thank you I have already a conversion function from pixel to NDC:
float PixelToNDC(int Pixel, int Max)
{
float F_Pixel = Pixel;
float F_Max = Max;
return (F_Pixel / F_Max * 2) - 1;
}
and seem work. Now my demo project is a good point, I like to known the best way to clear temporarily the drawing object and recreate it in the second time.
Here my updated project:
void ClearObjects()
{
OurVertices.clear();
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
// clear the back buffer
devcon->ClearRenderTargetView(backbuffer, color);
}
void DrawAll()
{
static const XMVECTORF32 s_MyValue = { 1.f, 2.f, 3.f, 4.f };
DrawRectangle(2, 2, 798, 598, s_MyValue);
DrawLine(20, 300, 600, 300, s_MyValue);
}
void DrawAll2()
{
static const XMVECTORF32 s_MyValue = { 1.f, 2.f, 3.f, 4.f };
DrawRectangle(2, 2, 398, 398, s_MyValue);
DrawLine(20, 300, 600, 300, s_MyValue);
}
// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = SCREEN_WIDTH; // set the back buffer width
scd.BufferDesc.Height = SCREEN_HEIGHT; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);
// get the address of the back buffer
ID3D11Texture2D* pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();
// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, NULL);
// Set the viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = SCREEN_WIDTH;
viewport.Height = SCREEN_HEIGHT;
devcon->RSSetViewports(1, &viewport);
InitPipeline();
DrawAll();
UpdateDeviceContext();
}
// this is the function used to render a single frame
void RenderFrame(void)
{
if (OurVertices.size() < 1)
return;
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
// clear the back buffer
devcon->ClearRenderTargetView(backbuffer, color);
// select which vertex buffer to display
UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);
// select which primtive type we are using
// draw the vertex buffer to the back buffer
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
devcon->Draw(OurVertices.size(), 0);
swapchain->Present(0, 0);
}
// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
// close and release all existing COM objects
pLayout->Release();
pVS->Release();
pPS->Release();
pVBuffer->Release();
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
}
float PixelToNDC(int Pixel, int Max)
{
float F_Pixel = Pixel;
float F_Max = Max;
return (F_Pixel / F_Max * 2) - 1;
}
void UpdateVertexVect(float x, float y, XMVECTORF32 col)
{
VERTEX CurVertex;
CurVertex.pos.x = x;
CurVertex.pos.y = y;
CurVertex.col = col;
OurVertices.push_back(CurVertex);
}
void UpdateDeviceContext()
{
rasterDesc.AntialiasedLineEnable = false;
rasterDesc.CullMode = D3D11_CULL_BACK;
rasterDesc.DepthBias = 0;
rasterDesc.DepthBiasClamp = 0.0f;
rasterDesc.DepthClipEnable = false;
rasterDesc.FillMode = D3D11_FILL_WIREFRAME;
rasterDesc.FrontCounterClockwise = true;
rasterDesc.MultisampleEnable = false;
rasterDesc.ScissorEnable = false;
rasterDesc.SlopeScaledDepthBias = 0.0f;
HRESULT result = dev->CreateRasterizerState(&rasterDesc, &m_rasterState);
if (FAILED(result)) return;
devcon->RSSetState(m_rasterState);
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = OurVertices.size() * sizeof(VERTEX);
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
HRESULT val = dev->CreateBuffer(&bd, NULL, &pVBuffer); // create the buffer
D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
memcpy(ms.pData, OurVertices.data(), OurVertices.size() * sizeof(VERTEX)); // copy the data
devcon->Unmap(pVBuffer, NULL);
}
void DrawRectangle(int x_Pix, int y_Pix, int width_Pix, int height_Pix, XMVECTORF32 col)
{
float x, y, width, height;
x = PixelToNDC(x_Pix, SCREEN_WIDTH);
y = PixelToNDC(y_Pix, SCREEN_HEIGHT);
width = PixelToNDC(width_Pix, SCREEN_WIDTH);
height = PixelToNDC(height_Pix, SCREEN_HEIGHT);
// Update Vector Coordinate compatible with "D3D11_PRIMITIVE_TOPOLOGY_LINELIST" topology
UpdateVertexVect(x, y, col);
UpdateVertexVect(x, height, col);
UpdateVertexVect(x, y, col);
UpdateVertexVect(width, y, col);
UpdateVertexVect(x, height, col);
UpdateVertexVect(width, height, col);
UpdateVertexVect(width, y, col);
UpdateVertexVect(width, height, col);
}
void DrawLine(int x1_Pix, int y1_Pix, int x2_Pix, int y2_Pix, XMVECTORF32 col)
{
float x1, y1, x2, y2;
x1 = PixelToNDC(x1_Pix, SCREEN_WIDTH);
y1 = PixelToNDC(y1_Pix, SCREEN_HEIGHT);
x2 = PixelToNDC(x2_Pix, SCREEN_WIDTH);
y2 = PixelToNDC(y2_Pix, SCREEN_HEIGHT);
// Update Vector Coordinate compatible with "D3D11_PRIMITIVE_TOPOLOGY_LINELIST" topology
UpdateVertexVect(x1,- y1, col);
UpdateVertexVect(x2,- y2, col);
}
// this function loads and prepares the shaders
void InitPipeline()
{
ID3DBlob *pErrors;
// load and compile the two shaders
ID3D10Blob* VS, * PS;
D3DCompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, &VS, &pErrors); // , 0, 0);
D3DCompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, &PS, &pErrors); // , 0, 0);
// encapsulate both shaders into shader objects
dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);
// set the shader objects
devcon->VSSetShader(pVS, 0, 0);
devcon->PSSetShader(pPS, 0, 0);
// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
devcon->IASetInputLayout(pLayout);
}
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
RECT wr = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
hWnd = CreateWindowEx(WS_EX_LAYERED, L"WindowClass", L"Our First Direct3D Program", WS_POPUP, 300, 300, wr.right - wr.left, wr.bottom - wr.top, NULL, NULL, hInstance, NULL);
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), RGB(255, 255, 255), LWA_COLORKEY);
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
InitD3D(hWnd);
// enter the main loop:
MSG msg;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
}
if (GetKeyState('A') & 0x8000/*Check if high-order bit is set (1 << 15)*/)
{
ClearObjects();
}
if (GetKeyState('B') & 0x8000/*Check if high-order bit is set (1 << 15)*/)
{
DrawAll2();
}
RenderFrame();
}
// clean up DirectX and COM
CleanD3D();
return msg.wParam;
}
I have created a function “ClearObjects” that in theory must delete all drawing but don't do nothing probrably I need to add some code,
Theorically I can call: “CleanD3D” but in this case I need to restart the entere project I like only clear the rectangles and lines and call for example “DrawAll” to redraw it again.
What you suggest ?
NightCreature83 said:
Aerodactyl55 said:
One way to use 2D coord is to create an orthographic projection matrix and use it to transform the vertices. Research the XMMatrixOrthographicOffCenter[LH/RH] function (or a similar function in other math libraries).
Thats not true, but a projection camera does add distortion to the image so you get the sense of depth in the view. If you screen align your objects in a projection camera the object will seem like they are 2D too, but you still have depth effects on them.
If you purely want the outline of the rectangle you should use a line list with 8 vertices which are the corners of your rectangle.
I don't understand what you mean here, and I am not sure if what you are saying is related to what I posted. Using a (properly setup) orthographic projection matrix allows you to specify the coords of the vertices in pixels just as the OP requested, or you can convert to NDC directly like OP did (which is a method that I already knew but did not suggest because I thought is was easier to just use an orthographic projection matrix).