I'm learning DirectX 11 and I'm trying to render a simple cube, unfortunately my code doesn't work, it simply doesn't render nothing... no errors, no warnings... The only thing displayed is the window with the specified clear color. I'm also very sure that the code is executed entirely.
This is the header of my specialized class:
#pragma once
#include "DirectxApp.h"
#include <DirectXMath.h>
#include "DirectxUtils.h"
struct Vertex
{
DirectX::XMFLOAT3 Position;
DirectX::XMFLOAT4 Color;
};
struct TransformationMatrix
{
DirectX::XMMATRIX worldViewProjMatrix;
};
class MyDirectxApp : public DirectxApp
{
private:
ID3D11Buffer* m_vertexBuffer;
ID3D11Buffer* m_indexBuffer;
ID3D11Buffer* m_worldViewProjBuffer;
ID3D11RasterizerState* m_rasterizerState;
ID3D11InputLayout* m_inputLayout;
ID3D11VertexShader* m_vertexShader;
ID3D11PixelShader* m_pixelShader;
DirectX::XMMATRIX m_worldMatrix;
DirectX::XMMATRIX m_viewMatrix;
DirectX::XMMATRIX m_projMatrix;
TransformationMatrix m_transformationMatrix;
float m_theta;
float m_phi;
float m_radius;
public:
MyDirectxApp(HINSTANCE hInstance,
int width,
int height,
LPWSTR windowName = L"",
bool enable4xMsaa = true,
int xCoord = CW_USEDEFAULT,
int yCoord = CW_USEDEFAULT
);
virtual bool Init();
virtual void OnFrame();
virtual ~MyDirectxApp(void);
};
And this is the cpp (the init method of the super class initializes the window and the basic components of DirectX, see later):
#include "MyDirectxApp.h"
using namespace DirectX;
MyDirectxApp::MyDirectxApp(HINSTANCE hInstance,
int width,
int height,
LPWSTR windowName,
bool enable4xMsaa,
int xCoord,
int yCoord
) : DirectxApp(hInstance, width, height, windowName, enable4xMsaa, xCoord, yCoord)
{
m_vertexBuffer = 0;
m_indexBuffer = 0;
m_inputLayout = 0;
m_rasterizerState = 0;
m_vertexShader = 0;
m_pixelShader = 0;
m_worldViewProjBuffer = 0;
XMMATRIX matrixIdentity = XMMatrixIdentity();
m_worldMatrix = matrixIdentity;
m_viewMatrix = matrixIdentity;
m_projMatrix = matrixIdentity;
m_transformationMatrix.worldViewProjMatrix = matrixIdentity;
m_theta = 1.5f * DirectX::XM_PI;
m_phi = 0.25f* DirectX::XM_PI;
m_radius = 5.0f;
}
bool MyDirectxApp::Init()
{
if(!DirectxApp::Init())
{
return false;
}
HRESULT hResult;
//////////////////////////////////////
// CreateVertexBuffer
//////////////////////////////////////
Vertex cubeVertexArray[] = {
// Position Color
{XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f)}, //white
{XMFLOAT3(-1.0f, +1.0f, -1.0f), XMFLOAT4(0.0f, 0.0f, 0.0f, 1.0f)}, //black
{XMFLOAT3(+1.0f, +1.0f, -1.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f)}, //red
{XMFLOAT3(+1.0f, -1.0f, -1.0f), XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f)}, //green
{XMFLOAT3(-1.0f, -1.0f, +1.0f), XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f)}, //blue
{XMFLOAT3(-1.0f, +1.0f, +1.0f), XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f)}, //yellow
{XMFLOAT3(+1.0f, +1.0f, +1.0f), XMFLOAT4(0.0f, 1.0f, 1.0f, 1.0f)}, //cyan
{XMFLOAT3(+1.0f, -1.0f, +1.0f), XMFLOAT4(1.0f, 0.0f, 1.0f, 1.0f)} //magenta
};
hResult = DirectxUtils::CreateVertexBuffer(m_d3dDevice, &cubeVertexArray, sizeof(cubeVertexArray), &m_vertexBuffer);
if (FAILED(hResult))
{
MessageBox(0, L"CreateVertexBuffer FAILED", 0, 0);
return false;
}
//////////////////////////////////////
// CreateIndexBuffer
//////////////////////////////////////
UINT indices[] = {
0, 1, 2, // front face
0, 2, 3,
4, 6, 5, // back face
4, 7, 6,
4, 5, 1, // left face
4, 1, 0,
3, 2, 6, // right face
3, 6, 7,
1, 5, 6, // top face
1, 6, 2,
4, 0, 3, // bottom face
4, 3, 7
};
hResult = DirectxUtils::CreateIndexBuffer(m_d3dDevice, &indices, sizeof(indices), &m_indexBuffer);
if (FAILED(hResult))
{
MessageBox(0, L"CreateIndexBuffer FAILED", 0, 0);
return false;
}
//////////////////////////////////////
// CreateVertexShader
//////////////////////////////////////
D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[] = {
{"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},
};
hResult = DirectxUtils::CreateVertexShader(m_d3dDevice, L"VertexShader.hlsl", "main", inputLayoutDesc, 2, &m_vertexShader, &m_inputLayout);
if (FAILED(hResult))
{
MessageBox(0, L"CreateVertexShader FAILED", 0, 0);
return false;
}
//////////////////////////////////////
// CreatePixelShader
//////////////////////////////////////
hResult = DirectxUtils::CreatePixelShader(m_d3dDevice, L"PixelShader.hlsl", "main", &m_pixelShader);
if (FAILED(hResult))
{
MessageBox(0, L"CreatePixelShader FAILED", 0, 0);
return false;
}
//////////////////////////////////////
// create world\view\proj matrix
//////////////////////////////////////
XMVECTOR cameraPos = XMVectorSet(0.0f, 3.0f, -5.0f, 1.0f);
XMVECTOR cameraTarget = XMVectorZero();
XMVECTOR cameraUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
m_worldMatrix = XMMatrixIdentity();
m_projMatrix = XMMatrixPerspectiveFovLH(XMConvertToRadians(45.0f), AspectRatio(), 0.1f, 100.0f);
m_viewMatrix = XMMatrixLookAtLH(cameraPos, cameraTarget, cameraUp);
hResult = DirectxUtils::CreateConstantBuffer(m_d3dDevice, sizeof(TransformationMatrix), &m_worldViewProjBuffer);
if (FAILED(hResult))
{
MessageBox(0, L"CreateConstantBuffer FAILED", 0, 0);
return false;
}
//////////////////////////////////////
// CreateRasterizerState
//////////////////////////////////////
D3D11_RASTERIZER_DESC rasterizerDesc;
rasterizerDesc.FillMode = D3D11_FILL_SOLID;
rasterizerDesc.CullMode = D3D11_CULL_BACK;
rasterizerDesc.FrontCounterClockwise = false;
rasterizerDesc.DepthClipEnable = true;
hResult = m_d3dDevice->CreateRasterizerState(&rasterizerDesc, &m_rasterizerState);
if (FAILED(hResult))
{
MessageBox(0, L"CreateRasterizerState FAILED", 0, 0);
return false;
}
return true;
}
void MyDirectxApp::OnFrame()
{
///////////////////////////////////
// update worldViewProj matrix
///////////////////////////////////
XMVECTOR cameraPos = XMVectorSet(0.0f, 3.0f, -5.0f, 1.0f);
XMVECTOR cameraTarget = XMVectorZero();
XMVECTOR cameraUp = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
m_viewMatrix = XMMatrixLookAtLH(cameraPos, cameraTarget, cameraUp);
m_transformationMatrix.worldViewProjMatrix = m_worldMatrix * m_viewMatrix * m_projMatrix;
///////////////////////////////////
// drawing
///////////////////////////////////
static const FLOAT clearColor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
m_d3dDeviceContext->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilBufferView);
m_d3dDeviceContext->ClearRenderTargetView(m_renderTargetView, clearColor);
m_d3dDeviceContext->ClearDepthStencilView(m_depthStencilBufferView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
m_d3dDeviceContext->IASetInputLayout(m_inputLayout);
m_d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
UINT stride = sizeof(Vertex);
UINT offset = 0;
m_d3dDeviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);
m_d3dDeviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);
m_d3dDeviceContext->VSSetShader(m_vertexShader, nullptr, 0);
m_d3dDeviceContext->PSSetShader(m_pixelShader, nullptr, 0);
m_d3dDeviceContext->RSSetState(m_rasterizerState);
m_d3dDeviceContext->UpdateSubresource(m_worldViewProjBuffer, 0, nullptr, &m_transformationMatrix, 0, 0);
m_d3dDeviceContext->VSSetConstantBuffers(0, 1, &m_worldViewProjBuffer);
m_d3dDeviceContext->DrawIndexed(36, 0, 0);
m_swapChain->Present(0, 0);
}
MyDirectxApp::~MyDirectxApp(void)
{
m_vertexBuffer->Release();
m_indexBuffer->Release();
m_inputLayout->Release();
m_rasterizerState->Release();
m_vertexShader->Release();
m_pixelShader->Release();
m_worldViewProjBuffer->Release();
}
The VertexShader is really simple, it only does the world-view-projection transformation:
cbuffer cbPerObject
{
float4x4 worldViewProjection;
};
//input data structure
struct VertexInput
{
float3 iPosition : POSITION;
float4 iColor : COLOR;
};
//output data
struct VertexOutput
{
float4 oPosition : SV_POSITION; //system-value-position is a special semantic name
float4 oColor : COLOR;
};
VertexOutput main(VertexInput vertexInput)
{
VertexOutput vertexOutput;
//transform world-view-projection
vertexOutput.oPosition = mul(float4(vertexInput.iPosition, 1.0f), worldViewProjection);
vertexOutput.oColor = vertexInput.iColor;
return vertexOutput;
}
The PixelShader is even simpler:
//input data structure
//must match the vertexShader output
struct PixelShaderInput
{
float4 iPosition : SV_POSITION;
float4 iColor : COLOR;
};
float4 main(PixelShaderInput pixelShaderInput) : SV_TARGET //system-value-target means the output must match the renderTarget format
{
return pixelShaderInput.iColor;
}
As mentioned above the basic components of Directx are created by the super class (DirectxApp), here's the code:
bool DirectxApp::InitDirectx()
{
//////////////////////////////////////
// device creation
//////////////////////////////////////
UINT creationDeviceFlags = 0;
#if defined(DEBUG)
creationDeviceFlags = D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_FEATURE_LEVEL featureLevel;
HRESULT hResult = D3D11CreateDevice(0, //display adapter
D3D_DRIVER_TYPE_HARDWARE, //drier type
0, //software driver
creationDeviceFlags, //device flag
0, //array of feature levels (NULL means choose the greatest)
0, //number of feature levels
D3D11_SDK_VERSION, //sdk version
&m_d3dDevice,
&featureLevel,
&m_d3dDeviceContext);
if (FAILED(hResult))
{
MessageBox(0, L"D3D11CreateDevice FAILED", 0, 0);
return false;
}
if (featureLevel != D3D_FEATURE_LEVEL_11_0)
{
MessageBox(0, L"D3D_FEATURE_LEVEL_11_0 not supported", 0, 0);
return false;
}
//////////////////////////////////////
// check 4xMSAA
//////////////////////////////////////
UINT m4xMsaaQuality;
m_d3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality);
assert(m4xMsaaQuality > 0); //m4xMsaaQuality is always > 0
//////////////////////////////////////
// swap chain creation
//////////////////////////////////////
DXGI_SWAP_CHAIN_DESC swapChainDesc;
swapChainDesc.BufferDesc.Width = m_windowWidth;
swapChainDesc.BufferDesc.Height = m_windowHeight;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
if (m_enable4xMsaa)
{
swapChainDesc.SampleDesc.Count = 4;
swapChainDesc.SampleDesc.Quality = m4xMsaaQuality -1;
}
else
{
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
}
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1; //means double buffering
swapChainDesc.OutputWindow = m_mainWindow;
swapChainDesc.Windowed = true;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = 0;
IDXGIDevice* dxgiDevice = 0;
m_d3dDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
IDXGIAdapter* dxgiAdapter = 0;
dxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&dxgiAdapter));
IDXGIFactory* dxgiFactory = 0;
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgiFactory));
HRESULT hResultSwapChain = dxgiFactory->CreateSwapChain(m_d3dDevice, &swapChainDesc, &m_swapChain);
dxgiDevice->Release();
dxgiAdapter->Release();
dxgiFactory->Release();
if (FAILED(hResultSwapChain))
{
MessageBox(0, L"CreateSwapChain FAILED", 0, 0);
return false;
}
//////////////////////////////////////
// render target creation
//////////////////////////////////////
ID3D11Texture2D* backBufferTexture2D = 0;
m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBufferTexture2D));
HRESULT hResultRenderTarget = m_d3dDevice->CreateRenderTargetView(backBufferTexture2D, 0, &m_renderTargetView);
backBufferTexture2D->Release();
if (FAILED(hResultRenderTarget))
{
MessageBox(0, L"CreateRenderTargetView FAILED", 0, 0);
return false;
}
//////////////////////////////////////
// depth-stencil buffer creation
//////////////////////////////////////
D3D11_TEXTURE2D_DESC depthStencilBufferTexture2D;
depthStencilBufferTexture2D.Width = m_windowWidth;
depthStencilBufferTexture2D.Height = m_windowHeight;
depthStencilBufferTexture2D.MipLevels = 1;
depthStencilBufferTexture2D.ArraySize = 1;
depthStencilBufferTexture2D.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
if (m_enable4xMsaa)
{
depthStencilBufferTexture2D.SampleDesc.Count = 4;
depthStencilBufferTexture2D.SampleDesc.Quality = m4xMsaaQuality -1;
}
else
{
depthStencilBufferTexture2D.SampleDesc.Count = 1;
depthStencilBufferTexture2D.SampleDesc.Quality = 0;
}
depthStencilBufferTexture2D.Usage = D3D11_USAGE_DEFAULT;
depthStencilBufferTexture2D.BindFlags = D3D11_BIND_DEPTH_STENCIL;
depthStencilBufferTexture2D.CPUAccessFlags = 0;
depthStencilBufferTexture2D.MiscFlags = 0;
HRESULT hResultDepthStencil = m_d3dDevice->CreateTexture2D(&depthStencilBufferTexture2D, 0, &m_depthStencilBufferTexture2D);
if (FAILED(hResultDepthStencil))
{
MessageBox(0, L"CreateTexture2D depthStencil FAILED", 0, 0);
return false;
}
HRESULT hResultDepthStencilView = m_d3dDevice->CreateDepthStencilView(m_depthStencilBufferTexture2D, 0, &m_depthStencilBufferView);
if (FAILED(hResultDepthStencilView))
{
MessageBox(0, L"CreateDepthStencilView FAILED", 0, 0);
return false;
}
//////////////////////////////////////
// viewport creation
//////////////////////////////////////
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = float(m_windowWidth);
viewport.Height = float(m_windowHeight);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
m_d3dDeviceContext->RSSetViewports(1, &viewport);
return true;
}
I appreciate any hint to solve this problem!
Thanks in advance
EDIT
To the rendering pipeline arrives only one triangle, the VertexShader is executed but not the PixelShader, and then dies...
It may not be the only problem, but you should transpose the matrices before sending them to the shader. You can do that by calling XMMatrixTranspose( matrix ).
(I see now that someone already mentioned it)
Related
I wanted to draw a 3D cube, but it doesn't display correctly. That is, the Z buffer (depth buffer) does not work.
The initialization of the depth buffer occurs in the InitDepthBuffer method, which I copied from the manual from Microsoft. The InitDepthBuffer method is called in the InitD3D method below.
Why "cube" is not displayed correctly and how to fix the program?
My Game.cpp
// include the basic windows header files and the Direct3D header files
#include <windows.h>
#include <windowsx.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dx10.h>
#include <xnamath.h>
// include the Direct3D Library file
#pragma comment (lib, "d3d11.lib")
#pragma comment (lib, "d3dx11.lib")
#pragma comment (lib, "d3dx10.lib")
// define the screen resolution
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
// global declarations
IDXGISwapChain* swapchain; // the pointer to the swap chain interface
ID3D11Device* dev; // the pointer to our Direct3D device interface
ID3D11DeviceContext* devcon; // the pointer to our Direct3D device context
ID3D11RenderTargetView* backbuffer; // the pointer to our back buffer
ID3D11InputLayout* pLayout; // the pointer to the input layout
ID3D11VertexShader* pVS; // the pointer to the vertex shader
ID3D11PixelShader* pPS; // the pointer to the pixel shader
ID3D11Buffer* pVBuffer; // the pointer to the vertex buffer
ID3D11Buffer* pIBuffer;
ID3D11Buffer* wvpConstBuffer;
ID3D11ShaderResourceView* pTexture; // the texture
ID3D11SamplerState* pSamplerState;
ID3D11RasterizerState* pRasterState;
ID3D11Texture2D* pDepthStencil = NULL;
ID3D11DepthStencilState* pDSState;
ID3D11DepthStencilView* pDSV;
// a struct to define a single vertex
struct VERTEX { FLOAT X, Y, Z, texX, texY; };
struct ConstantBuffer
{
XMMATRIX mWorld;
XMMATRIX mView;
XMMATRIX mProjection;
};
XMMATRIX g_World;
XMMATRIX g_View;
XMMATRIX g_Projection;
// function prototypes
void InitD3D(HWND hWnd); // sets up and initializes Direct3D
void RenderFrame(void); // renders a single frame
void CleanD3D(void); // closes Direct3D and releases memory
void InitGraphics(void); // creates the shape to render
void InitPipeline(void); // loads and prepares the shaders
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// 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(NULL,
L"WindowClass",
L"My Game",
WS_OVERLAPPEDWINDOW,
300,
300,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
hInstance,
NULL);
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;
}
RenderFrame();
}
// clean up DirectX and COM
CleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void InitDepthBuffer()
{
D3D11_TEXTURE2D_DESC descDepth;
descDepth.Width = SCREEN_WIDTH;
descDepth.Height = SCREEN_HEIGHT;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
dev->CreateTexture2D(&descDepth, NULL, &pDepthStencil);
D3D11_DEPTH_STENCIL_DESC dsDesc;
// Depth test parameters
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
// Stencil test parameters
dsDesc.StencilEnable = true;
dsDesc.StencilReadMask = 0xFF;
dsDesc.StencilWriteMask = 0xFF;
// Stencil operations if pixel is front-facing
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Stencil operations if pixel is back-facing
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
dev->CreateDepthStencilState(&dsDesc, &pDSState);
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
descDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
dev->CreateDepthStencilView(pDepthStencil, // Depth stencil texture
&descDSV, // Depth stencil desc
&pDSV); // [out] Depth stencil view
}
// 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();
InitDepthBuffer();
// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, pDSV);
devcon->OMSetDepthStencilState(pDSState, 1);
// 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;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
devcon->RSSetViewports(1, &viewport);
InitPipeline();
InitGraphics();
}
// this is the function used to render a single frame
void RenderFrame(void)
{
// update WVP matrices
ConstantBuffer cb;
cb.mWorld = XMMatrixTranspose(g_World);
cb.mView = XMMatrixTranspose(g_View);
cb.mProjection = XMMatrixTranspose(g_Projection);
devcon->UpdateSubresource(wvpConstBuffer, 0, NULL, &cb, 0, 0);
// clear the back buffer to a deep blue and the depth buffer
devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f));
devcon->ClearDepthStencilView(pDSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
// select which vertex buffer to display
UINT stride = sizeof(VERTEX);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);
devcon->IASetIndexBuffer(pIBuffer, DXGI_FORMAT_R32_UINT, 0);
devcon->VSSetConstantBuffers(0, 1, &wvpConstBuffer);
// select which primtive type we are using
devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// draw the vertex buffer to the back buffer
devcon->DrawIndexed(24, 0, 0);
// switch the back buffer and the front buffer
swapchain->Present(0, 0);
g_World *= XMMatrixRotationY(XM_PI / 12);
Sleep(100);
}
// 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();
}
void InitTextures()
{
D3DX11CreateShaderResourceViewFromFile(dev, L"texture.png", NULL, NULL, &pTexture, NULL);
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&sampDesc, sizeof(D3D11_SAMPLER_DESC));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
dev->CreateSamplerState(&sampDesc, &pSamplerState);
}
// this is the function that creates the shape to render
void InitGraphics()
{
// create a triangle using the VERTEX struct
VERTEX OurVertices[] =
{ // CUBE
{-0.5f, 0.5f, 0.5f, 0.0f, 0.0f}, // Front
{0.5f, 0.5f, 0.5f, 1.0f, 0.0f},
{0.5f, -0.5f, 0.5f, 1.0f, 1.0f},
{-0.5f, -0.5f, 0.5f, 0.0f, 1.0f},
{-0.5f, 0.5f, -0.5f, 1.0f, 0.0f}, // Back
{0.5f, 0.5f, -0.5f, 0.0f, 0.0f},
{0.5f, -0.5f, -0.5f, 0.0f, 1.0f},
{-0.5f, -0.5f, -0.5f, 1.0f, 1.0f},
};
// create the vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC; // write access access by CPU and GPU
bd.ByteWidth = sizeof(OurVertices); // size is the VERTEX struct * 3
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // use as a vertex buffer
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // allow CPU to write in buffer
dev->CreateBuffer(&bd, NULL, &pVBuffer); // create the buffer
// copy the vertices into the buffer
D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
memcpy(ms.pData, OurVertices, sizeof(OurVertices)); // copy the data
devcon->Unmap(pVBuffer, NULL); // unmap the buffer
unsigned int indices[] =
{
0, 1, 2, // front
0, 2, 3,
4, 0, 3, // left
4, 3, 7,
//4, 5, 6, // back
//4, 6, 7,
6, 5, 1, // right
6, 1, 2,
};
// indices
D3D11_BUFFER_DESC bdIndices;
bdIndices.Usage = D3D11_USAGE_DEFAULT;
bdIndices.ByteWidth = sizeof(indices);
bdIndices.BindFlags = D3D11_BIND_INDEX_BUFFER;
bdIndices.CPUAccessFlags = 0;
bdIndices.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
InitData.pSysMem = indices;
InitData.SysMemPitch = 0;
InitData.SysMemSlicePitch = 0;
dev->CreateBuffer(&bdIndices, &InitData, &pIBuffer);
D3D11_BUFFER_DESC bdWVP;
ZeroMemory(&bdWVP, sizeof(D3D11_BUFFER_DESC));
bdWVP.Usage = D3D11_USAGE_DEFAULT;
bdWVP.ByteWidth = sizeof(ConstantBuffer);
bdWVP.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bdWVP.CPUAccessFlags = 0;
dev->CreateBuffer(&bdWVP, NULL, &wvpConstBuffer);
g_World = XMMatrixIdentity();
XMVECTOR Eye = XMVectorSet(0.0f, 1.0f, -3.0f, 0.0f);
XMVECTOR At = XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f);
XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);
g_View = XMMatrixLookAtLH(Eye, At, Up);
g_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, 0.01f, 100.0f);
}
void InitRasterizer()
{
D3D11_RASTERIZER_DESC raster_desc;
raster_desc.FillMode = D3D11_FILL_SOLID;
raster_desc.CullMode = D3D11_CULL_NONE;
raster_desc.FrontCounterClockwise = false;
raster_desc.DepthBias = 0;
raster_desc.DepthBiasClamp = 0.0f;
raster_desc.SlopeScaledDepthBias = 0.0f;
raster_desc.DepthClipEnable = true;
raster_desc.ScissorEnable = false;
raster_desc.MultisampleEnable = false;
raster_desc.AntialiasedLineEnable = false;
dev->CreateRasterizerState(&raster_desc, &pRasterState);
}
// this function loads and prepares the shaders
void InitPipeline()
{
InitRasterizer();
InitTextures();
// load and compile the two shaders
ID3D10Blob* VS, * PS;
D3DX11CompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
D3DX11CompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 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);
// set the texture
devcon->PSSetShaderResources(0, 1, &pTexture);
devcon->PSSetSamplers(0, 1, &pSamplerState);
// off cull mode
devcon->RSSetState(pRasterState);
// create the input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
devcon->IASetInputLayout(pLayout);
}
shaders.shader
cbuffer ConstantBuffer : register(b0)
{
matrix World;
matrix View;
matrix Projection;
}
Texture2D ObjTexture;
SamplerState ObjSamplerState;
struct VS_OUTPUT
{
float4 Pos : SV_POSITION;
float2 TexCoord : TEXCOORD;
};
VS_OUTPUT VShader(float4 Pos : POSITION, float4 inTexCoord : TEXCOORD)
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.Pos = mul(Pos, World);
output.Pos = mul(output.Pos, View);
output.Pos = mul(output.Pos, Projection);
output.TexCoord = inTexCoord;
return output;
}
float4 PShader(VS_OUTPUT input) : SV_Target
{
return ObjTexture.Sample(ObjSamplerState, input.TexCoord);
}
the "cube"
I've looked all over but couldn't solve the problem.
With a fresh eye today i've noticed that besides things i've mentioned earlier render target view and depth stencil view are using different multisampling settings: render target use 4 samples while depth stencil only 1. In order for them to work together their dimensions and multisampling settings must be exactly the same.
I'm setting up d3d11 to learn the basics, but I'm having some trouble. I have no errors and everything compiles fine, but ending up with a white window. Am I missing something here? there should be a colored quad in the window. Sorry for any mistakes in asking the question. This is my first post here.
CPP FILE:
#include <Windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <iostream>
struct Vec3
{
float x, y, z;
};
struct Vertex
{
Vec3 position;
Vec3 color;
};
bool running = true;
HWND hwndApp;
LRESULT CALLBACK AppWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_DESTROY)
{
running = false;
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int main()
{
WNDCLASSEX appWndClass = { };
appWndClass.lpfnWndProc = AppWndProc;
appWndClass.cbSize = sizeof(WNDCLASSEX);
appWndClass.cbClsExtra = NULL;
appWndClass.cbWndExtra = NULL;
appWndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
appWndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
appWndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
appWndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
appWndClass.style = NULL;
appWndClass.hInstance = GetModuleHandle(NULL);
appWndClass.lpszClassName = "AppWndClass";
appWndClass.lpszMenuName = "";
RegisterClassEx(&appWndClass);
hwndApp = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
appWndClass.lpszClassName,
"AppWndClass",
WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
ShowWindow(hwndApp, SW_SHOW);
UpdateWindow(hwndApp);
ID3D11Device* d3dDevice = nullptr;
ID3D11DeviceContext* d3dDeviceContext = nullptr;
IDXGIDevice* dxgiDevice = nullptr;
IDXGIAdapter* dxgiAdapter = nullptr;
IDXGIFactory* dxgiFactory = nullptr;
IDXGISwapChain* dxgiSwapChain = nullptr;
ID3D11RenderTargetView* renderTargetView = nullptr;
D3D_FEATURE_LEVEL featureLevel;
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0
};
D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
0,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&d3dDevice,
&featureLevel,
&d3dDeviceContext
);
if (d3dDevice == nullptr) return -1;
if (d3dDeviceContext == nullptr) return -1;
d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)& dxgiDevice);
dxgiDevice->GetAdapter(&dxgiAdapter);
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)& dxgiFactory);
RECT rc;
GetClientRect(hwndApp, &rc);
DXGI_SWAP_CHAIN_DESC swapChainDescription;
ZeroMemory(&swapChainDescription, sizeof(swapChainDescription));
swapChainDescription.BufferCount = 1;
swapChainDescription.BufferDesc.Width = rc.right - rc.left;
swapChainDescription.BufferDesc.Height = rc.bottom - rc.top;
swapChainDescription.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDescription.BufferDesc.RefreshRate.Numerator = 60;
swapChainDescription.BufferDesc.RefreshRate.Denominator = 1;
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.OutputWindow = hwndApp;
swapChainDescription.SampleDesc.Count = 1;
swapChainDescription.SampleDesc.Quality = 0;
swapChainDescription.Windowed = TRUE;
dxgiFactory->CreateSwapChain(d3dDevice, &swapChainDescription, &dxgiSwapChain);
ID3D11Texture2D* buffer = nullptr;
dxgiSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)& buffer);
if (buffer == nullptr) return -1;
d3dDevice->CreateRenderTargetView(buffer, nullptr, &renderTargetView);
buffer->Release();
if (renderTargetView == nullptr) return -1;
Vertex vertices[] =
{
{ -0.5f, -0.5f, 0.0f, 0, 0, 0 },
{ -0.5f, 0.5f, 0.0f, 1, 1, 0 },
{ 0.5f, -0.5f, 0.0f, 0, 0, 1 },
{ 0.5f, 0.5f, 0.0f, 1, 1, 1 }
};
UINT sizeVertices = ARRAYSIZE(vertices);
D3D11_INPUT_ELEMENT_DESC inputElementDescription[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA , 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
UINT sizeInputElementDescription = ARRAYSIZE(inputElementDescription);
D3D11_BUFFER_DESC bufferDescription = {};
bufferDescription.Usage = D3D11_USAGE_DEFAULT;
bufferDescription.ByteWidth = sizeof(Vertex) * sizeVertices;
bufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDescription.CPUAccessFlags = 0;
bufferDescription.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA initialData = {};
initialData.pSysMem = vertices;
ID3D11Buffer* vertexBuffer;
d3dDevice->CreateBuffer(&bufferDescription, &initialData, &vertexBuffer);
void* shaderByteCode = nullptr;
size_t byteCodeLength = 0;
ID3DBlob* blobCode = nullptr;
ID3DBlob* blobErrorMsgs = nullptr;
//D3DCompileFromFile( L"VertexShader.hlsl", nullptr, nullptr, "vsmain", "vs_5_0", 0, 0, &blobCode, &blobErrorMsgs );
if (!SUCCEEDED(D3DCompileFromFile(L"VertexShader.hlsl", nullptr, nullptr, "vsmain", "vs_5_0", 0, 0, &blobCode, &blobErrorMsgs)))
{
if (blobErrorMsgs) blobErrorMsgs->Release();
std::cout << "ERROR COMPILING VERTEXSHADER" << std::endl;
return false;
}
shaderByteCode = blobCode->GetBufferPointer();
byteCodeLength = blobCode->GetBufferSize();
ID3D11VertexShader* vertexShader;
d3dDevice->CreateVertexShader(shaderByteCode, byteCodeLength, nullptr, &vertexShader);
vertexShader->Release();
ID3D11InputLayout* inputLayout;
d3dDevice->CreateInputLayout(inputElementDescription, sizeInputElementDescription, shaderByteCode, byteCodeLength, &inputLayout);
blobCode->Release();
void* shaderByteCode2 = nullptr;
size_t byteCodeLength2 = 0;
ID3DBlob* blobCode2 = nullptr;
ID3DBlob* blobErrorMsgs2 = nullptr;
//D3DCompileFromFile(L"PixelShader.hlsl", nullptr, nullptr, "psmain", "ps_5_0", 0, 0, &blobCode2, &blobErrorMsgs2);
if (!SUCCEEDED(D3DCompileFromFile(L"PixelShader.hlsl", nullptr, nullptr, "psmain", "ps_5_0", 0, 0, &blobCode2, &blobErrorMsgs2)))
{
if (blobErrorMsgs2) blobErrorMsgs2->Release();
std::cout << "ERROR COMPILING PIXELSHADER" << std::endl;
return false;
}
shaderByteCode2 = blobCode2->GetBufferPointer();
byteCodeLength2 = blobCode2->GetBufferSize();
ID3D11PixelShader* pixelShader;
d3dDevice->CreatePixelShader(shaderByteCode2, byteCodeLength2, nullptr, &pixelShader);
pixelShader->Release();
blobCode2->Release();
FLOAT clearColor[] = { 0.0, 0.0, 0.0, 1.0 };
while (running)
{
d3dDeviceContext->ClearRenderTargetView(renderTargetView, clearColor);
d3dDeviceContext->OMSetRenderTargets(1, &renderTargetView, NULL);
GetClientRect(hwndApp, &rc);
D3D11_VIEWPORT vp = {};
vp.Width = rc.right - rc.left;
vp.Height = rc.bottom - rc.top;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
d3dDeviceContext->RSSetViewports(1, &vp);
d3dDeviceContext->VSSetShader(vertexShader, nullptr, 0);
d3dDeviceContext->PSSetShader(pixelShader, nullptr, 0);
UINT stride = sizeof(Vertex);
UINT offset = 0;
d3dDeviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
d3dDeviceContext->IASetInputLayout(inputLayout);
d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
d3dDeviceContext->Draw(sizeVertices, 0);
dxgiSwapChain->Present(true, NULL);
MSG msg = { 0 };
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
renderTargetView->Release();
inputLayout->Release();
vertexBuffer->Release();
dxgiDevice->Release();
dxgiAdapter->Release();
dxgiFactory->Release();
d3dDeviceContext->Release();
d3dDevice->Release();
return 0;
}
VertexShader
struct VS_INPUT
{
float4 position: POSITION;
float3 color: COLOR;
};
struct VS_OUTPUT
{
float4 position: SV_POSITION;
float3 color: COLOR;
};
VS_OUTPUT vsmain(VS_INPUT input)
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.position = input.position;
output.color = input.color;
return output;
}
PixelShader
struct PS_INPUT
{
float4 position: SV_POSITION;
float3 color: COLOR;
};
float4 psmain(PS_INPUT input) : SV_TARGET
{
return float4(input.color,1.0f);
}
I expect the window to show a multicolored quad, but the window is all white.
Shaders was released and then used later in code.
vertexShader->Release();
pixelShader->Release();
moving the release of shaders to the end of the program solved it.
I'm taking my first steps in programming with Direct3D. I have a very basic pipeline setup, and all I want to get from it is an antialiased smooth image. But I get this:
First, I can't get rid of stair effect though I have 4x MSAA enabled already in my pipeline (DXGI_SAMPLE_DESC::Count is 4 and Quality is 0):
And second, I get this noisy texturing though I have mipmaps generated and LINEAR filtering set in the sampler state.
Am I missing something or doing wrong?
Here is my code:
1) Renderer class:
#include "Scene.h" // Custom class that contains vertex and index buffer contents for every rendered mesh.
#include "Camera.h" // Custom class that contains camera position and fov.
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
#include <DirectXMath.h>
using namespace DirectX;
#include <map>
#include "generated\VertexShader.h"
#include "generated\PixelShader.h"
class Renderer
{
public:
Renderer(HWND hWnd, int wndWidth, int wndHeight, const Scene& scene, const Camera& camera);
void Render();
void SwitchToWireframe();
void SwitchToSolid();
protected:
void CreateDeviceAndSwapChain();
void CreateDepthStencil();
void CreateInputLayout();
void CreateVertexShader();
void CreatePixelShader();
void CreateRasterizerStates();
void CreateBlendState();
void CreateSamplerState();
void CreateBuffer(ID3D11Buffer** buffer,
D3D11_USAGE usage, D3D11_BIND_FLAG bindFlags,
UINT cpuAccessFlags, UINT miscFlags,
UINT sizeOfBuffer, UINT sizeOfBufferElement, const void* initialData);
void CreateTexture2DAndSRV(const Scene::Texture& texture, ID3D11ShaderResourceView** view);
void CreateTexturesAndViews();
void GenerateMips();
protected:
const Scene& m_scene;
const Camera& m_camera;
DWORD m_cameraLastUpdateTickCount;
HWND m_windowHandle;
int m_windowWidth;
int m_windowHeight;
DXGI_SAMPLE_DESC m_sampleDesc;
ComPtr<IDXGISwapChain> m_swapChain;
ComPtr<ID3D11Texture2D> m_swapChainBuffer;
ComPtr<ID3D11RenderTargetView> m_swapChainBufferRTV;
ComPtr<ID3D11Device> m_device;
ComPtr<ID3D11DeviceContext> m_deviceContext;
ComPtr<ID3D11Debug> m_debugger;
ComPtr<ID3D11Texture2D> m_depthStencilTexture;
ComPtr<ID3D11DepthStencilState> m_depthStencilState;
ComPtr<ID3D11DepthStencilView> m_depthStencilView;
ComPtr<ID3D11InputLayout> m_inputLayout;
ComPtr<ID3D11VertexShader> m_vertexShader;
ComPtr<ID3D11PixelShader> m_pixelShader;
ComPtr<ID3D11RasterizerState> m_solidRasterizerState;
ComPtr<ID3D11RasterizerState> m_wireframeRasterizerState;
ComPtr<ID3D11BlendState> m_blendState;
ComPtr<ID3D11SamplerState> m_linearSamplerState;
std::map<std::string, ComPtr<ID3D11ShaderResourceView>> m_diffuseMapViews;
std::map<std::string, ComPtr<ID3D11ShaderResourceView>> m_normalMapViews;
XMMATRIX m_worldViewMatrix;
ID3D11RasterizerState* m_currentRasterizerState;
};
void Renderer::CreateDeviceAndSwapChain()
{
HRESULT hr;
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferDesc.Width = m_windowWidth;
swapChainDesc.BufferDesc.Height = m_windowHeight;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 1;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 60;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
swapChainDesc.SampleDesc = m_sampleDesc;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = m_windowHandle;
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
D3D_FEATURE_LEVEL desiredFeatureLevels[] = { D3D_FEATURE_LEVEL_10_1 };
D3D_FEATURE_LEVEL featureLevel;
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
desiredFeatureLevels, 1, D3D11_SDK_VERSION, &swapChainDesc,
m_swapChain.GetAddressOf(), m_device.GetAddressOf(), &featureLevel,
m_deviceContext.GetAddressOf());
if (FAILED(hr))
{
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL,
D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
desiredFeatureLevels, 1, D3D11_SDK_VERSION, &swapChainDesc,
m_swapChain.GetAddressOf(), m_device.GetAddressOf(), &featureLevel,
m_deviceContext.GetAddressOf());
}
if (FAILED(hr))
throw std::exception("Failed to create device or swap chain");
hr = m_device->QueryInterface(m_debugger.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to get debugger interface");
hr = m_swapChain->GetBuffer(0, __uuidof(m_swapChainBuffer),
(void**)m_swapChainBuffer.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to get swap chain buffer");
hr = m_device->CreateRenderTargetView(m_swapChainBuffer.Get(), NULL,
m_swapChainBufferRTV.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create RTV for swap chain buffer");
}
void Renderer::CreateDepthStencil()
{
HRESULT hr;
D3D11_TEXTURE2D_DESC tdesc;
tdesc.Width = m_windowWidth;
tdesc.Height = m_windowHeight;
tdesc.MipLevels = 1;
tdesc.ArraySize = 1;
tdesc.Format = DXGI_FORMAT_D16_UNORM;
tdesc.SampleDesc = m_sampleDesc;
tdesc.Usage = D3D11_USAGE_DEFAULT;
tdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
tdesc.CPUAccessFlags = 0;
tdesc.MiscFlags = 0;
hr = m_device->CreateTexture2D(&tdesc, NULL, m_depthStencilTexture.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create depth stencil texture");
D3D11_DEPTH_STENCIL_VIEW_DESC dsvdesc;
dsvdesc.Format = DXGI_FORMAT_D16_UNORM;
dsvdesc.ViewDimension = m_sampleDesc.Count > 1
? D3D11_DSV_DIMENSION_TEXTURE2DMS
: D3D11_DSV_DIMENSION_TEXTURE2D;
dsvdesc.Flags = 0;
dsvdesc.Texture2D.MipSlice = 0;
hr = m_device->CreateDepthStencilView(m_depthStencilTexture.Get(), &dsvdesc,
m_depthStencilView.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create depth stencil view");
D3D11_DEPTH_STENCIL_DESC dsdesc;
dsdesc.DepthEnable = TRUE;
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsdesc.DepthFunc = D3D11_COMPARISON_LESS;
dsdesc.StencilEnable = FALSE;
dsdesc.StencilReadMask = 0;
dsdesc.StencilWriteMask = 0;
dsdesc.FrontFace = {};
dsdesc.BackFace = {};
hr = m_device->CreateDepthStencilState(&dsdesc, m_depthStencilState.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create depth stencil state");
}
void Renderer::CreateInputLayout()
{
HRESULT hr;
D3D11_INPUT_ELEMENT_DESC iedescs[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
hr = m_device->CreateInputLayout(iedescs, 3,
g_vertexShader, sizeof(g_vertexShader),
m_inputLayout.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create input layout");
}
void Renderer::CreateVertexShader()
{
HRESULT hr;
hr = m_device->CreateVertexShader(g_vertexShader, sizeof(g_vertexShader),
NULL, m_vertexShader.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create vertex shader");
}
void Renderer::CreatePixelShader()
{
HRESULT hr;
hr = m_device->CreatePixelShader(g_pixelShader, sizeof(g_pixelShader),
NULL, m_pixelShader.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create pixel shader");
}
void Renderer::CreateRasterizerStates()
{
HRESULT hr;
D3D11_RASTERIZER_DESC rdesc;
rdesc.FillMode = D3D11_FILL_SOLID;
rdesc.CullMode = D3D11_CULL_FRONT;
rdesc.FrontCounterClockwise = FALSE;
rdesc.DepthBias = 0;
rdesc.DepthBiasClamp = 0.0f;
rdesc.SlopeScaledDepthBias = 0.0f;
rdesc.DepthClipEnable = TRUE;
rdesc.ScissorEnable = FALSE;
rdesc.MultisampleEnable = m_sampleDesc.Count > 1 ? TRUE : FALSE;
rdesc.AntialiasedLineEnable = m_sampleDesc.Count > 1 ? TRUE : FALSE;
hr = m_device->CreateRasterizerState(&rdesc, m_solidRasterizerState.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create rasterizer state");
rdesc.FillMode = D3D11_FILL_WIREFRAME;
hr = m_device->CreateRasterizerState(&rdesc, m_wireframeRasterizerState.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create rasterizer state");
m_currentRasterizerState = m_solidRasterizerState.Get();
}
void Renderer::CreateSamplerState()
{
HRESULT hr;
D3D11_SAMPLER_DESC smdesc;
smdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
smdesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
smdesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
smdesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
smdesc.MipLODBias = 0.0f;
smdesc.MaxAnisotropy = 0;
smdesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
smdesc.BorderColor[4] = {};
FLOAT MinLOD = 0.0;
FLOAT MaxLOD = 0.0;
hr = m_device->CreateSamplerState(&smdesc, m_linearSamplerState.GetAddressOf());
if (FAILED(hr))
throw new std::exception("Failed to create sampler state");
}
void Renderer::CreateBlendState()
{
HRESULT hr;
D3D11_BLEND_DESC bdesc;
bdesc.AlphaToCoverageEnable = FALSE;
bdesc.IndependentBlendEnable = FALSE;
bdesc.RenderTarget[0].BlendEnable = FALSE;
bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
bdesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
hr = m_device->CreateBlendState(&bdesc, m_blendState.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create blend state");
}
void Renderer::CreateBuffer(ID3D11Buffer** buffer,
D3D11_USAGE usage, D3D11_BIND_FLAG bindFlags,
UINT cpuAccessFlags, UINT miscFlags,
UINT sizeOfBuffer, UINT sizeOfBufferElement, const void* initialData)
{
HRESULT hr;
D3D11_BUFFER_DESC bdesc;
bdesc.ByteWidth = sizeOfBuffer;
bdesc.Usage = usage;
bdesc.BindFlags = bindFlags;
bdesc.CPUAccessFlags = cpuAccessFlags;
bdesc.MiscFlags = miscFlags;
bdesc.StructureByteStride = sizeOfBufferElement;
D3D11_SUBRESOURCE_DATA bdata;
bdata.pSysMem = initialData;
bdata.SysMemPitch = 0;
bdata.SysMemSlicePitch = 0;
hr = m_device->CreateBuffer(&bdesc, &bdata, buffer);
if (FAILED(hr))
throw std::exception("Failed to create buffer");
}
void Renderer::CreateTexture2DAndSRV(const Scene::Texture& sceneTexture, ID3D11ShaderResourceView** view)
{
HRESULT hr;
constexpr DXGI_FORMAT texformat = DXGI_FORMAT_R32G32B32A32_FLOAT;
D3D11_TEXTURE2D_DESC tdesc;
tdesc.Width = sceneTexture.width;
tdesc.Height = sceneTexture.height;
tdesc.MipLevels = 0;
tdesc.ArraySize = 1;
tdesc.Format = texformat;
tdesc.SampleDesc.Count = 1;
tdesc.SampleDesc.Quality = 0;
tdesc.Usage = D3D11_USAGE_DEFAULT;
tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
tdesc.CPUAccessFlags = 0;
tdesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
ComPtr<ID3D11Texture2D> texture2d;
hr = m_device->CreateTexture2D(&tdesc, NULL, texture2d.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create texture");
D3D11_SUBRESOURCE_DATA srdata;
srdata.pSysMem = sceneTexture.data;
srdata.SysMemPitch = sceneTexture.width * sizeof(float) * 4;
srdata.SysMemSlicePitch = 0;
m_deviceContext->UpdateSubresource(texture2d.Get(), 0, NULL,
srdata.pSysMem, srdata.SysMemPitch, srdata.SysMemSlicePitch);
D3D11_SHADER_RESOURCE_VIEW_DESC srvdesc;
srvdesc.Format = texformat;
srvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvdesc.Texture2D.MostDetailedMip = 0;
srvdesc.Texture2D.MipLevels = -1;
ComPtr<ID3D11ShaderResourceView> shaderResourceView;
hr = m_device->CreateShaderResourceView(texture2d.Get(), &srvdesc, view);
if (FAILED(hr))
throw std::exception("Failed to create shader resource view");
}
void Renderer::CreateTexturesAndViews()
{
for (auto it = m_scene.materials.cbegin(); it != m_scene.materials.cend(); it++)
{
//don't know what's the problem but if I don't place initialized ComPtr<...> instance into a map
//then further .GetAddessOf() fails.
m_diffuseMapViews.emplace(it->first, ComPtr<ID3D11ShaderResourceView>());
m_normalMapViews.emplace(it->first, ComPtr<ID3D11ShaderResourceView>());
CreateTexture2DAndSRV(it->second.diffuseMap, m_diffuseMapViews[it->first].GetAddressOf());
CreateTexture2DAndSRV(it->second.normalMap, m_normalMapViews[it->first].GetAddressOf());
}
}
void Renderer::GenerateMips()
{
for (auto it = m_diffuseMapViews.begin(); it != m_diffuseMapViews.end(); it++)
m_deviceContext->GenerateMips(it->second.Get());
for (auto it = m_normalMapViews.begin(); it != m_normalMapViews.end(); it++)
m_deviceContext->GenerateMips(it->second.Get());
}
Renderer::Renderer(HWND hWnd, int windowWidth, int windowHeight,
const Scene& scene, const Camera& camera)
: m_scene(scene)
, m_camera(camera)
, m_cameraLastUpdateTickCount(0)
, m_windowHandle(hWnd)
, m_windowWidth(windowWidth)
, m_windowHeight(windowHeight)
{
m_sampleDesc.Count = 4;
m_sampleDesc.Quality = 0;
CreateDeviceAndSwapChain();
CreateDepthStencil();
CreateInputLayout();
CreateVertexShader();
CreatePixelShader();
CreateRasterizerStates();
CreateBlendState();
CreateSamplerState();
CreateTexturesAndViews();
GenerateMips();
// Setting up IA stage
m_deviceContext->IASetPrimitiveTopology(
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_deviceContext->IASetInputLayout(m_inputLayout.Get());
// Setting up VS stage
m_deviceContext->VSSetShader(m_vertexShader.Get(), 0, 0);
// Setting up RS stage
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = static_cast<FLOAT>(m_windowWidth);
viewport.Height = static_cast<FLOAT>(m_windowHeight);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
m_deviceContext->RSSetViewports(1, &viewport);
// Setting up PS stage
m_deviceContext->PSSetSamplers(0, 1, m_linearSamplerState.GetAddressOf());
m_deviceContext->PSSetShader(m_pixelShader.Get(), 0, 0);
// Setting up OM stage
m_deviceContext->OMSetBlendState(m_blendState.Get(), NULL, 0xffffffff);
m_deviceContext->OMSetDepthStencilState(m_depthStencilState.Get(), 0);
m_deviceContext->OMSetRenderTargets(1, m_swapChainBufferRTV.GetAddressOf(), m_depthStencilView.Get());
}
void Renderer::Render()
{
constexpr float background[4] = { 0.047f, 0.0487f, 0.066f, 1.0f };
// Setting up view matix
if (m_cameraLastUpdateTickCount
!= m_camera.GetLastUpdateTickCount())
{
const Float3& camFrom = m_camera.GetFrom();
const Float3& camAt = m_camera.GetAt();
const Float3& camUp = m_camera.GetUp();
m_cameraLastUpdateTickCount = m_camera.GetLastUpdateTickCount();
FXMVECTOR from = XMVectorSet(camFrom.x, camFrom.y, camFrom.z, 1.0f);
FXMVECTOR at = XMVectorSet(camAt.x, camAt.y, camAt.z, 1.0f);
FXMVECTOR up = XMVectorSet(camUp.x, camUp.y, camUp.z, 0.0f);
FXMVECTOR dir = XMVectorSubtract(at, from);
FXMVECTOR x = XMVector3Cross(dir, up);
FXMVECTOR up2 = XMVector3Cross(x, dir);
XMMATRIX lookTo = XMMatrixLookToRH(from, dir, up2);
float scalef = 1.0f / XMVectorGetByIndex(XMVector3Length(dir), 0);
XMMATRIX scale = XMMatrixScaling(scalef, scalef, scalef);
float aspect = float(m_windowWidth) / m_windowHeight;
float fov = m_camera.GetFov() / 180.0f * 3.14f;
XMMATRIX persp = XMMatrixPerspectiveFovRH(fov, aspect, 0.1f, 1000.0f);
m_worldViewMatrix = XMMatrixMultiply(XMMatrixMultiply(lookTo, scale), persp);
}
else
{
return;
}
m_deviceContext->ClearDepthStencilView(m_depthStencilView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
m_deviceContext->ClearRenderTargetView(m_swapChainBufferRTV.Get(), background);
for (auto imesh = m_scene.meshes.cbegin(); imesh != m_scene.meshes.cend(); imesh++)
{
// Creating vertex buffer
ComPtr<ID3D11Buffer> vertexBuffer;
CreateBuffer(vertexBuffer.GetAddressOf(),
D3D11_USAGE_DEFAULT, D3D11_BIND_VERTEX_BUFFER, 0, 0,
sizeof(Scene::Vertex) * imesh->vertices.size(), sizeof(Scene::Vertex),
imesh->vertices.data());
// Creating index buffer
ComPtr<ID3D11Buffer> indexBuffer;
CreateBuffer(indexBuffer.GetAddressOf(),
D3D11_USAGE_DEFAULT, D3D11_BIND_INDEX_BUFFER, 0, 0,
sizeof(unsigned int) * imesh->indices.size(), sizeof(unsigned int),
imesh->indices.data());
// Creating constant buffer
ComPtr<ID3D11Buffer> constantBuffer;
CreateBuffer(constantBuffer.GetAddressOf(),
D3D11_USAGE_IMMUTABLE, D3D11_BIND_CONSTANT_BUFFER, 0, 0,
sizeof(XMMATRIX), sizeof(XMMATRIX),
&m_worldViewMatrix);
// Setting up IA stage
ID3D11Buffer* vertexBuffers[8] = { vertexBuffer.Get() };
unsigned int vertexBufferStrides[8] = { sizeof(Scene::Vertex) };
unsigned int vertexBufferOffsets[8] = { 0 };
m_deviceContext->IASetVertexBuffers(0, 8,
vertexBuffers, vertexBufferStrides, vertexBufferOffsets);
m_deviceContext->IASetIndexBuffer(indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
// Setting up VS stage
m_deviceContext->VSSetConstantBuffers(0, 1, constantBuffer.GetAddressOf());
// Setting up RS stage
m_deviceContext->RSSetState(m_currentRasterizerState);
// Setting up PS stage
ID3D11ShaderResourceView* srvs[2] = { };
srvs[0] = m_diffuseMapViews.at(imesh->material).Get();
srvs[1] = m_normalMapViews.at(imesh->material).Get();
m_deviceContext->PSSetShaderResources(0, 2, srvs);
// Drawing
m_deviceContext->DrawIndexed(imesh->indices.size(), 0, 0);
}
m_swapChain->Present(0, 0);
}
void Renderer::SwitchToWireframe()
{
m_currentRasterizerState = m_wireframeRasterizerState.Get();
m_camera.UpdateLastUpdateTickCount();
}
void Renderer::SwitchToSolid()
{
m_currentRasterizerState = m_solidRasterizerState.Get();
m_camera.UpdateLastUpdateTickCount();
}
2) Vertex shader
struct VS_INPUT
{
float3 position : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD;
};
struct VS_OUTPUT
{
float4 position : SV_POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD;
};
cbuffer Matrices
{
matrix worldViewMatrix;
}
VS_OUTPUT main(VS_INPUT input)
{
VS_OUTPUT output;
output.position = mul(worldViewMatrix, float4(input.position.xyz, 1.0));
output.normal = input.normal;
output.texcoord = input.texcoord;
return output;
}
3) Pixel shader
Texture2D DiffuseMap : register(t0);
Texture2D NormalMap: register(t1);
SamplerState LinearSampler : register(s0);
float4 main(VS_OUTPUT input) : SV_TARGET
{
float3 light = normalize(float3(2.87, -0.36, 1.68));
float3 diffuseColor = DiffuseMap.Sample(LinearSampler, input.texcoord);
float3 normalDisplace = float3(0.0, 0.0, 1.0) - NormalMap.Sample(LinearSampler, input.texcoord);
float illumination = clamp(dot(light, input.normal + normalDisplace), 0.2, 1.0);
return float4(mul(diffuseColor, illumination), 1.0);
}
Okay, I've just figured out the reason of this stairs effect:
The reason is that I passed the same width and height values for CreateWindow WinApi function, and for DXGI_SWAP_CHAIN_DESC::BufferDesc. Meanwhile, these should be different because CreateWindow takes outer width and height of a window to create (window rectangle), while BufferDesc should receive inner values (window client area rectangle). Because of that actual area on screen was smaller than swap chain buffer and the result of rendering was presumably resampled to fit the rectangle, which was introducing the aliasing after MSAA was already applied.
Fixing the issue gave a much cleaner result (4x MSAA is applied here):
But the question with texture aliasing is still open:
I'm trying to render a square with a texture. Does anyone know why this texture appears to be shifted or misaligned?
Here is how it's supposed to look: http://imgur.com/siCQXXT
Here is how the issue looks: http://imgur.com/rj6tHcX
auto createVSTask = loadVSTask.then([this](const std::vector<byte>& fileData) {
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateVertexShader(
&fileData[0],
fileData.size(),
nullptr,
&m_vertexShader
)
);
static const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateInputLayout(
vertexDesc,
ARRAYSIZE(vertexDesc),
&fileData[0],
fileData.size(),
&m_inputLayout
)
);
});
auto createPSTask = loadPSTask.then([this](const std::vector<byte>& fileData) {
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreatePixelShader(
&fileData[0],
fileData.size(),
nullptr,
&m_pixelShader
)
);
CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateBuffer(
&constantBufferDesc,
nullptr,
&m_constantBuffer
)
);
});
auto createPrimitiveTask = (createPSTask && createVSTask).then([this]() {
const VertexPositionColor cubeVertices[] =
{
{ DirectX::XMFLOAT3(-1.0f, -1.0f, 0.0f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 0.0f) },
{ DirectX::XMFLOAT3(1.0f, -1.0f, 0.0f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 0.0f) },
{ DirectX::XMFLOAT3(1.0f, 1.0f, 0.0f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(1.0f, 1.0f) },
{ DirectX::XMFLOAT3(-1.0f, 1.0f, 0.0f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f), DirectX::XMFLOAT2(0.0f, 1.0f) },
};
static const unsigned short cubeIndices[] =
{
0, 1, 2,
0, 2, 3
};
m_indexCount = ARRAYSIZE(cubeIndices);
D3D11_SUBRESOURCE_DATA vertexBufferData = { 0 };
vertexBufferData.pSysMem = cubeVertices;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER);
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateBuffer(
&vertexBufferDesc,
&vertexBufferData,
&m_vertexBuffer
)
);
D3D11_SUBRESOURCE_DATA indexBufferData = { 0 };
indexBufferData.pSysMem = cubeIndices;
indexBufferData.SysMemPitch = 0;
indexBufferData.SysMemSlicePitch = 0;
CD3D11_BUFFER_DESC indexBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);
DX::ThrowIfFailed(
m_deviceResources->GetD3DDevice()->CreateBuffer(
&indexBufferDesc,
&indexBufferData,
&m_indexBuffer
)
);
});
auto loadTDTask = DX::ReadDataAsync(m_textureFile);
auto createSubresourceTask = loadTDTask.then([=](std::vector<byte>& textureData) {
D3D11_SUBRESOURCE_DATA textureSubresourceData = { 0 };
textureSubresourceData.pSysMem = &textureData[0];
textureSubresourceData.SysMemPitch = 1024;
textureSubresourceData.SysMemSlicePitch = 0;
D3D11_TEXTURE2D_DESC textureDesc = { 0 };
textureDesc.Width = 256;
textureDesc.Height = 256;
textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.CPUAccessFlags = 0;
textureDesc.ArraySize = 1;
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
textureDesc.MipLevels = 0;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
DX::ThrowIfFailed(m_d3dDevice->CreateTexture2D(
&textureDesc,
nullptr,
&m_texture
);
if (m_texture != NULL)
{
D3D11_SHADER_RESOURCE_VIEW_DESC textureViewDesc;
ZeroMemory(&textureViewDesc, sizeof(textureViewDesc));
textureViewDesc.Format = textureDesc.Format;
textureViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
textureViewDesc.Texture2D.MipLevels = -1;
textureViewDesc.Texture2D.MostDetailedMip = 0;
DX::ThrowIfFailed(
m_d3dDevice->CreateShaderResourceView(
m_texture.Get(),
&textureViewDesc,
&m_textureView
)
);
context->UpdateSubresource(m_texture.Get(), 0, nullptr, &textureData[0], textureSubresourceData.SysMemPitch, textureDesc.Width);
context->GenerateMips(m_textureView.Get());
}
}
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.MaxAnisotropy = 0;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
samplerDesc.BorderColor[0] = 0.0f;
samplerDesc.BorderColor[1] = 0.0f;
samplerDesc.BorderColor[2] = 0.0f;
samplerDesc.BorderColor[3] = 0.0f;
DX::ThrowIfFailed(
m_d3dDevice->CreateSamplerState(
&samplerDesc,
&m_sampler
)
);
First, you confirmed that it was no state or geometry problem with the clamp experiment, second, you said you are using a DDS image, and this is the key.
According to your code, the image is 256 width RGBA8, as the stone are 1/8 of that, it means they cover 32*4 = 128 bytes. Close enough, the DDS header is 124 bytes when you do not have the dx10 chunk in it and it explains why the image is offset-ed like that.
All you have to do is skip the header and pass only the image data to UpdateSubResource. I invit you to look at the DDS reference to learn how the file is layout so you can read the sizes, format, properly skip to the beginning of the data, and also take advantage of the DDS to store compressed format, and include the mip maps upfront to not use GenerateMips that is bad practice.
I am trying to texture a quad, with a character, that is within the glyph texture (obtained with D3DXFont::GetGlyphData).
Most of the characters are drawn correctly.
However characters such as: 'F', and 'A' are being drawn upside down.
None of the glyphs when saved to file seem to be upside down.
#include <Windows.h>
#include <d3d9.h>
#include <d3dx9.h>
// global declarations
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
ID3DXSprite* pSprite;
ID3DXFont* pFont;
void drawCharacter(const char c, int screenX, int screenY, D3DCOLOR color)
{
struct CUSTOMVERTEX
{
float x, y, z, rhw, tu, tv;
};
WORD glyphIndex;
IDirect3DTexture9* texture;
RECT rect;
POINT point;
D3DSURFACE_DESC desc;
if(GetGlyphIndices(pFont->GetDC(), &c, 1, &glyphIndex, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR)
return;
if(pFont->GetGlyphData(glyphIndex, &texture, &rect, &point) != S_OK)
return;
if(texture->GetLevelDesc(0, &desc) != D3D_OK)
return;
const float glyphWidth = static_cast<float>(desc.Width);
const float glyphHeight = static_cast<float>(desc.Height);
const float charWidth = static_cast<float>(rect.right - rect.left);
const float charHeight = static_cast<float>(rect.bottom - rect.top);
const float startX = static_cast<float>(screenY);
const float startY = static_cast<float>(screenY);
float u = (static_cast<float>(rect.left) + 0.5f) / glyphWidth;
float v = (static_cast<float>(rect.top) + 0.5f) / glyphHeight;
float u2 = u + (charWidth / glyphWidth);
float v2 = v + (charHeight / glyphHeight);
const CUSTOMVERTEX char_quad[4] =
{
// Bottom left vertex
{
startX, startY, 0.0f, 1.0f,
u, v2
},
// Bottom right vertex
{
startX + charWidth, startY, 0.0f, 1.0f,
u2, v2
},
// Top right vertex
{
startX + charWidth, startY + charHeight, 0.0f, 1.0f,
u2, v
},
// Top left vertex
{
startX, startY + charHeight, 0.0f, 1.0f,
u, v
}
};
// D3DXSaveTextureToFileA("glyph.dds", D3DXIFF_DDS, texture, 0);
d3ddev->SetTexture(0, texture);
d3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, char_quad, sizeof(CUSTOMVERTEX));
}
// this is the function used to render a single frame
void render_frame()
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
pSprite->Begin(D3DXSPRITE_ALPHABLEND);
// select which vertex format we are using
d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
drawCharacter('F', 100, 100, D3DCOLOR_XRGB(0, 255, 0));
pSprite->End();
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = "WindowClass";
if(!RegisterClassEx(&wc))
{
return 0;
}
hWnd = CreateWindowEx(NULL,
"WindowClass",
"Our Direct3D Program",
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
hInstance,
NULL);
if(!hWnd)
{
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(!d3d)
{
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = 800;
d3dpp.BackBufferHeight = 600;
// create a device class using this information and the info from the d3dpp stuct
if(d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev) != D3D_OK)
{
d3d->Release();
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
if(D3DXCreateSprite(d3ddev, &pSprite) != D3D_OK)
{
d3d->Release();
d3ddev->Release();
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
if(D3D_OK != D3DXCreateFont(d3ddev,
14,
0,
FW_BOLD,
1,
FALSE,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
ANTIALIASED_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
"Georgia",
&pFont))
{
d3d->Release();
d3ddev->Release();
pSprite->Release();
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
MSG msg;
while(TRUE)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(msg.message == WM_QUIT)
break;
render_frame();
}
d3d->Release();
d3ddev->Release();
pSprite->Release();
pFont->Release();
UnregisterClass(wc.lpszClassName, hInstance);
return msg.wParam;
}
Edit: Updated to include a full example of my problem.
It's been a while since I did any DirextX stuff, but I think it may be to do with the quad texture coordinate ordering. I ran your code and tried this:
const CUSTOMVERTEX char_quad[4] =
{
// Top left vertex
{
startX, startY + charHeight, 0.0f, 1.0f,
u, v2
},
// Top right vertex
{
startX + charWidth, startY + charHeight, 0.0f, 1.0f,
u2, v2
},
// Bottom right vertex
{
startX + charWidth, startY, 0.0f, 1.0f,
u2, v
},
// Bottom left vertex
{
startX, startY, 0.0f, 1.0f,
u, v
}
};
which output the characters ABCDEF all Ok.
I can't exactly remember how to specify the custom vertex, so I guess I was probably lucky with the above hack :)
Had another look at this and I think the coords should be ordered to render the TRIANGLEFAN in Clockwise Winding Order (so it doesn't get backface culled). Reordering the coords makes more sense I think:
// TRIANGLEFAN coords:
// v1-----v2 clockwise winding order
// | / |
// | / |
// v0-----v3
//
const CUSTOMVERTEX char_quad[4] =
{
// Bottom left vertex
{
startX, startY, 0.0f, 1.0f,
u, v
},
// Top left vertex
{
startX, startY + charHeight, 0.0f, 1.0f,
u, v2
},
// Top right vertex
{
startX + charWidth, startY + charHeight, 0.0f, 1.0f,
u2, v2
},
// Bottom right vertex
{
startX + charWidth, startY, 0.0f, 1.0f,
u2, v
},
};