Reputation: 1366
How to Render TriangleList and LineList in same frame in dx11.
I tried to bind two sets of buffers to GPU.
Each buffer set contains one index_buffer and one vertices buffer. And use ID3D11Device::DrawIndexed Function to Render the vertices.
I thought that to decide what polygon to render just simply call the ID3D11DeviceContext::IASetPrimitiveTopology function real-timely. But it seems won't work.
There would be only one single line rendered.
How can I render both the triangle and the line in same frame ?
My code is based on dxsdk tutorials03 in" dx11 area".The code is as follows.I simply add a ray render class to render a line .
#pragma once
//RayRenderClass.h
#include<D3D11.h>
#include<D3DX11.h>
#include<D3DX10math.h>
struct PointClass
{
float _XYZ[3];
};
struct VertexClass
{
PointClass pts;
float nor[3];
float tex[3];
};
class RayRenderClass
{
public:
RayRenderClass();
~RayRenderClass();
HRESULT Initialize(ID3D11Device* device, ID3D11DeviceContext* context);
HRESULT Shutdown();
HRESULT Render(ID3D11Device* device, ID3D11DeviceContext* context);
HRESULT UpdateStartPosition(D3DXVECTOR3 st);
HRESULT UpdateEndPosition(D3DXVECTOR3 ed);
D3DXVECTOR3 GetStartPosition();
D3DXVECTOR3 GetEndPosition();
private:
ULONG indices[2];
VertexClass pts[2];
ID3D11Buffer* m_indexBuffer;
ID3D11Buffer* m_vertices;
};
#include "RayRenderClass.h"
//RayRenderClass.cpp
#define SAFE_RELEASE(x) if((x)){(x)->Release(); x= nullptr;}
RayRenderClass::RayRenderClass()
{
ZeroMemory(pts, sizeof(pts));
//start point
pts[0].pts._XYZ[0] = 0.0f;
pts[0].pts._XYZ[1] = 0.0f;
pts[0].pts._XYZ[2] = 0.0f;
//end point
pts[1].pts._XYZ[0] = 1.0f;
pts[1].pts._XYZ[1] = 0.0f;
pts[1].pts._XYZ[2] = 0.0f;
}
RayRenderClass::~RayRenderClass()
{
}
HRESULT RayRenderClass::Initialize(ID3D11Device* device, ID3D11DeviceContext* context)
{
HRESULT hr = E_FAIL;
D3D11_BUFFER_DESC verticesDesc;
D3D11_BUFFER_DESC indexDesc;
D3D11_SUBRESOURCE_DATA verticesData;
D3D11_SUBRESOURCE_DATA indexData;
ZeroMemory(&verticesDesc, sizeof(verticesDesc));
verticesDesc.Usage = D3D11_USAGE_DYNAMIC;
verticesDesc.ByteWidth = sizeof(VertexClass)* 2;
verticesDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
verticesDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
ZeroMemory(&verticesData, sizeof(verticesData));
verticesData.pSysMem = &pts[0].pts._XYZ[0];
hr = device->CreateBuffer(&verticesDesc, &verticesData, &m_vertices);
if (FAILED(hr))
return hr;
ZeroMemory(&indexDesc, sizeof(indexDesc));
indexDesc.Usage = D3D11_USAGE_DEFAULT;
indexDesc.ByteWidth = sizeof(ULONG)* 2;
indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
ZeroMemory(&indexData, sizeof(indexData));
indexData.pSysMem = indices;
indexData.SysMemPitch = 0;
indexData.SysMemSlicePitch = 0;
hr = device->CreateBuffer(&indexDesc, &indexData, &m_indexBuffer);
if (FAILED(hr))
{
return hr;
}
return S_OK;
}
HRESULT RayRenderClass::Shutdown()
{
SAFE_RELEASE(m_vertices);
SAFE_RELEASE(m_indexBuffer);
return S_OK;
}
HRESULT RayRenderClass::UpdateStartPosition(D3DXVECTOR3 st)
{
HRESULT hr = E_FAIL;
pts[0].pts._XYZ[0] = st.x;
pts[0].pts._XYZ[1] = st.y;
pts[0].pts._XYZ[2] = st.z;
return hr;
}
HRESULT RayRenderClass::UpdateEndPosition(D3DXVECTOR3 ed)
{
HRESULT hr = E_FAIL;
pts[1].pts._XYZ[0] = ed.x;
pts[1].pts._XYZ[1] = ed.y;
pts[1].pts._XYZ[2] = ed.z;
return hr;
}
D3DXVECTOR3 RayRenderClass::GetStartPosition()
{
D3DXVECTOR3 ret = { pts[0].pts._XYZ };
return ret;
}
D3DXVECTOR3 RayRenderClass::GetEndPosition()
{
D3DXVECTOR3 ret = { pts[1].pts._XYZ };
return ret;
}
HRESULT RayRenderClass::Render(ID3D11Device* device, ID3D11DeviceContext* context)
{
HRESULT hr = E_FAIL;
D3D11_MAPPED_SUBRESOURCE mappedResource;
VertexClass* verticesPtr;
UINT stride = sizeof(VertexClass);
UINT offset = 0;
hr = context->Map(m_vertices, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(hr))
return hr;
verticesPtr = (VertexClass*)mappedResource.pData;
memcpy(verticesPtr, (void*)pts, (sizeof(VertexClass)* 2));
context->Unmap(m_vertices, 0);
context->IASetVertexBuffers(0, 1, &m_vertices, &stride, &offset);
context->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);
//D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
context->DrawIndexed(2, 0, 0);
return hr;
}
//--------------------------------------------------------------------------------------
// File: Tutorial03.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"
#include "RayRenderClass.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;
ID3D11Buffer* g_index = NULL;
RayRenderClass m_ray;
//--------------------------------------------------------------------------------------
// 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 3: Shaders",
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"Tutorial03.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"Tutorial03.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.0f, 0.5f, 0.5f ),
XMFLOAT3( 0.5f, -0.5f, 0.5f ),
XMFLOAT3( -0.5f, -0.5f, 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;
D3D11_BUFFER_DESC indexDesc;
D3D11_SUBRESOURCE_DATA indexData;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
// Set primitive topology
g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
UINT indices[] = {0,1,2};
ZeroMemory(&indexDesc, sizeof(indexDesc));
indexDesc.Usage = D3D11_USAGE_DEFAULT;
indexDesc.ByteWidth = sizeof(ULONG)* 3;
indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
ZeroMemory(&indexData, sizeof(indexData));
indexData.pSysMem = indices;
indexData.SysMemPitch = 0;
indexData.SysMemSlicePitch = 0;
hr = g_pd3dDevice->CreateBuffer(&indexDesc, &indexData, &g_index);
if (FAILED(hr))
{
return hr;
}
m_ray.Initialize(g_pd3dDevice, g_pImmediateContext);
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 );
g_pImmediateContext->IASetIndexBuffer(g_index, DXGI_FORMAT_R32_UINT, 0);
g_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Render a triangle
g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );
g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );
g_pImmediateContext->DrawIndexed( 3, 0 ,0);
// Present the information rendered to the back buffer to the front buffer (the screen)
m_ray.Render(g_pd3dDevice, g_pImmediateContext);
g_pSwapChain->Present(0, 0);
}
Upvotes: 0
Views: 2107
Reputation: 8963
In your render method, you don't set the vertex buffer for your triangle (only on initialization), so by calling
m_ray.Render(g_pd3dDevice, g_pImmediateContext);
You permanently set the pipeline to use your line buffer instead.
Make sure that the following line is called within your render function, to properly assign your triangle before the draw:
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
For you ray, you should not even need an index buffer, you can get rid of it and use:
g_pImmediateContext->Draw(2,0);
For the same effect
Upvotes: 1