Beginning Direct3D, simple triangle not rendering - c++

I've been playing around with making games for a little while now, using SDL at first and then SFML. It's been nice to have the basics done for me, but now I'd like to take another step and learn how to do the graphics from the ground up. So I'm trying to learn the ropes of Direct3D, and have been reading a couple of tutorials on D3D 11 to get started. I'm just trying to get the absolute basics going by drawing a white triangle on a dark background... but I can't get it to work.
I'm using the Visual Studio 2012 RC and the Windows 8 SDK, so there's some C++11 syntax in here, plus there's no D3DX. I've managed to set up the window and the initialization of Direct3D seems to go just fine. It runs the rendering part of the main loop, as it clears the screen in the color I specify. However, my fancy white triangle just won't show up. I've gone through my code several times, and with my lack of experience I can't tell what is wrong with it. I've cut out the window initialization/d3d shutdown and other irrelevant parts, but I'm afraid to cut off too much in case some of it is relevant to my problem, so... big-wall-of-code-warning.
I think I have all the required steps in place; I create the device, device context, swap chain and render target. Then I create a vertex shader+input layout and a pixel shader. After that I create a vertex buffer, add the vertices for my triangle and set the primitive topology to TRIANGLELIST, and that's it for the initialization. In my main loop, I point D3D to my vertex/pixel shaders, and tell it to draw the 3 vertices i inserted into the buffer. But only the dark blue background from the call to ClearRenderTargetView shows up; no triangle. Have I missed any steps, or done anything wrong on the way?
Here is the code I have (I'll shamefully admit to have slacked a bit with the code conventions on this one, so no p before pointer variables etc.):
Main loop:
while ( msg.message != WM_QUIT )
{
if ( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
g_d3dContext->ClearRenderTargetView( g_renderTarget, clearColor );
g_d3dContext->VSSetShader( g_vertexShader, nullptr, 0 );
g_d3dContext->PSSetShader( g_pixelShader, nullptr, 0 );
g_d3dContext->Draw( 3, 0 );
g_swapChain->Present( 0, 0 );
}
}
Direct3D init:
HRESULT hr = S_OK;
RECT rc;
GetClientRect( g_hWnd, &rc );
float width = static_cast<float>( rc.right - rc.left );
float height = static_cast<float>( rc.bottom - rc.top );
uint createDeviceFlags = 0;
const uint numDriverTypes = 3;
D3D_DRIVER_TYPE driverTypes[ numDriverTypes ] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE
};
const uint numFeatureLevels = 3;
D3D_FEATURE_LEVEL featureLevels[ numFeatureLevels ] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
DXGI_SWAP_CHAIN_DESC sd = { 0 };
sd.BufferCount = 1;
sd.BufferDesc.Width = static_cast<uint>( width );
sd.BufferDesc.Height = static_cast<uint>( height );
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = g_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = true;
for( uint driverTypeIndex : driverTypes )
{
g_driverType = driverTypes[ driverTypeIndex ];
hr = D3D11CreateDeviceAndSwapChain( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &g_swapChain, &g_d3d, &g_featureLevel, &g_d3dContext );
if( SUCCEEDED( hr ))
break;
}
if( FAILED( hr ))
return hr;
// Create a render target view
ID3D11Texture2D* backBuffer = nullptr;
hr = g_swapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast<void**>( &backBuffer ));
if( FAILED( hr ))
return hr;
hr = g_d3d->CreateRenderTargetView( backBuffer, nullptr, &g_renderTarget );
backBuffer->Release();
if( FAILED( hr ))
return hr;
g_d3dContext->OMSetRenderTargets( 1, &g_renderTarget, nullptr );
// Setup the viewport
D3D11_VIEWPORT vp = { 0 };
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_d3dContext->RSSetViewports( 1, &vp );
// Create vertex shader and input layout
ID3DBlob* vsBlob = nullptr;
ID3DBlob* errorBlob = nullptr;
hr = D3DCompileFromFile( L"VertexShader.hlsl", nullptr, nullptr, "main", "vs_4_0", 0, 0, &vsBlob, &errorBlob );
if ( FAILED( hr ))
return hr;
hr = g_d3d->CreateVertexShader( vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nullptr, &g_vertexShader );
if ( FAILED( hr ))
{
vsBlob->Release();
return hr;
}
D3D11_INPUT_ELEMENT_DESC ied = { 0 };
ied.AlignedByteOffset = 0;
ied.Format = DXGI_FORMAT_R32G32B32_FLOAT;
ied.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
ied.InputSlot = 0;
ied.InstanceDataStepRate = 0;
ied.SemanticIndex = 0;
ied.SemanticName = "POSITION";
hr = g_d3d->CreateInputLayout( &ied, 1, vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &g_inputLayout );
vsBlob->Release();
if ( FAILED ( hr ))
return hr;
g_d3dContext->IASetInputLayout( g_inputLayout );
// Create pixel shader
ID3DBlob* psBlob = nullptr;
errorBlob = nullptr;
hr = D3DCompileFromFile( L"PixelShader.hlsl", nullptr, nullptr, "main", "ps_4_0", 0, 0, &psBlob, &errorBlob );
if ( FAILED( hr ))
return hr;
hr = g_d3d->CreatePixelShader( psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nullptr, &g_pixelShader );
psBlob->Release();
if ( FAILED( hr ))
return hr;
// Put some vertices up in this bitch
Vector3f vertices[] =
{
Vector3f( 0.5f, -0.5f, 0.5f ),
Vector3f( 0.5f, -0.5f, 0.5f ),
Vector3f( -0.5f, -0.5f, 0.5f )
};
D3D11_BUFFER_DESC bd = { 0 };
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.ByteWidth = sizeof( Vector3f ) * 3;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
bd.StructureByteStride = 0;
bd.Usage = D3D11_USAGE_DEFAULT;
D3D11_SUBRESOURCE_DATA initData = { 0 };
initData.pSysMem = vertices;
initData.SysMemPitch = 0;
initData.SysMemSlicePitch = 0;
hr = g_d3d->CreateBuffer( &bd, &initData, &g_vertexBuffer );
if ( FAILED( hr ))
return hr;
uint stride = sizeof( Vector3f );
uint offset = 0;
g_d3dContext->IASetVertexBuffers( 0, 1, &g_vertexBuffer, &stride, &offset );
g_d3dContext->IASetPrimitiveTopology( D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
return S_OK;
My vertex type:
struct Vector3f
{
Vector3f( float ix, float iy, float iz )
: x( ix ), y( iy ), z( iz ) {}
float x;
float y;
float z;
};
My vertex shader:
float4 main( float4 pos : POSITION ) : SV_POSITION
{
return pos;
}
My pixel shader:
float4 main() : SV_TARGET
{
return float4( 1.0f, 1.0f, 1.0f, 1.0f );
}

Of course it was an incredibly stupid oversight. I simply entered bad vertex data - all the vertices were in the same Y dimension; the two first were even identical.
Changed to this:
Vector3f( -0.5f, 0.5f, 0.5f ),
Vector3f( 0.5f, 0.5f, 0.5f ),
Vector3f( -0.5f, -0.5f, 0.5f )
And there was much song and dance and happiness.

Related

Why is D2D drawing under D3D11?

My intuition is that if X is drawn before Y then X will be under Y. However, my code seems to always draw things drawn by D2D under things drawn by D3D11. This happens regardless of whether I'm using a depth buffer or not. Why is it doing this and how can I make D2D draw over D3D11 so that I can use D2D to create a GUI overlay?
Here is the smallest reproducible sample I could make:
#include <Windows.h>
#include <string>
#include <d3d11.h>
#include <d2d1.h>
#include <wrl.h>
#include <d3dcompiler.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "d3dcompiler.lib")
using namespace std;
using namespace Microsoft::WRL;
// Globals
HWND g_hWnd;
// D3D11
ComPtr<ID3D11Device> g_device;
ComPtr<ID3D11DeviceContext> g_context;
ComPtr<IDXGISwapChain> g_swapChain;
ComPtr<ID3D11RenderTargetView> g_renderTarget;
ComPtr<ID3D11Buffer> g_triangleVertexBuffer;
// D2D
ComPtr<ID2D1RenderTarget> g_renderTarget2D;
ComPtr<ID2D1Factory> g_factory2D;
// Utilities
constexpr const char* VERTEX_SHADER_CODE =
R"(
float4 main(float2 pos : POSITION) : SV_Position
{
return float4(pos, 0.0f, 1.0f);
}
)";
constexpr const char* PIXEL_SHADER_CODE =
R"(
float4 main() : SV_Target
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
)";
struct Vector2f
{
float x, y;
Vector2f() : x(0.0f), y(0.0f) { }
Vector2f(float x, float y) : x(x), y(y) { }
};
void AssertHResult(HRESULT hr, string errorMsg)
{
if (FAILED(hr))
throw std::exception(errorMsg.c_str());
}
void CompileShaderFromString(string code, string shaderType, ID3DBlob** output)
{
AssertHResult(D3DCompile(
code.c_str(),
code.length(),
nullptr,
nullptr,
nullptr,
"main",
shaderType.c_str(),
#ifdef _DEBUG
D3DCOMPILE_DEBUG |
#else
D3DCOMPILE_OPTIMIZATION_LEVEL3 |
#endif
D3DCOMPILE_ENABLE_STRICTNESS,
NULL,
output,
nullptr
), "Failed to compile shader");
}
// Graphics stuff
void InitializeD2D()
{
// Get swap chain surface
ComPtr<IDXGISurface> surface;
AssertHResult(g_swapChain->GetBuffer(
0,
__uuidof(IDXGISurface),
static_cast<void**>(&surface)
), "Failed to get surface of swap chain");
// Create factory
AssertHResult(D2D1CreateFactory<ID2D1Factory>(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&g_factory2D
), "Failed to create factory");
// Create render target
D2D1_RENDER_TARGET_PROPERTIES rtDesc = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_HARDWARE,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)
);
AssertHResult(g_factory2D->CreateDxgiSurfaceRenderTarget(
surface.Get(),
&rtDesc,
&g_renderTarget2D
), "Failed to create D2D render target");
}
void InitializeD3D()
{
// Get window dimensions
RECT rect{};
GetClientRect(g_hWnd, &rect);
float width = static_cast<float>(rect.right - rect.left);
float height = static_cast<float>(rect.bottom - rect.top);
// Create device, context, and swapchain
DXGI_SWAP_CHAIN_DESC scDesc{};
scDesc.BufferCount = 1;
scDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
scDesc.BufferDesc.Width = static_cast<UINT>(width);
scDesc.BufferDesc.Height = static_cast<UINT>(height);
scDesc.BufferDesc.RefreshRate.Numerator = 0;
scDesc.BufferDesc.RefreshRate.Denominator = 0;
scDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
scDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scDesc.Flags = NULL;
scDesc.OutputWindow = g_hWnd;
scDesc.SampleDesc.Count = 1;
scDesc.SampleDesc.Quality = 0;
scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scDesc.Windowed = true;
AssertHResult(D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
#ifdef _DEBUG
D3D11_CREATE_DEVICE_DEBUG |
#endif
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr,
NULL,
D3D11_SDK_VERSION,
&scDesc,
&g_swapChain,
&g_device,
nullptr,
&g_context
), "Failed to create device and swapchain");
// Create render target
ComPtr<ID3D11Resource> backBuffer;
AssertHResult(g_swapChain->GetBuffer(
0,
__uuidof(ID3D11Resource),
static_cast<void**>(&backBuffer)
), "Failed to get back buffer of swapchain");
AssertHResult(g_device->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&g_renderTarget
), "Failed to create render target view");
// Bind render target
g_context->OMSetRenderTargets(
1,
g_renderTarget.GetAddressOf(),
nullptr
);
// Bind viewport
D3D11_VIEWPORT viewport{};
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = width;
viewport.Height = height;
g_context->RSSetViewports(
1,
&viewport
);
}
void InitializeD3DTriangle()
{
// Create vertex buffer
Vector2f vertices[3] =
{
Vector2f(-0.5f, -0.5f),
Vector2f(0.0f, 0.5f),
Vector2f(0.5f, -0.5f)
};
D3D11_BUFFER_DESC vbDesc{};
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbDesc.ByteWidth = static_cast<UINT>(sizeof(Vector2f) * 3);
vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vbDesc.MiscFlags = NULL;
vbDesc.StructureByteStride = sizeof(Vector2f);
vbDesc.Usage = D3D11_USAGE_DYNAMIC;
D3D11_SUBRESOURCE_DATA vbData{};
vbData.pSysMem = vertices;
AssertHResult(g_device->CreateBuffer(
&vbDesc,
&vbData,
&g_triangleVertexBuffer
), "Failed to create vertex buffer");
// Bind vertex buffer
const UINT offset = 0;
const UINT stride = sizeof(Vector2f);
g_context->IASetVertexBuffers(
0,
1,
g_triangleVertexBuffer.GetAddressOf(),
&stride,
&offset
);
// Create and bind vertex shader
ComPtr<ID3DBlob> vsBlob;
ComPtr<ID3D11VertexShader> vertexShader;
CompileShaderFromString(
VERTEX_SHADER_CODE,
"vs_4_0",
&vsBlob
);
AssertHResult(g_device->CreateVertexShader(
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
nullptr,
&vertexShader
), "Failed to create vertex shader");
g_context->VSSetShader(
vertexShader.Get(),
nullptr,
NULL
);
// Create and bind pixel shader
ComPtr<ID3DBlob> pxBlob;
ComPtr<ID3D11PixelShader> pixelShader;
CompileShaderFromString(
PIXEL_SHADER_CODE,
"ps_4_0",
&pxBlob
);
AssertHResult(g_device->CreatePixelShader(
pxBlob->GetBufferPointer(),
pxBlob->GetBufferSize(),
nullptr,
&pixelShader
), "Failed to create pixel shader");
g_context->PSSetShader(
pixelShader.Get(),
nullptr,
NULL
);
// Set topology
g_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Create input layout
ComPtr<ID3D11InputLayout> inputLayout;
D3D11_INPUT_ELEMENT_DESC ilDesc{};
ilDesc.AlignedByteOffset = 0;
ilDesc.Format = DXGI_FORMAT_R32G32_FLOAT;
ilDesc.SemanticName = "POSITION";
ilDesc.SemanticIndex = 0;
ilDesc.InputSlot = 0;
ilDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
ilDesc.InstanceDataStepRate = 0;
AssertHResult(g_device->CreateInputLayout(
&ilDesc,
1,
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
&inputLayout
), "Failed to create input layout");
// Bind input layout
g_context->IASetInputLayout(inputLayout.Get());
}
// Windows
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
return 0;
}
void InitializeWindow(HINSTANCE hInst, int width, int height)
{
// Register window class
WNDCLASSEXW wc{};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"MainWindow";
wc.style = CS_OWNDC;
RegisterClassExW(&wc);
// Adjust width and height to be client area instead of window area
RECT rc{};
rc.left = 0;
rc.top = 0;
rc.right = width;
rc.bottom = height;
constexpr auto ws = WS_OVERLAPPEDWINDOW;
AdjustWindowRectEx(
&rc,
ws,
false,
NULL
);
// Instantiate and show window
g_hWnd = CreateWindowExW(
NULL,
L"MainWindow",
L"Window Title",
ws,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<int>(rc.right - rc.left),
static_cast<int>(rc.bottom - rc.top),
NULL,
NULL,
hInst,
nullptr
);
ShowWindow(g_hWnd, SW_SHOW);
}
// Driver code
void Update()
{
// Begin frame
g_renderTarget2D->BeginDraw();
// Clear screen to black
D2D1_COLOR_F bgColour = { 0.0f, 0.0f, 0.0f, 1.0f };
g_renderTarget2D->Clear(bgColour);
// Draw D3D triangle
g_context->Draw(
3,
0
);
// Draw D2D rectangle
D2D_RECT_F rect{};
rect.bottom = 500;
rect.top = 300;
rect.left = 100;
rect.right = 700;
D2D1_COLOR_F rectColour = { 0.0f, 1.0f, 0.0f, 1.0f };
ComPtr<ID2D1SolidColorBrush> brush;
g_renderTarget2D->CreateSolidColorBrush(
rectColour,
&brush
);
g_renderTarget2D->FillRectangle(
rect,
brush.Get()
);
// End frame
AssertHResult(g_swapChain->Present(
1,
NULL
), "Failed to present swapchain");
g_renderTarget2D->EndDraw();
}
int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE prevInst, LPWSTR cmdArgs, int cmdShow)
{
InitializeWindow(hInst, 800, 600);
InitializeD3D();
InitializeD2D();
InitializeD3DTriangle();
// Run message loop
while (true)
{
// Handle windows messages
MSG msg{};
PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE);
TranslateMessage(&msg);
DispatchMessageW(&msg);
if (msg.message == WM_QUIT)
break;
// Quit is escape is pressed
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
break;
// Do frame
Update();
}
return 0;
}
If you want to control the draw order, then you shouldn't be drawing both at the same time. Call Draw, then BeginDraw / EndDraw. Don't mix them as you have no idea when Direct2D is actually flushing commands to the context in your code, and you have no explicit indication of when Direct3D is done drawing to the render target.
You can of course call Direct3D's Flush which will force all work on the GPU to complete, but it's horribly inefficient to call it every frame.

