|
|
|
#pragma comment(lib, "user32") |
|
#pragma comment(lib, "d3d11") |
|
#pragma comment(lib, "d3dcompiler") |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
#include <windows.h> |
|
#include <d3d11_1.h> |
|
#include <d3dcompiler.h> |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
#define TITLE "Minimal D3D11 pt3 by d7samurai" |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) |
|
{ |
|
WNDCLASSA wndClass = { 0, DefWindowProcA, 0, 0, 0, 0, 0, 0, 0, TITLE }; |
|
|
|
RegisterClassA(&wndClass); |
|
|
|
HWND window = CreateWindowExA(0, TITLE, TITLE, WS_POPUP | WS_MAXIMIZE | WS_VISIBLE, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 }; |
|
|
|
ID3D11Device* baseDevice; |
|
ID3D11DeviceContext* baseDeviceContext; |
|
|
|
D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &baseDevice, nullptr, &baseDeviceContext); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
ID3D11Device1* device; |
|
|
|
baseDevice->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast<void**>(&device)); |
|
|
|
ID3D11DeviceContext1* deviceContext; |
|
|
|
baseDeviceContext->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void**>(&deviceContext)); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
IDXGIDevice1* dxgiDevice; |
|
|
|
device->QueryInterface(__uuidof(IDXGIDevice1), reinterpret_cast<void**>(&dxgiDevice)); |
|
|
|
IDXGIAdapter* dxgiAdapter; |
|
|
|
dxgiDevice->GetAdapter(&dxgiAdapter); |
|
|
|
IDXGIFactory2* dxgiFactory; |
|
|
|
dxgiAdapter->GetParent(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory)); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; |
|
swapChainDesc.Width = 0; // use window width |
|
swapChainDesc.Height = 0; // use window height |
|
swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // can't specify _SRGB here when using DXGI_SWAP_EFFECT_FLIP_* ... |
|
swapChainDesc.Stereo = FALSE; |
|
swapChainDesc.SampleDesc.Count = 1; |
|
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; |
|
swapChainDesc.BufferCount = 2; |
|
swapChainDesc.Scaling = DXGI_SCALING_STRETCH; |
|
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; |
|
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; |
|
|
|
IDXGISwapChain1* swapChain; |
|
|
|
dxgiFactory->CreateSwapChainForHwnd(device, window, &swapChainDesc, nullptr, nullptr, &swapChain); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
ID3D11Texture2D* framebufferTexture; |
|
|
|
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&framebufferTexture)); |
|
|
|
D3D11_RENDER_TARGET_VIEW_DESC framebufferDesc = {}; |
|
framebufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; // ... so do this to get _SRGB swapchain (rendertarget view) |
|
framebufferDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; |
|
|
|
ID3D11RenderTargetView* framebufferRTV; |
|
|
|
device->CreateRenderTargetView(framebufferTexture, &framebufferDesc, &framebufferRTV); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
D3D11_TEXTURE2D_DESC framebufferDepthDesc; |
|
|
|
framebufferTexture->GetDesc(&framebufferDepthDesc); // copy from framebuffer properties |
|
|
|
framebufferDepthDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; |
|
framebufferDepthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; |
|
|
|
ID3D11Texture2D* framebufferDepthTexture; |
|
|
|
device->CreateTexture2D(&framebufferDepthDesc, nullptr, &framebufferDepthTexture); |
|
|
|
ID3D11DepthStencilView* framebufferDSV; |
|
|
|
device->CreateDepthStencilView(framebufferDepthTexture, nullptr, &framebufferDSV); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
D3D11_TEXTURE2D_DESC shadowmapDepthDesc = {}; |
|
shadowmapDepthDesc.Width = 2048; |
|
shadowmapDepthDesc.Height = 2048; |
|
shadowmapDepthDesc.MipLevels = 1; |
|
shadowmapDepthDesc.ArraySize = 1; |
|
shadowmapDepthDesc.Format = DXGI_FORMAT_R32_TYPELESS; |
|
shadowmapDepthDesc.SampleDesc.Count = 1; |
|
shadowmapDepthDesc.Usage = D3D11_USAGE_DEFAULT; |
|
shadowmapDepthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; |
|
|
|
ID3D11Texture2D* shadowmapDepthTexture; |
|
|
|
device->CreateTexture2D(&shadowmapDepthDesc, nullptr, &shadowmapDepthTexture); |
|
|
|
D3D11_DEPTH_STENCIL_VIEW_DESC shadowmapDSVdesc = {}; |
|
shadowmapDSVdesc.Format = DXGI_FORMAT_D32_FLOAT; |
|
shadowmapDSVdesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; |
|
|
|
ID3D11DepthStencilView* shadowmapDSV; |
|
|
|
device->CreateDepthStencilView(shadowmapDepthTexture, &shadowmapDSVdesc, &shadowmapDSV); |
|
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC shadowmapSRVdesc = {}; |
|
shadowmapSRVdesc.Format = DXGI_FORMAT_R32_FLOAT; |
|
shadowmapSRVdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; |
|
shadowmapSRVdesc.Texture2D.MipLevels = 1; |
|
|
|
ID3D11ShaderResourceView* shadowmapSRV; |
|
|
|
device->CreateShaderResourceView(shadowmapDepthTexture, &shadowmapSRVdesc, &shadowmapSRV); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
struct float4 { float x, y, z, w; }; |
|
|
|
struct Constants |
|
{ |
|
float4 CameraProjection[4]; |
|
float4 LightProjection[4]; |
|
float4 LightRotation; |
|
float4 ModelRotation; |
|
float4 ModelTranslation; |
|
float4 ShadowmapSize; |
|
}; |
|
|
|
D3D11_BUFFER_DESC constantBufferDesc = {}; |
|
constantBufferDesc.ByteWidth = sizeof(Constants) + 0xf & 0xfffffff0; // ensure constant buffer size is multiple of 16 bytes |
|
constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; |
|
constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; |
|
constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; |
|
|
|
ID3D11Buffer* constantBuffer; |
|
|
|
device->CreateBuffer(&constantBufferDesc, nullptr, &constantBuffer); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
float vertexData[] = { -1, 1, -1, 0, 0, 1, 1, -1, 9.5f, 0, -0.58f, 0.58f, -1, 2, 2, 0.58f, 0.58f, -1, 7.5f, 2, -0.58f, 0.58f, -1, 0, 0, 0.58f, 0.58f, -1, 0, 0, -0.58f, 0.58f, -0.58f, 0, 0, 0.58f, 0.58f, -0.58f, 0, 0 }; // pos.x, pos.y, pos.z, tex.u, tex.v, ... |
|
|
|
D3D11_BUFFER_DESC vertexBufferDesc = {}; |
|
vertexBufferDesc.ByteWidth = sizeof(vertexData); |
|
vertexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; |
|
vertexBufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; // using regular shader resource as vertex buffer for manual vertex fetch |
|
vertexBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; |
|
vertexBufferDesc.StructureByteStride = 5 * sizeof(float); // 5 floats per vertex (float3 position, float2 texcoord) |
|
|
|
D3D11_SUBRESOURCE_DATA vertexBufferData = { vertexData }; |
|
|
|
ID3D11Buffer* vertexBuffer; |
|
|
|
device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &vertexBuffer); |
|
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC vertexBufferSRVdesc = {}; |
|
vertexBufferSRVdesc.Format = DXGI_FORMAT_UNKNOWN; |
|
vertexBufferSRVdesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; |
|
vertexBufferSRVdesc.Buffer.NumElements = vertexBufferDesc.ByteWidth / vertexBufferDesc.StructureByteStride; |
|
|
|
ID3D11ShaderResourceView* vertexBufferSRV; |
|
|
|
device->CreateShaderResourceView(vertexBuffer, &vertexBufferSRVdesc, &vertexBufferSRV); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
D3D11_DEPTH_STENCIL_DESC depthStencilDesc = {}; |
|
depthStencilDesc.DepthEnable = TRUE; |
|
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; |
|
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS; |
|
|
|
ID3D11DepthStencilState* depthStencilState; |
|
|
|
device->CreateDepthStencilState(&depthStencilDesc, &depthStencilState); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
D3D11_RASTERIZER_DESC1 rasterizerDesc = {}; |
|
rasterizerDesc.FillMode = D3D11_FILL_SOLID; |
|
rasterizerDesc.CullMode = D3D11_CULL_BACK; |
|
|
|
ID3D11RasterizerState1* cullBackRS; |
|
|
|
device->CreateRasterizerState1(&rasterizerDesc, &cullBackRS); |
|
|
|
rasterizerDesc.CullMode = D3D11_CULL_FRONT; |
|
|
|
ID3D11RasterizerState1* cullFrontRS; |
|
|
|
device->CreateRasterizerState1(&rasterizerDesc, &cullFrontRS); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
ID3DBlob* framebufferVSBlob; |
|
|
|
D3DCompileFromFile(L"shaders.hlsl", nullptr, nullptr, "framebuffer_vs", "vs_5_0", 0, 0, &framebufferVSBlob, nullptr); |
|
|
|
ID3D11VertexShader* framebufferVS; |
|
|
|
device->CreateVertexShader(framebufferVSBlob->GetBufferPointer(), framebufferVSBlob->GetBufferSize(), nullptr, &framebufferVS); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
ID3DBlob* framebufferPSBlob; |
|
|
|
D3DCompileFromFile(L"shaders.hlsl", nullptr, nullptr, "framebuffer_ps", "ps_5_0", 0, 0, &framebufferPSBlob, nullptr); |
|
|
|
ID3D11PixelShader* framebufferPS; |
|
|
|
device->CreatePixelShader(framebufferPSBlob->GetBufferPointer(), framebufferPSBlob->GetBufferSize(), nullptr, &framebufferPS); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
ID3DBlob* shadowmapVSBlob; |
|
|
|
D3DCompileFromFile(L"shaders.hlsl", nullptr, nullptr, "shadowmap_vs", "vs_5_0", 0, 0, &shadowmapVSBlob, nullptr); |
|
|
|
ID3D11VertexShader* shadowmapVS; |
|
|
|
device->CreateVertexShader(shadowmapVSBlob->GetBufferPointer(), shadowmapVSBlob->GetBufferSize(), nullptr, &shadowmapVS); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
FLOAT framebufferClear[4] = { 0.025f, 0.025f, 0.025f, 1 }; |
|
|
|
D3D11_VIEWPORT framebufferVP = { 0, 0, static_cast<float>(framebufferDepthDesc.Width), static_cast<float>(framebufferDepthDesc.Height), 0, 1 }; |
|
D3D11_VIEWPORT shadowmapVP = { 0, 0, static_cast<float>(shadowmapDepthDesc.Width), static_cast<float>(shadowmapDepthDesc.Height), 0, 1 }; |
|
|
|
ID3D11ShaderResourceView* nullSRV = nullptr; // null srv used for unbinding resources |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
Constants constants = { 2.0f / (framebufferVP.Width / framebufferVP.Height), 0, 0, 0, 0, 2, 0, 0, 0, 0, 1.125f, 1, 0, 0, -1.125f, 0, // camera projection matrix (perspective) |
|
0.5f, 0, 0, 0, 0, 0.5f, 0, 0, 0, 0, 0.125f, 0, 0, 0, -0.125f, 1 }; // light projection matrix (orthographic) |
|
|
|
constants.LightRotation = { 0.8f, 0.6f, 0.0f }; |
|
constants.ModelRotation = { 0.0f, 0.0f, 0.0f }; |
|
constants.ModelTranslation = { 0.0f, 0.0f, 4.0f }; |
|
|
|
constants.ShadowmapSize = { shadowmapVP.Width, shadowmapVP.Height }; |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
while (true) |
|
{ |
|
MSG msg; |
|
|
|
while (PeekMessageA(&msg, nullptr, 0, 0, PM_REMOVE)) |
|
{ |
|
if (msg.message == WM_KEYDOWN) return 0; |
|
DispatchMessageA(&msg); |
|
} |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
constants.ModelRotation.x += 0.001f; |
|
constants.ModelRotation.y += 0.005f; |
|
constants.ModelRotation.z += 0.003f; |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
D3D11_MAPPED_SUBRESOURCE mappedSubresource; |
|
|
|
deviceContext->Map(constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubresource); |
|
|
|
*reinterpret_cast<Constants*>(mappedSubresource.pData) = constants; |
|
|
|
deviceContext->Unmap(constantBuffer, 0); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
deviceContext->ClearDepthStencilView(shadowmapDSV, D3D11_CLEAR_DEPTH, 1.0f, 0); |
|
|
|
deviceContext->OMSetRenderTargets(0, nullptr, shadowmapDSV); // null rendertarget for depth only |
|
deviceContext->OMSetDepthStencilState(depthStencilState, 0); |
|
|
|
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); // using triangle strip this time |
|
|
|
deviceContext->VSSetConstantBuffers(0, 1, &constantBuffer); |
|
deviceContext->VSSetShaderResources(0, 1, &vertexBufferSRV); |
|
deviceContext->VSSetShader(shadowmapVS, nullptr, 0); |
|
|
|
deviceContext->RSSetViewports(1, &shadowmapVP); |
|
deviceContext->RSSetState(cullFrontRS); |
|
|
|
deviceContext->PSSetShader(nullptr, nullptr, 0); // null pixelshader for depth only |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
deviceContext->DrawInstanced(8, 24, 0, 0); // render shadowmap (light pov) |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
deviceContext->ClearRenderTargetView(framebufferRTV, framebufferClear); |
|
deviceContext->ClearDepthStencilView(framebufferDSV, D3D11_CLEAR_DEPTH, 1.0f, 0); |
|
|
|
deviceContext->OMSetRenderTargets(1, &framebufferRTV, framebufferDSV); |
|
|
|
deviceContext->VSSetShader(framebufferVS, nullptr, 0); |
|
|
|
deviceContext->RSSetViewports(1, &framebufferVP); |
|
deviceContext->RSSetState(cullBackRS); |
|
|
|
deviceContext->PSSetShaderResources(1, 1, &shadowmapSRV); |
|
deviceContext->PSSetShader(framebufferPS, nullptr, 0); |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
deviceContext->DrawInstanced(8, 24, 0, 0); // render framebuffer (camera pov) |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
deviceContext->PSSetShaderResources(1, 1, &nullSRV); // release shadowmap as srv to avoid srv/dsv conflict |
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
swapChain->Present(1, 0); |
|
} |
|
} |
Great example how instead of wasting time on stack you can study simple, well made examples. I literally cannot stress it enough how yours 2 previous examples helped me to simply understand what goes where and how a simple pipeline should look like, and I will be glad to test this one too when the time comes :)