Is it possible to draw a circle made up of triangles with DirectX 3D 11?

Is there a way to create a circle out of 16 triangles with DirectX 3D 11; kind of like a unit circle? I am currently using the Direct3D 11 Tutorial 02: Rendering a Triangle from the DirectX Sample Browser (June 2010) and modified it a bit to draw the triangle in the center, but I now want to draw a circle using that triangle.
Would I have to create 48 vertices to create it, or is there a easier way? Like using a for loop.
I am also new to C++, and am just learning and getting used to it and DirectX basics.
This is the code for the Tutorial02.cpp:
//--------------------------------------------------------------------------------------
// File: Tutorial02.cpp
//
// This application displays a triangle using Direct3D 11
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#include "resource.h"
//--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertex
{
XMFLOAT3 Pos;
};
//--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCE g_hInst = NULL;
HWND g_hWnd = NULL;
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device* g_pd3dDevice = NULL;
ID3D11DeviceContext* g_pImmediateContext = NULL;
IDXGISwapChain* g_pSwapChain = NULL;
ID3D11RenderTargetView* g_pRenderTargetView = NULL;
ID3D11VertexShader* g_pVertexShader = NULL;
ID3D11PixelShader* g_pPixelShader = NULL;
ID3D11InputLayout* g_pVertexLayout = NULL;
ID3D11Buffer* g_pVertexBuffer = NULL;
//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
HRESULT InitDevice();
void CleanupDevice();
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();
//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
UNREFERENCED_PARAMETER( hPrevInstance );
UNREFERENCED_PARAMETER( lpCmdLine );
if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
return 0;
if( FAILED( InitDevice() ) )
{
CleanupDevice();
return 0;
}
// Main message loop
MSG msg = {0};
while( WM_QUIT != msg.message )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render();
}
}
CleanupDevice();
return ( int )msg.wParam;
}
//--------------------------------------------------------------------------------------
// Register class and create window
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
// Register class
WNDCLASSEX wcex;
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"TutorialWindowClass";
wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
if( !RegisterClassEx( &wcex ) )
return E_FAIL;
// Create window
g_hInst = hInstance;
RECT rc = { 0, 0, 640, 480 };
AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 11 Tutorial 2: Rendering a Triangle",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,
NULL );
if( !g_hWnd )
return E_FAIL;
ShowWindow( g_hWnd, nCmdShow );
return S_OK;
}
//--------------------------------------------------------------------------------------
// Helper for compiling shaders with D3DX11
//--------------------------------------------------------------------------------------
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
{
HRESULT hr = S_OK;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
// Setting this flag improves the shader debugging experience, but still allows
// the shaders to be optimized and to run exactly the way they will run in
// the release configuration of this program.
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif
ID3DBlob* pErrorBlob;
hr = D3DX11CompileFromFile( szFileName, NULL, NULL, szEntryPoint, szShaderModel,
dwShaderFlags, 0, NULL, ppBlobOut, &pErrorBlob, NULL );
if( FAILED(hr) )
{
if( pErrorBlob != NULL )
OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );
if( pErrorBlob ) pErrorBlob->Release();
return hr;
}
if( pErrorBlob ) pErrorBlob->Release();
return S_OK;
}
//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
HRESULT hr = S_OK;
RECT rc;
GetClientRect( g_hWnd, &rc );
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
UINT createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = g_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
g_driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
if( SUCCEEDED( hr ) )
break;
}
if( FAILED( hr ) )
return hr;
// Create a render target view
ID3D11Texture2D* pBackBuffer = NULL;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
if( FAILED( hr ) )
return hr;
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );
// Setup the viewport
D3D11_VIEWPORT vp;
vp.Width = (FLOAT)width;
vp.Height = (FLOAT)height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports( 1, &vp );
// Compile the vertex shader
ID3DBlob* pVSBlob = NULL;
hr = CompileShaderFromFile( L"Tutorial02.fx", "VS", "vs_4_0", &pVSBlob );
if( FAILED( hr ) )
{
MessageBox( NULL,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
return hr;
}
// Create the vertex shader
hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader );
if( FAILED( hr ) )
{
pVSBlob->Release();
return hr;
}
// Define the input layout
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = ARRAYSIZE( layout );
// Create the input layout
hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &g_pVertexLayout );
pVSBlob->Release();
if( FAILED( hr ) )
return hr;
// Set the input layout
g_pImmediateContext->IASetInputLayout( g_pVertexLayout );
// Compile the pixel shader
ID3DBlob* pPSBlob = NULL;
hr = CompileShaderFromFile( L"Tutorial02.fx", "PS", "ps_4_0", &pPSBlob );
if( FAILED( hr ) )
{
MessageBox( NULL,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
return hr;
}
// Create the pixel shader
hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader );
pPSBlob->Release();
if( FAILED( hr ) )
return hr;
// Create vertex buffer
SimpleVertex vertices[] =
{
XMFLOAT3(-0.1f, 0.8f, 0.5f),
XMFLOAT3(0.1f, 0.8f, 0.5f),
XMFLOAT3(0.0f, 0.0f, 0.5f),
};
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 3;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
if( FAILED( hr ) )
return hr;
// Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
// Set primitive topology
g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
return S_OK;
}
//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
if( g_pImmediateContext ) g_pImmediateContext->ClearState();
if( g_pVertexBuffer ) g_pVertexBuffer->Release();
if( g_pVertexLayout ) g_pVertexLayout->Release();
if( g_pVertexShader ) g_pVertexShader->Release();
if( g_pPixelShader ) g_pPixelShader->Release();
if( g_pRenderTargetView ) g_pRenderTargetView->Release();
if( g_pSwapChain ) g_pSwapChain->Release();
if( g_pImmediateContext ) g_pImmediateContext->Release();
if( g_pd3dDevice ) g_pd3dDevice->Release();
}
//--------------------------------------------------------------------------------------
// Called every time the application receives a message
//--------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;
HDC hdc;
switch( message )
{
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
//--------------------------------------------------------------------------------------
// Render a frame
//--------------------------------------------------------------------------------------
void Render()
{
// Clear the back buffer
float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // red,green,blue,alpha
g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
// Render a triangle
g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );
g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );
g_pImmediateContext->Draw( 3, 0 );
// Present the information rendered to the back buffer to the front buffer (the screen)
g_pSwapChain->Present( 0, 0 );
}
If you want to draw a circle using 16 triangles, you need 17 vertices; one for each corner of your circle and one for the center. Then you have to use 48 indices to tell D3D how it should connect those vertices. Then you can call DrawIndexed to draw the triangles. You can also use a triangle strip which is a different primitive topology and uses slightly less indices.
See this tutorial on how to create vertex and index buffers.
Use a for loop, as you say. Let's say you want 10 triangles. There are 2pi radians in a circle, so 2pi/10 is the angle for each triangle. Let's calculate:
int n = 10; // number of triangles
SimpleVertex* vertices = malloc(sizeof(SimpleVertex) * 10 * 3); // 10 triangles, 3 verticies per triangle
float deltaTheta = 2*pi / n; // Change in theta for each vertex
for( int i = 0; i < n; i++ ) {
int theta = i * deltaTheta; // Theta is the angle for that triangle
int index = 3 * i;
vertices[index + 0] = SimpleVertex(0, 0, 0);
// Given an angle theta, cosine [cos] will give you the x coordinate,
// and sine [sin] will give you the y coordinate.
// #include <math.h>
vertices[index + 1] = SimpleVertex(cos(theta), sin(theta), 0);
vertices[index + 2] = SimpleVertex(cos(theta + deltaTheta), sin(theta + deltaTheta), 0);
}
Note:
As you can imagine, many of the vertices will overlap. (0, 0, 0) is always the same, and the last vertex of one triangle equals the 2nd vertical of the next triangle. I'll leave you up to the optimization, first get it working so you understand what's happening. If you aren't familiar with trig, look up the unit circle. Or just accept that cos/sin are defined to be the x and y coordinates of a circle given degrees (Or rather, radians). You will have to wait until your tutorial goes over how to specify what vertices each triangle uses first.

Can't get antialiased picture from Direct3D

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:

C++ : DirectX Texture is Misaligned/Shifted

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.

RenderTargetView <-> Texture

I found this tutorial, i follow it and i create the class DirectX
class DirectX
{
private:
D3D_DRIVER_TYPE DriverType;
D3D_FEATURE_LEVEL FeatureLevel;
public:
int InitDirectX(HWND &hwnd, WinDesc &wd)
{
HRESULT result;
RECT dimensions;
GetClientRect( hwnd, &dimensions );
int width=dimensions.right-dimensions.left;
int height=dimensions.bottom-dimensions.top;
D3D_DRIVER_TYPE driverTypes[]=
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_SOFTWARE
};
unsigned int totalDriverTypes=ARRAYSIZE(driverTypes);
D3D_FEATURE_LEVEL featureLevels[]=
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
unsigned int totalFeatureLevels = ARRAYSIZE( featureLevels );
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc,sizeof(swapChainDesc));
swapChainDesc.BufferCount=1;
swapChainDesc.BufferDesc.Width=width;
swapChainDesc.BufferDesc.Height=height;
swapChainDesc.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferDesc.RefreshRate.Numerator=60;
swapChainDesc.BufferDesc.RefreshRate.Denominator=1;
swapChainDesc.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow=hwnd;
swapChainDesc.Windowed=1;
swapChainDesc.SampleDesc.Count=1;
swapChainDesc.SampleDesc.Quality=0;
for(int driver=0;driver<totalDriverTypes;++driver)
{
result = D3D11CreateDeviceAndSwapChain( 0, driverTypes[driver], 0,
0, featureLevels, totalFeatureLevels,
D3D11_SDK_VERSION, &swapChainDesc, &SwapChain,
&Device, &FeatureLevel, &Context );
if( SUCCEEDED( result ) )
{
D3D_DRIVER_TYPE driverType_ = driverTypes[driver];
break;
}
}
}
D3D11_TEXTURE2D_DESC textureDesc;
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
ZeroMemory(&textureDesc, sizeof(textureDesc));
textureDesc.Width = width;
textureDesc.Height = height;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = 0;
result=Device->CreateTexture2D(&textureDesc, NULL, &backBuffer);
renderTargetViewDesc.Format = textureDesc.Format;
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
renderTargetViewDesc.Texture2D.MipSlice = 0;
result=Device->CreateRenderTargetView(backBuffer, &renderTargetViewDesc, &RenderTargetView);
shaderResourceViewDesc.Format = textureDesc.Format;
shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
shaderResourceViewDesc.Texture2D.MipLevels = 1;
result=Device->CreateShaderResourceView(backBuffer, &shaderResourceViewDesc, &shaderResourceView);
float color[4]={1,1,0,0};
Context->ClearRenderTargetView(RenderTargetView,color);
Context->OMSetRenderTargets(1,&RenderTargetView,0);
}
};
When i run it it get no error put when i call SwapChain->Present(0,0) nothing is displayed althought the renderTargetView should to be yellow.
Why?? I cannot found the error.
PS if i create a renderTargetView with this code:
ID3D11Texture2D* backBufferTexture;
result = SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ),
( LPVOID* )&backBufferTexture );
result = Device->CreateRenderTargetView( backBufferTexture, 0,
&RenderTargetView );
all works;
and in my code i check all the "result" values;
2°
this is code of the sprite i want render:
Init()//init vertex buffer, index buffer, texture, matrix....
the render functioon is this:
C->OMSetRenderTargets(1,&RT1,0);
C->Update(...)// matrix to sent vertex shader, set texture, vertex, buffer....
C->Draw(6,0)//draw the sprite;
It should render a sprite(ex. a ball) on RT1 then :
C->OMSetRenderTargets(1,&RT,0);
RT1->Update() //like the texture;
RT1->Draw(6,0)
...
Swapchain->present(1,0);
The RT1 is displayed(ex. if i have clear it with blue there is a blue shape on the screen i can translate, scale and rotate) but not the ball(i have render on RT1);
but if i render the ball without set RT1 as renderTargetView the ball is correct displayed