提交 e7abbbf9 编写于 作者: GamebabyRockSun_QQ's avatar GamebabyRockSun_QQ

添加17号示例,Assimp导入模型,并运行3D骨骼动画

上级 75eacf58
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
#include <windows.h>
#include <tchar.h>
#include <commdlg.h>
#include <wrl.h> //添加WTL支持 方便使用COM
#include <strsafe.h>
#include <atlbase.h>
#include <atlcoll.h>
#include <atlchecked.h>
#include <atlstr.h>
#include <atlconv.h>
#include <atlexcept.h>
#include <DirectXMath.h>
#include <dxgi1_6.h>
#include <d3d12.h> //for d3d12
#include <d3dcompiler.h>
#if defined(_DEBUG)
#include <dxgidebug.h>
#endif
#include "../Commons/GRS_Assimp_Loader.h"
#include "../Commons/GRS_D3D12_Utility.h"
#include "../Commons/GRS_Texture_Loader.h"
using namespace DirectX;
using namespace Microsoft;
using namespace Microsoft::WRL;
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "d3dcompiler.lib")
#pragma comment(lib, "assimp-vc142-mtd.lib")
#define GRS_SLEEP(dwMilliseconds) WaitForSingleObject(GetCurrentThread(),dwMilliseconds)
#define GRS_THROW_IF_FAILED(hr) {HRESULT _hr = (hr);if (FAILED(_hr)){ ATLTRACE("Error: 0x%08x\n",_hr); AtlThrow(_hr); }}
//更简洁的向上边界对齐算法 内存管理中常用 请记住
#define GRS_UPPER(A,B) ((size_t)(((A)+((B)-1))&~((B) - 1)))
//上取整除法
#define GRS_UPPER_DIV(A,B) ((UINT)(((A)+((B)-1))/(B)))
#define GRS_WND_CLASS _T("GRS Game Window Class")
#define GRS_WND_TITLE _T("GRS DirectX12 Assimp Import Model & Animation & Render")
struct ST_GRS_CB_MVP
{
XMFLOAT4X4 mxWorld; //世界矩阵,这里其实是Model->World的转换矩阵
XMFLOAT4X4 mxView; //视矩阵
XMFLOAT4X4 mxProjection; //投影矩阵
XMFLOAT4X4 mxViewProj; //视矩阵*投影
XMFLOAT4X4 mxMVP; //世界*视矩阵*投影
};
struct ST_GRS_CB_BONES
{
XMFLOAT4X4 mxBones[GRS_MAX_BONES]; //骨骼动画“调色板” 最多256根"大骨头"。内存大,显存多,任性!
};
TCHAR g_pszAppPath[MAX_PATH] = {};
CHAR g_pszAppPathA[MAX_PATH] = {};
CHAR g_pszModelFile[MAX_PATH] = {};
ST_GRS_MESH_DATA g_stMeshData = {};
XMVECTOR g_v4EyePos = XMVectorSet( 0.0f, 20.0f, -100.0f, 0.0f ); //眼睛位置
XMVECTOR g_v4LookAt = XMVectorSet( 0.0f, 10.0f, 0.2f, 0.0f ); //眼睛所盯的位置
XMVECTOR g_v4UpDir = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ); //头部正上方位置
BOOL g_bWireFrame = FALSE;
FLOAT g_fScaling = 1.0f;
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
int iWidth = 1024;
int iHeight = 768;
HWND hWnd = nullptr;
MSG msg = {};
const UINT nFrameBackBufCount = 3u;
UINT nFrameIndex = 0;
DXGI_FORMAT emRenderTargetFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
const float faClearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
UINT nRTVDescriptorSize = 0U;
UINT nSamplerDescriptorSize = 0;
UINT nCBVSRVDescriptorSize = 0;
D3D12_VIEWPORT stViewPort = { 0.0f, 0.0f, static_cast<float>( iWidth ), static_cast<float>( iHeight ), D3D12_MIN_DEPTH, D3D12_MAX_DEPTH };
D3D12_RECT stScissorRect = { 0, 0, static_cast<LONG>( iWidth ), static_cast<LONG>( iHeight ) };
D3D_FEATURE_LEVEL emFeatureLevel = D3D_FEATURE_LEVEL_12_1;
ComPtr<IDXGIFactory5> pIDXGIFactory5;
ComPtr<IDXGIFactory6> pIDXGIFactory6;
ComPtr<IDXGIAdapter1> pIAdapter1;
ComPtr<ID3D12Device4> pID3D12Device4;
ComPtr<ID3D12CommandQueue> pIMainCMDQueue;
ComPtr<ID3D12CommandAllocator> pIMainCMDAlloc;
ComPtr<ID3D12GraphicsCommandList> pIMainCMDList;
ComPtr<ID3D12CommandQueue> pICopyCMDQueue;
ComPtr<ID3D12CommandAllocator> pICopyCMDAlloc;
ComPtr<ID3D12GraphicsCommandList> pICopyCMDList;
ComPtr<ID3D12Fence> pIFence;
UINT64 n64FenceValue = 0ui64;
HANDLE hEventFence = nullptr;
D3D12_RESOURCE_BARRIER stBeginResBarrier = {};
D3D12_RESOURCE_BARRIER stEneResBarrier = {};
ComPtr<IDXGISwapChain1> pISwapChain1;
ComPtr<IDXGISwapChain3> pISwapChain3;
ComPtr<ID3D12DescriptorHeap> pIRTVHeap;
ComPtr<ID3D12Resource> pIARenderTargets[nFrameBackBufCount];
ComPtr<ID3D12DescriptorHeap> pIDSVHeap;
ComPtr<ID3D12Resource> pIDepthStencilBuffer;
ComPtr<ID3DBlob> pIVSModel;
ComPtr<ID3DBlob> pIPSModel;
ComPtr<ID3D12RootSignature> pIRootSignature;
ComPtr<ID3D12PipelineState> pIPSOModel;
ComPtr<ID3D12PipelineState> pIPSOWireFrame;
ComPtr<ID3D12DescriptorHeap> pICBVSRVHeap;
ComPtr<ID3D12DescriptorHeap> pISamplerHeap;
ComPtr<ID3D12Heap> pIUploadHeapModel;
ComPtr<ID3D12Heap> pIDefaultHeapModel;
ComPtr<ID3D12Heap> pIUploadHeapIndices;
ComPtr<ID3D12Heap> pIDefaultHeapIndices;
ComPtr<ID3D12Resource> pIVBPositionsUp;
ComPtr<ID3D12Resource> pIVBNormalsUp;
ComPtr<ID3D12Resource> pIVBTexCoordsUp;
ComPtr<ID3D12Resource> pIVBBoneIndicesUp;
ComPtr<ID3D12Resource> pIIBIndicesUp;
ComPtr<ID3D12Resource> pIVBPositions;
ComPtr<ID3D12Resource> pIVBNormals;
ComPtr<ID3D12Resource> pIVBTexCoords;
ComPtr<ID3D12Resource> pIVBBoneIndices;
ComPtr<ID3D12Resource> pIIBIndices;
// 顶点缓冲视图,注意本例中用了4个slot来传入顶点数据,所以需要4个视图
// 多Slot向显卡传递顶点数据是一个重要的技巧,目前大多数模型导入库都是按数据类型分别导入每组数据
// 同时很多游戏引擎也是支持多slot来导入顶点数据的
D3D12_VERTEX_BUFFER_VIEW staVBV[g_ncSlotCnt] = {};
D3D12_INDEX_BUFFER_VIEW stIBV = {};
ComPtr<ID3D12Resource> pICBMVP;
ComPtr<ID3D12Resource> pICBBones;
ST_GRS_CB_MVP* pstCBMVP = nullptr;
ST_GRS_CB_BONES* pstBones = nullptr;
ComPtr<IWICImagingFactory> pIWICFactory;
ComPtr<IWICBitmapDecoder> pIWICDecoder;
ComPtr<IWICBitmapFrameDecode> pIWICFrame;
ComPtr<IWICBitmapSource> pIBMP;
CAtlArray<ComPtr<ID3D12Resource>> arTexture;
CAtlArray<ComPtr<ID3D12Resource>> arTextureUp;
USES_CONVERSION;
try
{
::CoInitialize( nullptr ); //for WIC & COM
// 0、得到当前的工作目录,方便我们使用相对路径来访问各种资源文件
{
if ( 0 == ::GetModuleFileName( nullptr, g_pszAppPath, MAX_PATH ) )
{
GRS_THROW_IF_FAILED( HRESULT_FROM_WIN32( GetLastError() ) );
}
WCHAR* lastSlash = _tcsrchr( g_pszAppPath, _T( '\\' ) );
if ( lastSlash )
{//删除Exe文件名
*( lastSlash ) = _T( '\0' );
}
lastSlash = _tcsrchr( g_pszAppPath, _T( '\\' ) );
if ( lastSlash )
{//删除x64路径
*( lastSlash ) = _T( '\0' );
}
lastSlash = _tcsrchr( g_pszAppPath, _T( '\\' ) );
if ( lastSlash )
{//删除Debug 或 Release路径
*( lastSlash + 1 ) = _T( '\0' );
}
// 复制一份MBCS的路径供Assimp使用
StringCchCopyA( g_pszAppPathA, MAX_PATH, T2A( g_pszAppPath ) );
}
// 1、载入默认的模型
{
g_stMeshData.m_strFileName = CString( g_pszAppPathA ) + "Assets\\The3DModel\\hero.x";
CHAR pszAppPathA[MAX_PATH] = {};
StringCchCopyA( pszAppPathA, MAX_PATH, T2A( g_pszAppPath ) );
//CHAR pXFile[MAX_PATH] = {};
//StringCchPrintfA( pXFile, MAX_PATH, "%Assets\\The3DModel\\hero.x", pszAppPathA );
g_stMeshData.m_strFileName.Format( "%Assets\\The3DModel\\hero.x", pszAppPathA );
OPENFILENAMEA ofn;
RtlZeroMemory( &ofn, sizeof( ofn ) );
ofn.lStructSize = sizeof( ofn );
ofn.hwndOwner = ::GetConsoleWindow();
ofn.lpstrFilter = "x 文件\0*.x;*.X\0OBJ文件\0*.obj\0FBX文件\0*.fbx\0所有文件\0*.*\0";
ofn.lpstrFile = g_stMeshData.m_strFileName.GetBuffer();
ofn.nMaxFile = MAX_PATH;
ofn.lpstrTitle = "请选择一个3D模型文件.......";
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
if ( !GetOpenFileNameA( &ofn ) )
{
g_stMeshData.m_strFileName.Format( "%Assets\\The3DModel\\hero.x", pszAppPathA );
}
if ( !LoadMesh( g_stMeshData.m_strFileName, g_stMeshData ) )
{
GRS_THROW_IF_FAILED( HRESULT_FROM_WIN32( GetLastError() ) );
}
}
// 2、创建窗口
{
WNDCLASSEX wcex = {};
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_GLOBALCLASS;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor( nullptr, IDC_ARROW );
wcex.hbrBackground = (HBRUSH) GetStockObject( NULL_BRUSH ); //防止无聊的背景重绘
wcex.lpszClassName = GRS_WND_CLASS;
RegisterClassEx( &wcex );
DWORD dwWndStyle = WS_OVERLAPPED | WS_SYSMENU;
RECT rtWnd = { 0, 0, iWidth, iHeight };
AdjustWindowRect( &rtWnd, dwWndStyle, FALSE );
// 计算窗口居中的屏幕坐标
INT posX = ( GetSystemMetrics( SM_CXSCREEN ) - rtWnd.right - rtWnd.left ) / 2;
INT posY = ( GetSystemMetrics( SM_CYSCREEN ) - rtWnd.bottom - rtWnd.top ) / 2;
hWnd = CreateWindowW( GRS_WND_CLASS
, GRS_WND_TITLE
, dwWndStyle
, posX
, posY
, rtWnd.right - rtWnd.left
, rtWnd.bottom - rtWnd.top
, nullptr
, nullptr
, hInstance
, nullptr );
if ( !hWnd )
{
GRS_THROW_IF_FAILED( HRESULT_FROM_WIN32( GetLastError() ) );
}
}
// 3、创建DXGI Factory对象
{
UINT nDXGIFactoryFlags = 0U;
#if defined(_DEBUG)
// 打开显示子系统的调试支持
ComPtr<ID3D12Debug> debugController;
if ( SUCCEEDED( D3D12GetDebugInterface( IID_PPV_ARGS( &debugController ) ) ) )
{
debugController->EnableDebugLayer();
// 打开附加的调试支持
nDXGIFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
}
#endif
GRS_THROW_IF_FAILED( CreateDXGIFactory2( nDXGIFactoryFlags, IID_PPV_ARGS( &pIDXGIFactory5 ) ) );
GRS_SET_DXGI_DEBUGNAME_COMPTR( pIDXGIFactory5 );
//获取IDXGIFactory6接口
GRS_THROW_IF_FAILED( pIDXGIFactory5.As( &pIDXGIFactory6 ) );
GRS_SET_DXGI_DEBUGNAME_COMPTR( pIDXGIFactory6 );
}
// 4、枚举适配器创建设备
{//选择NUMA架构的独显来创建3D设备对象,暂时先不支持集显了,当然你可以修改这些行为
GRS_THROW_IF_FAILED( pIDXGIFactory6->EnumAdapterByGpuPreference( 0
, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE
, IID_PPV_ARGS( &pIAdapter1 ) ) );
GRS_SET_DXGI_DEBUGNAME_COMPTR( pIAdapter1 );
// 创建D3D12.1的设备
GRS_THROW_IF_FAILED( D3D12CreateDevice( pIAdapter1.Get(), D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS( &pID3D12Device4 ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pID3D12Device4 );
DXGI_ADAPTER_DESC1 stAdapterDesc = {};
TCHAR pszWndTitle[MAX_PATH] = {};
GRS_THROW_IF_FAILED( pIAdapter1->GetDesc1( &stAdapterDesc ) );
::GetWindowText( hWnd, pszWndTitle, MAX_PATH );
StringCchPrintf( pszWndTitle
, MAX_PATH
, _T( "%s(GPU[0]:%s)" )
, pszWndTitle
, stAdapterDesc.Description );
::SetWindowText( hWnd, pszWndTitle );
// 得到每个描述符元素的大小
nRTVDescriptorSize = pID3D12Device4->GetDescriptorHandleIncrementSize( D3D12_DESCRIPTOR_HEAP_TYPE_RTV );
nSamplerDescriptorSize = pID3D12Device4->GetDescriptorHandleIncrementSize( D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER );
nCBVSRVDescriptorSize = pID3D12Device4->GetDescriptorHandleIncrementSize( D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV );
}
// 5、创建命令队列&命令列表
{
D3D12_COMMAND_QUEUE_DESC stQueueDesc = {};
stQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommandQueue( &stQueueDesc, IID_PPV_ARGS( &pIMainCMDQueue ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIMainCMDQueue );
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT
, IID_PPV_ARGS( &pIMainCMDAlloc ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIMainCMDAlloc );
// 创建图形命令列表
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommandList(
0
, D3D12_COMMAND_LIST_TYPE_DIRECT
, pIMainCMDAlloc.Get()
, nullptr
, IID_PPV_ARGS( &pIMainCMDList ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIMainCMDList );
stQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommandQueue( &stQueueDesc, IID_PPV_ARGS( &pICopyCMDQueue ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pICopyCMDQueue );
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_COPY
, IID_PPV_ARGS( &pICopyCMDAlloc ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pICopyCMDAlloc );
// 创建图形命令列表
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommandList(
0
, D3D12_COMMAND_LIST_TYPE_COPY
, pICopyCMDAlloc.Get()
, nullptr
, IID_PPV_ARGS( &pICopyCMDList ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pICopyCMDList );
}
// 6、创建交换链
{
DXGI_SWAP_CHAIN_DESC1 stSwapChainDesc = {};
stSwapChainDesc.BufferCount = nFrameBackBufCount;
stSwapChainDesc.Width = 0;//iWidth;
stSwapChainDesc.Height = 0;// iHeight;
stSwapChainDesc.Format = emRenderTargetFormat;
stSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
stSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
stSwapChainDesc.SampleDesc.Count = 1;
stSwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
stSwapChainDesc.Scaling = DXGI_SCALING_NONE;
GRS_THROW_IF_FAILED( pIDXGIFactory6->CreateSwapChainForHwnd(
pIMainCMDQueue.Get(), // 交换链需要命令队列,Present命令要执行
hWnd,
&stSwapChainDesc,
nullptr,
nullptr,
&pISwapChain1
) );
GRS_SET_DXGI_DEBUGNAME_COMPTR( pISwapChain1 );
GRS_THROW_IF_FAILED( pISwapChain1.As( &pISwapChain3 ) );
GRS_SET_DXGI_DEBUGNAME_COMPTR( pISwapChain3 );
//得到当前后缓冲区的序号,也就是下一个将要呈送显示的缓冲区的序号
//注意此处使用了高版本的SwapChain接口的函数
nFrameIndex = pISwapChain3->GetCurrentBackBufferIndex();
//创建RTV(渲染目标视图)描述符堆(这里堆的含义应当理解为数组或者固定大小元素的固定大小显存池)
{
D3D12_DESCRIPTOR_HEAP_DESC stRTVHeapDesc = {};
stRTVHeapDesc.NumDescriptors = nFrameBackBufCount;
stRTVHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
stRTVHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateDescriptorHeap(
&stRTVHeapDesc
, IID_PPV_ARGS( &pIRTVHeap ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIRTVHeap );
}
//创建RTV的描述符
{
D3D12_CPU_DESCRIPTOR_HANDLE stRTVHandle
= pIRTVHeap->GetCPUDescriptorHandleForHeapStart();
for ( UINT i = 0; i < nFrameBackBufCount; i++ )
{
GRS_THROW_IF_FAILED( pISwapChain3->GetBuffer( i
, IID_PPV_ARGS( &pIARenderTargets[i] ) ) );
GRS_SET_D3D12_DEBUGNAME_INDEXED_COMPTR( pIARenderTargets, i );
pID3D12Device4->CreateRenderTargetView( pIARenderTargets[i].Get()
, nullptr
, stRTVHandle );
stRTVHandle.ptr += nRTVDescriptorSize;
}
}
// 关闭ALT+ENTER键切换全屏的功能,因为我们没有实现OnSize处理,所以先关闭
// 注意将这个屏蔽Alt+Enter组合键的动作放到了这里,是因为直到这个时候DXGI Factory通过Create Swapchain动作才知道了HWND是哪个窗口
// 因为组合键的处理在Windows中都是基于窗口过程的,没有窗口句柄就不知道是哪个窗口以及窗口过程,之前的屏蔽就没有意义了
GRS_THROW_IF_FAILED( pIDXGIFactory6->MakeWindowAssociation( hWnd, DXGI_MWA_NO_ALT_ENTER ) );
}
// 7、创建深度缓冲及深度缓冲描述符堆
{
D3D12_DEPTH_STENCIL_VIEW_DESC stDepthStencilDesc = {};
stDepthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
stDepthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
stDepthStencilDesc.Flags = D3D12_DSV_FLAG_NONE;
D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT;
depthOptimizedClearValue.DepthStencil.Depth = 1.0f;
depthOptimizedClearValue.DepthStencil.Stencil = 0;
D3D12_HEAP_PROPERTIES stDSHeapProp = { };
stDSHeapProp.Type = D3D12_HEAP_TYPE_DEFAULT;
stDSHeapProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
stDSHeapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
stDSHeapProp.CreationNodeMask = 0;
stDSHeapProp.VisibleNodeMask = 0;
D3D12_RESOURCE_DESC stDSTex2DDesc = {};
stDSTex2DDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
stDSTex2DDesc.Alignment = 0;
stDSTex2DDesc.Width = iWidth;
stDSTex2DDesc.Height = iHeight;
stDSTex2DDesc.DepthOrArraySize = 1;
stDSTex2DDesc.MipLevels = 0;
stDSTex2DDesc.Format = DXGI_FORMAT_D32_FLOAT;
stDSTex2DDesc.SampleDesc.Count = 1;
stDSTex2DDesc.SampleDesc.Quality = 0;
stDSTex2DDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
stDSTex2DDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
//使用隐式默认堆创建一个深度蜡板缓冲区,
//因为基本上深度缓冲区会一直被使用,重用的意义不大,所以直接使用隐式堆,图方便
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommittedResource(
&stDSHeapProp
, D3D12_HEAP_FLAG_NONE
, &stDSTex2DDesc
, D3D12_RESOURCE_STATE_DEPTH_WRITE
, &depthOptimizedClearValue
, IID_PPV_ARGS( &pIDepthStencilBuffer )
) );
//==============================================================================================
D3D12_DESCRIPTOR_HEAP_DESC stDSVHeapDesc = {};
stDSVHeapDesc.NumDescriptors = 1;
stDSVHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
stDSVHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateDescriptorHeap( &stDSVHeapDesc, IID_PPV_ARGS( &pIDSVHeap ) ) );
pID3D12Device4->CreateDepthStencilView( pIDepthStencilBuffer.Get()
, &stDepthStencilDesc
, pIDSVHeap->GetCPUDescriptorHandleForHeapStart() );
}
// 8、创建围栏
{
GRS_THROW_IF_FAILED( pID3D12Device4->CreateFence( 0
, D3D12_FENCE_FLAG_NONE
, IID_PPV_ARGS( &pIFence ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIFence );
n64FenceValue = 1;
// 创建一个Event同步对象,用于等待围栏事件通知
hEventFence = CreateEvent( nullptr, FALSE, FALSE, nullptr );
if ( hEventFence == nullptr )
{
GRS_THROW_IF_FAILED( HRESULT_FROM_WIN32( GetLastError() ) );
}
}
// 9、编译Shader创建渲染管线状态对象
{
// 先创建根签名
D3D12_FEATURE_DATA_ROOT_SIGNATURE stFeatureData = {};
// 检测是否支持V1.1版本的根签名
stFeatureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;
if ( FAILED( pID3D12Device4->CheckFeatureSupport( D3D12_FEATURE_ROOT_SIGNATURE, &stFeatureData, sizeof( stFeatureData ) ) ) )
{
stFeatureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0;
}
D3D12_DESCRIPTOR_RANGE1 stDSPRanges1[3] = {};
stDSPRanges1[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
stDSPRanges1[0].NumDescriptors = 2;
stDSPRanges1[0].BaseShaderRegister = 0;
stDSPRanges1[0].RegisterSpace = 0;
stDSPRanges1[0].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
stDSPRanges1[0].OffsetInDescriptorsFromTableStart = 0;
// 在GPU上执行SetGraphicsRootDescriptorTable后,我们不修改命令列表中的SRV,因此我们可以使用默认Rang行为:
// D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC_WHILE_SET_AT_EXECUTE
stDSPRanges1[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
stDSPRanges1[1].NumDescriptors = 1;
stDSPRanges1[1].BaseShaderRegister = 0;
stDSPRanges1[1].RegisterSpace = 0;
stDSPRanges1[1].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
stDSPRanges1[1].OffsetInDescriptorsFromTableStart = 0;
stDSPRanges1[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
stDSPRanges1[2].NumDescriptors = 1;
stDSPRanges1[2].BaseShaderRegister = 0;
stDSPRanges1[2].RegisterSpace = 0;
stDSPRanges1[2].Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE;
stDSPRanges1[2].OffsetInDescriptorsFromTableStart = 0;
D3D12_ROOT_PARAMETER1 stRootParameters1[3] = {};
stRootParameters1[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
stRootParameters1[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
stRootParameters1[0].DescriptorTable.NumDescriptorRanges = 1;
stRootParameters1[0].DescriptorTable.pDescriptorRanges = &stDSPRanges1[0];
stRootParameters1[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
stRootParameters1[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
stRootParameters1[1].DescriptorTable.NumDescriptorRanges = 1;
stRootParameters1[1].DescriptorTable.pDescriptorRanges = &stDSPRanges1[1];
stRootParameters1[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
stRootParameters1[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
stRootParameters1[2].DescriptorTable.NumDescriptorRanges = 1;
stRootParameters1[2].DescriptorTable.pDescriptorRanges = &stDSPRanges1[2];
D3D12_VERSIONED_ROOT_SIGNATURE_DESC stRootSignatureDesc = {};
if ( D3D_ROOT_SIGNATURE_VERSION_1_1 == stFeatureData.HighestVersion )
{
stRootSignatureDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
stRootSignatureDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
stRootSignatureDesc.Desc_1_1.NumParameters = _countof( stRootParameters1 );
stRootSignatureDesc.Desc_1_1.pParameters = stRootParameters1;
stRootSignatureDesc.Desc_1_1.NumStaticSamplers = 0;
stRootSignatureDesc.Desc_1_1.pStaticSamplers = nullptr;
}
else
{
D3D12_DESCRIPTOR_RANGE stDSPRanges[3] = {};
stDSPRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
stDSPRanges[0].NumDescriptors = 2;
stDSPRanges[0].BaseShaderRegister = 0;
stDSPRanges[0].RegisterSpace = 0;
stDSPRanges[0].OffsetInDescriptorsFromTableStart = 0;
stDSPRanges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
stDSPRanges[1].NumDescriptors = 1;
stDSPRanges[1].BaseShaderRegister = 0;
stDSPRanges[1].RegisterSpace = 0;
stDSPRanges[1].OffsetInDescriptorsFromTableStart = 0;
stDSPRanges[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
stDSPRanges[2].NumDescriptors = 1;
stDSPRanges[2].BaseShaderRegister = 0;
stDSPRanges[2].RegisterSpace = 0;
stDSPRanges[2].OffsetInDescriptorsFromTableStart = 0;
D3D12_ROOT_PARAMETER stRootParameters[3] = {};
stRootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
stRootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
stRootParameters[0].DescriptorTable.NumDescriptorRanges = 1;
stRootParameters[0].DescriptorTable.pDescriptorRanges = &stDSPRanges[0];
stRootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
stRootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
stRootParameters[1].DescriptorTable.NumDescriptorRanges = 1;
stRootParameters[1].DescriptorTable.pDescriptorRanges = &stDSPRanges[1];
stRootParameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
stRootParameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
stRootParameters[2].DescriptorTable.NumDescriptorRanges = 1;
stRootParameters[2].DescriptorTable.pDescriptorRanges = &stDSPRanges[2];
stRootSignatureDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_0;
stRootSignatureDesc.Desc_1_0.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
stRootSignatureDesc.Desc_1_0.NumParameters = _countof( stRootParameters );
stRootSignatureDesc.Desc_1_0.pParameters = stRootParameters;
stRootSignatureDesc.Desc_1_0.NumStaticSamplers = 0;
stRootSignatureDesc.Desc_1_0.pStaticSamplers = nullptr;
}
ComPtr<ID3DBlob> pISignatureBlob;
ComPtr<ID3DBlob> pIErrorBlob;
HRESULT _hr = D3D12SerializeVersionedRootSignature( &stRootSignatureDesc
, &pISignatureBlob
, &pIErrorBlob );
if ( FAILED( _hr ) )
{
ATLTRACE( "Create Root Signature Error:%s\n", (CHAR*) pIErrorBlob->GetBufferPointer() );
AtlThrow( _hr );
}
GRS_THROW_IF_FAILED( pID3D12Device4->CreateRootSignature( 0
, pISignatureBlob->GetBufferPointer()
, pISignatureBlob->GetBufferSize()
, IID_PPV_ARGS( &pIRootSignature ) ) );
// 接着以函数方式编译Shader
UINT compileFlags = 0;
#if defined(_DEBUG)
// Enable better shader debugging with the graphics debugging tools.
compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
//编译为行矩阵形式
compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
TCHAR pszShaderFileName[MAX_PATH] = {};
StringCchPrintf( pszShaderFileName, MAX_PATH
, _T( "%s17-D3D12_Assimp_Animation\\Shader\\simple_bones_animation_multitex.hlsl" )
, g_pszAppPath );
ComPtr<ID3DBlob> pIErrorMsg;
HRESULT hr = D3DCompileFromFile( pszShaderFileName, nullptr, nullptr
, "VSMain", "vs_5_0", compileFlags, 0, &pIVSModel, &pIErrorMsg );
if ( FAILED( hr ) )
{
ATLTRACE( "编译 Vertex Shader:\"%s\" 发生错误:%s\n"
, T2A( pszShaderFileName )
, pIErrorMsg ? pIErrorMsg->GetBufferPointer() : "无法读取文件!" );
GRS_THROW_IF_FAILED( hr );
}
pIErrorMsg.Reset();
hr = D3DCompileFromFile( pszShaderFileName, nullptr, nullptr
, "PSMain", "ps_5_0", compileFlags, 0, &pIPSModel, &pIErrorMsg );
if ( FAILED( hr ) )
{
ATLTRACE( "编译 Pixel Shader:\"%s\" 发生错误:%s\n"
, T2A( pszShaderFileName )
, pIErrorMsg ? pIErrorMsg->GetBufferPointer() : "无法读取文件!" );
GRS_THROW_IF_FAILED( hr );
}
// 我们多添加了一个法线的定义,但目前Shader中我们并没有使用
D3D12_INPUT_ELEMENT_DESC stIALayoutSphere[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 2, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "BLENDINDICES", 0, DXGI_FORMAT_R32G32B32A32_UINT, 3, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "BLENDWEIGHT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 3, 16, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
};
// 创建 graphics pipeline state object (PSO)对象
D3D12_GRAPHICS_PIPELINE_STATE_DESC stPSODesc = {};
stPSODesc.InputLayout = { stIALayoutSphere, _countof( stIALayoutSphere ) };
stPSODesc.pRootSignature = pIRootSignature.Get();
stPSODesc.VS.pShaderBytecode = pIVSModel->GetBufferPointer();
stPSODesc.VS.BytecodeLength = pIVSModel->GetBufferSize();
stPSODesc.PS.pShaderBytecode = pIPSModel->GetBufferPointer();
stPSODesc.PS.BytecodeLength = pIPSModel->GetBufferSize();
stPSODesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
stPSODesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
stPSODesc.BlendState.AlphaToCoverageEnable = FALSE;
stPSODesc.BlendState.IndependentBlendEnable = FALSE;
stPSODesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
stPSODesc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
stPSODesc.DepthStencilState.DepthEnable = TRUE;
stPSODesc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;//启用深度缓存写入功能
stPSODesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS; //深度测试函数(该值为普通的深度测试)
stPSODesc.DepthStencilState.StencilEnable = FALSE;
stPSODesc.SampleMask = UINT_MAX;
stPSODesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
stPSODesc.NumRenderTargets = 1;
stPSODesc.RTVFormats[0] = emRenderTargetFormat;
stPSODesc.SampleDesc.Count = 1;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateGraphicsPipelineState( &stPSODesc
, IID_PPV_ARGS( &pIPSOModel ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIPSOModel );
// 网格化显示的渲染管线
stPSODesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateGraphicsPipelineState( &stPSODesc
, IID_PPV_ARGS( &pIPSOWireFrame ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIPSOWireFrame );
}
// 10、创建 SRV CBV Sample堆
{
//将纹理视图描述符和CBV描述符放在一个描述符堆上
D3D12_DESCRIPTOR_HEAP_DESC stSRVHeapDesc = {};
UINT nTextureCount = (UINT) g_stMeshData.m_mapTextrueName2Index.GetCount();
stSRVHeapDesc.NumDescriptors = 2 + ( ( nTextureCount > 0 ) ? nTextureCount : 1 ); // 2 CBV + n SRV
stSRVHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
stSRVHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateDescriptorHeap( &stSRVHeapDesc, IID_PPV_ARGS( &pICBVSRVHeap ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pICBVSRVHeap );
D3D12_DESCRIPTOR_HEAP_DESC stSamplerHeapDesc = {};
stSamplerHeapDesc.NumDescriptors = 1;
stSamplerHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
stSamplerHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateDescriptorHeap( &stSamplerHeapDesc, IID_PPV_ARGS( &pISamplerHeap ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pISamplerHeap );
}
// 11、创建D3D12的模型资源,并复制数据
{
// 计算所有的缓冲大小
size_t szPositions = g_stMeshData.m_arPositions.GetCount() * sizeof( g_stMeshData.m_arPositions[0] );
size_t szNormals = g_stMeshData.m_arNormals.GetCount() * sizeof( g_stMeshData.m_arNormals[0] );
size_t szTexCoords = g_stMeshData.m_arTexCoords.GetCount() * sizeof( g_stMeshData.m_arTexCoords[0] );
size_t szBoneIndices = g_stMeshData.m_arBoneIndices.GetCount() * sizeof( g_stMeshData.m_arBoneIndices[0] );
size_t szIndices = g_stMeshData.m_arIndices.GetCount() * sizeof( g_stMeshData.m_arIndices[0] );
// 需要的缓冲大小+64k-1 使得刚好是64k边界大小时,可以多分配64k出来,防止CreatePlacedResource报错
size_t szVBBuffer = szPositions + szNormals + szTexCoords + szBoneIndices + D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT - 1;
// 注意对齐边界必须是4的倍数,比5大4的倍数是8
size_t szAlign = 4 * D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
// 创建上传堆
D3D12_HEAP_DESC stUploadHeapDesc = { };
// 实际数据大小的5*64K边界对齐大小,因为有5个Buffer
stUploadHeapDesc.SizeInBytes = GRS_UPPER( szVBBuffer, szAlign );
// 注意上传堆肯定是Buffer类型,可以不指定对齐方式,其默认是64k边界对齐
stUploadHeapDesc.Alignment = 0;
stUploadHeapDesc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD; //上传堆类型
stUploadHeapDesc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
stUploadHeapDesc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
// 上传堆就是缓冲,可以摆放任意数据
stUploadHeapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
GRS_THROW_IF_FAILED( pID3D12Device4->CreateHeap( &stUploadHeapDesc, IID_PPV_ARGS( &pIUploadHeapModel ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIUploadHeapModel );
size_t szOffset = 0;
BYTE* pData = nullptr;
D3D12_RESOURCE_DESC stUploadBufferDesc = {};
stUploadBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
stUploadBufferDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
stUploadBufferDesc.Width = GRS_UPPER( szPositions, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
stUploadBufferDesc.Height = 1;
stUploadBufferDesc.DepthOrArraySize = 1;
stUploadBufferDesc.MipLevels = 1;
stUploadBufferDesc.Format = DXGI_FORMAT_UNKNOWN;
stUploadBufferDesc.SampleDesc.Count = 1;
stUploadBufferDesc.SampleDesc.Quality = 0;
stUploadBufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
stUploadBufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
// Positions Upload Buffer
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIUploadHeapModel.Get()
, szOffset
, &stUploadBufferDesc
, D3D12_RESOURCE_STATE_GENERIC_READ
, nullptr
, IID_PPV_ARGS( &pIVBPositionsUp ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIVBPositionsUp );
GRS_THROW_IF_FAILED( pIVBPositionsUp->Map( 0, nullptr, reinterpret_cast<void**>( &pData ) ) );
// 第一次 Copy!CPU Memory -> Share Memory 实质上就是在内存中倒腾,只是物理地址不同
// 估计会有那么一天,这个Copy动作可能被简单替换为CPU物理地址映射的变更,传说Vulkan中已经大致是这样了
memcpy( pData, g_stMeshData.m_arPositions.GetData(), szPositions );
pIVBPositionsUp->Unmap( 0, nullptr );
pData = nullptr;
// Normals Upload Buffer
szOffset += stUploadBufferDesc.Width;
stUploadBufferDesc.Width = GRS_UPPER( szNormals, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIUploadHeapModel.Get()
, szOffset
, &stUploadBufferDesc
, D3D12_RESOURCE_STATE_GENERIC_READ
, nullptr
, IID_PPV_ARGS( &pIVBNormalsUp ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIVBNormalsUp );
GRS_THROW_IF_FAILED( pIVBNormalsUp->Map( 0, nullptr, reinterpret_cast<void**>( &pData ) ) );
// 第一次 Copy!CPU Memory -> Share Memory 实质上就是在内存中倒腾,只是物理地址不同
// 估计会有那么一天,这个Copy动作可能被简单替换为CPU物理地址映射的变更,传说Vulkan中已经大致是这样了
memcpy( pData, g_stMeshData.m_arNormals.GetData(), szNormals );
pIVBNormalsUp->Unmap( 0, nullptr );
pData = nullptr;
// TexCoords Upload Buffer
szOffset += stUploadBufferDesc.Width;
stUploadBufferDesc.Width = GRS_UPPER( szTexCoords, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIUploadHeapModel.Get()
, szOffset
, &stUploadBufferDesc
, D3D12_RESOURCE_STATE_GENERIC_READ
, nullptr
, IID_PPV_ARGS( &pIVBTexCoordsUp ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIVBTexCoordsUp );
GRS_THROW_IF_FAILED( pIVBTexCoordsUp->Map( 0, nullptr, reinterpret_cast<void**>( &pData ) ) );
// 第一次 Copy!CPU Memory -> Share Memory 实质上就是在内存中倒腾,只是物理地址不同
// 估计会有那么一天,这个Copy动作可能被简单替换为CPU物理地址映射的变更,传说Vulkan中已经大致是这样了
memcpy( pData, g_stMeshData.m_arTexCoords.GetData(), szTexCoords );
pIVBTexCoordsUp->Unmap( 0, nullptr );
pData = nullptr;
// Bone Indices Upload Buffer
szOffset += stUploadBufferDesc.Width;
stUploadBufferDesc.Width = GRS_UPPER( szBoneIndices, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIUploadHeapModel.Get()
, szOffset
, &stUploadBufferDesc
, D3D12_RESOURCE_STATE_GENERIC_READ
, nullptr
, IID_PPV_ARGS( &pIVBBoneIndicesUp ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIVBBoneIndicesUp );
GRS_THROW_IF_FAILED( pIVBBoneIndicesUp->Map( 0, nullptr, reinterpret_cast<void**>( &pData ) ) );
// 第一次 Copy!CPU Memory -> Share Memory 实质上就是在内存中倒腾,只是物理地址不同
// 估计会有那么一天,这个Copy动作可能被简单替换为CPU物理地址映射的变更,传说Vulkan中已经大致是这样了
memcpy( pData, g_stMeshData.m_arBoneIndices.GetData(), szBoneIndices );
pIVBBoneIndicesUp->Unmap( 0, nullptr );
pData = nullptr;
// 创建默认堆(显存中的堆)
D3D12_HEAP_DESC stDefaultHeapDesc = {};
// 大小跟上传堆一样
stDefaultHeapDesc.SizeInBytes = GRS_UPPER( szVBBuffer, szAlign );
// 指定堆的对齐方式,这里使用了默认的64K边界对齐,因为这里实际放的是顶点数据
stDefaultHeapDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
stDefaultHeapDesc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; //默认堆类型
stDefaultHeapDesc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
stDefaultHeapDesc.Properties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
// 只是用来摆放普通的缓冲
stDefaultHeapDesc.Flags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
// Vertex Data Default Heap
GRS_THROW_IF_FAILED( pID3D12Device4->CreateHeap( &stDefaultHeapDesc, IID_PPV_ARGS( &pIDefaultHeapModel ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIDefaultHeapModel );
D3D12_RESOURCE_DESC stDefaultBufferDesc = {};
szOffset = 0;
stDefaultBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
stDefaultBufferDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
stDefaultBufferDesc.Width = GRS_UPPER( szPositions, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
stDefaultBufferDesc.Height = 1;
stDefaultBufferDesc.DepthOrArraySize = 1;
stDefaultBufferDesc.MipLevels = 1;
stDefaultBufferDesc.Format = DXGI_FORMAT_UNKNOWN;
stDefaultBufferDesc.SampleDesc.Count = 1;
stDefaultBufferDesc.SampleDesc.Quality = 0;
stDefaultBufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
stDefaultBufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
D3D12_RESOURCE_BARRIER stBufferBarrier = {};
stBufferBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
stBufferBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
stBufferBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
stBufferBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
stBufferBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
// Positions Default Buffer
szOffset = 0;
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIDefaultHeapModel.Get()
, szOffset
, &stDefaultBufferDesc
, D3D12_RESOURCE_STATE_COPY_DEST
, nullptr
, IID_PPV_ARGS( &pIVBPositions ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIVBPositions );
// 第二次Copy!独显的时候:Share Memory -> Video Memory
// 这里只是记录个复制命令,之后会在Copy Engine上Excute
pICopyCMDList->CopyBufferRegion( pIVBPositions.Get(), 0, pIVBPositionsUp.Get(), 0, szPositions );
// 然后加入个资源屏障,同步! 并确认复制操作完成
stBufferBarrier.Transition.pResource = pIVBPositions.Get();
pICopyCMDList->ResourceBarrier( 1, &stBufferBarrier );
// Normals Default Buffer
szOffset += stDefaultBufferDesc.Width;
stDefaultBufferDesc.Width = GRS_UPPER( szNormals, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIDefaultHeapModel.Get()
, szOffset
, &stDefaultBufferDesc
, D3D12_RESOURCE_STATE_COPY_DEST
, nullptr
, IID_PPV_ARGS( &pIVBNormals ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIVBNormals );
// 第二次Copy!独显的时候:Share Memory -> Video Memory
// 这里只是记录个复制命令,之后会在Copy Engine上Excute
pICopyCMDList->CopyBufferRegion( pIVBNormals.Get(), 0, pIVBNormalsUp.Get(), 0, szNormals );
// 然后加入个资源屏障,同步! 并确认复制操作完成
stBufferBarrier.Transition.pResource = pIVBNormals.Get();
pICopyCMDList->ResourceBarrier( 1, &stBufferBarrier );
// TexCoords Default Buffer
szOffset += stDefaultBufferDesc.Width;
stDefaultBufferDesc.Width = GRS_UPPER( szTexCoords, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIDefaultHeapModel.Get()
, szOffset
, &stDefaultBufferDesc
, D3D12_RESOURCE_STATE_COPY_DEST
, nullptr
, IID_PPV_ARGS( &pIVBTexCoords ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIVBTexCoords );
// 第二次Copy!独显的时候:Share Memory -> Video Memory
// 这里只是记录个复制命令,之后会在Copy Engine上Excute
pICopyCMDList->CopyBufferRegion( pIVBTexCoords.Get(), 0, pIVBTexCoordsUp.Get(), 0, szTexCoords );
// 然后加入个资源屏障,同步! 并确认复制操作完成
stBufferBarrier.Transition.pResource = pIVBTexCoords.Get();
pICopyCMDList->ResourceBarrier( 1, &stBufferBarrier );
// Bone Indices Default Buffer
szOffset += stDefaultBufferDesc.Width;
stDefaultBufferDesc.Width = GRS_UPPER( szBoneIndices, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIDefaultHeapModel.Get()
, szOffset
, &stDefaultBufferDesc
, D3D12_RESOURCE_STATE_COPY_DEST
, nullptr
, IID_PPV_ARGS( &pIVBBoneIndices ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIVBBoneIndices );
// 第二次Copy!独显的时候:Share Memory -> Video Memory
// 这里只是记录个复制命令,之后会在Copy Engine上Excute
pICopyCMDList->CopyBufferRegion( pIVBBoneIndices.Get(), 0, pIVBBoneIndicesUp.Get(), 0, szBoneIndices );
// 然后加入个资源屏障,同步! 并确认复制操作完成
stBufferBarrier.Transition.pResource = pIVBBoneIndices.Get();
pICopyCMDList->ResourceBarrier( 1, &stBufferBarrier );
// Positions Buffer View
staVBV[0].BufferLocation = pIVBPositions->GetGPUVirtualAddress();
staVBV[0].SizeInBytes = (UINT) szPositions;
staVBV[0].StrideInBytes = sizeof( g_stMeshData.m_arPositions[0] );
// Normals Buffer View
staVBV[1].BufferLocation = pIVBNormals->GetGPUVirtualAddress();
staVBV[1].SizeInBytes = (UINT) szNormals;
staVBV[1].StrideInBytes = sizeof( g_stMeshData.m_arNormals[0] );
// TexCoords Buffer View
staVBV[2].BufferLocation = pIVBTexCoords->GetGPUVirtualAddress();
staVBV[2].SizeInBytes = (UINT) szTexCoords;
staVBV[2].StrideInBytes = sizeof( g_stMeshData.m_arTexCoords[0] );
// BoneIndices Buffer View
staVBV[3].BufferLocation = pIVBBoneIndices->GetGPUVirtualAddress();
staVBV[3].SizeInBytes = (UINT) szBoneIndices;
staVBV[3].StrideInBytes = sizeof( g_stMeshData.m_arBoneIndices[0] );
// Indices Upload Buffer
// Indices 上传堆
stUploadHeapDesc.SizeInBytes = GRS_UPPER( szIndices, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreateHeap( &stUploadHeapDesc, IID_PPV_ARGS( &pIUploadHeapIndices ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIUploadHeapIndices );
stUploadBufferDesc.Width = GRS_UPPER( szIndices, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIUploadHeapIndices.Get()
, 0
, &stUploadBufferDesc
, D3D12_RESOURCE_STATE_GENERIC_READ
, nullptr
, IID_PPV_ARGS( &pIIBIndicesUp ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIIBIndicesUp );
GRS_THROW_IF_FAILED( pIIBIndicesUp->Map( 0, nullptr, reinterpret_cast<void**>( &pData ) ) );
// 第一次 Copy!CPU Memory -> Share Memory 实质上就是在内存中倒腾,只是物理地址不同
// 估计会有那么一天,这个Copy动作可能被简单替换为CPU物理地址映射的变更,传说Vulkan中已经大致是这样了
memcpy( pData, g_stMeshData.m_arIndices.GetData(), szIndices );
pIIBIndicesUp->Unmap( 0, nullptr );
pData = nullptr;
// Indices Default Buffer
// Indices Data Default Heap
stDefaultHeapDesc.SizeInBytes = GRS_UPPER( szIndices, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreateHeap( &stDefaultHeapDesc, IID_PPV_ARGS( &pIDefaultHeapIndices ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIDefaultHeapIndices );
stDefaultBufferDesc.Width = GRS_UPPER( szIndices, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreatePlacedResource(
pIDefaultHeapIndices.Get()
, 0
, &stDefaultBufferDesc
, D3D12_RESOURCE_STATE_COPY_DEST
, nullptr
, IID_PPV_ARGS( &pIIBIndices ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pIIBIndices );
// 第二次Copy!独显的时候:Share Memory -> Video Memory
// 这里只是记录个复制命令,之后会在Copy Engine上Excute
pICopyCMDList->CopyBufferRegion( pIIBIndices.Get(), 0, pIIBIndicesUp.Get(), 0, szIndices );
// 然后加入个资源屏障,同步! 并确认复制操作完成
stBufferBarrier.Transition.pResource = pIIBIndices.Get();
pICopyCMDList->ResourceBarrier( 1, &stBufferBarrier );
// Indices Buffer View
stIBV.BufferLocation = pIIBIndices->GetGPUVirtualAddress();
stIBV.SizeInBytes = (UINT) szIndices;
// 32bit ? 16bit Index
stIBV.Format = ( sizeof( g_stMeshData.m_arIndices[0] ) > 2 ) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
// Const Buffers
D3D12_HEAP_PROPERTIES stUploadHeapProp = { };
stUploadHeapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
stUploadHeapProp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
stUploadHeapProp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
stUploadHeapProp.CreationNodeMask = 0;
stUploadHeapProp.VisibleNodeMask = 0;
D3D12_RESOURCE_DESC stConstBufferDesc = {};
stConstBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
stConstBufferDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
stConstBufferDesc.Width = GRS_UPPER( sizeof( ST_GRS_CB_MVP ), D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
stConstBufferDesc.Height = 1;
stConstBufferDesc.DepthOrArraySize = 1;
stConstBufferDesc.MipLevels = 1;
stConstBufferDesc.Format = DXGI_FORMAT_UNKNOWN;
stConstBufferDesc.SampleDesc.Count = 1;
stConstBufferDesc.SampleDesc.Quality = 0;
stConstBufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
stConstBufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
// MVP Const Buffer
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommittedResource(
&stUploadHeapProp
, D3D12_HEAP_FLAG_NONE
, &stConstBufferDesc //注意缓冲尺寸设置为256边界对齐大小
, D3D12_RESOURCE_STATE_GENERIC_READ
, nullptr
, IID_PPV_ARGS( &pICBMVP ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pICBMVP );
// Map 之后就不再Unmap了 直接复制数据进去 这样每帧都不用map-copy-unmap浪费时间了
GRS_THROW_IF_FAILED( pICBMVP->Map( 0, nullptr, reinterpret_cast<void**>( &pstCBMVP ) ) );
// Bones Const Buffer
stConstBufferDesc.Width = GRS_UPPER( sizeof( ST_GRS_CB_BONES ), D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT );
GRS_THROW_IF_FAILED( pID3D12Device4->CreateCommittedResource(
&stUploadHeapProp
, D3D12_HEAP_FLAG_NONE
, &stConstBufferDesc //注意缓冲尺寸设置为256边界对齐大小
, D3D12_RESOURCE_STATE_GENERIC_READ
, nullptr
, IID_PPV_ARGS( &pICBBones ) ) );
GRS_SET_D3D12_DEBUGNAME_COMPTR( pICBBones );
// Map 之后就不再Unmap了 直接复制数据进去 这样每帧都不用map-copy-unmap浪费时间了
GRS_THROW_IF_FAILED( pICBBones->Map( 0, nullptr, reinterpret_cast<void**>( &pstBones ) ) );
// Create Const Buffer View
D3D12_CPU_DESCRIPTOR_HANDLE stCBVHandle = { pICBVSRVHeap->GetCPUDescriptorHandleForHeapStart() };
// 创建第一个CBV 世界矩阵 视矩阵 透视矩阵
size_t szBufferViewAlign = 256;
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
cbvDesc.BufferLocation = pICBMVP->GetGPUVirtualAddress();
cbvDesc.SizeInBytes = (UINT) GRS_UPPER( sizeof( ST_GRS_CB_MVP ), szBufferViewAlign );
pID3D12Device4->CreateConstantBufferView( &cbvDesc, stCBVHandle );
stCBVHandle.ptr += nCBVSRVDescriptorSize;
// 创建第二个CBV 骨头调色板
cbvDesc.BufferLocation = pICBBones->GetGPUVirtualAddress();
cbvDesc.SizeInBytes = (UINT) GRS_UPPER( sizeof( ST_GRS_CB_BONES ), szBufferViewAlign );
pID3D12Device4->CreateConstantBufferView( &cbvDesc, stCBVHandle );
}
// 12、加载纹理
{
// 从模型文件所在路径计算纹理文件
WCHAR pszModelPath[MAX_PATH] = {};
StringCchCopyW( pszModelPath, MAX_PATH, A2W( g_stMeshData.m_strFileName ) );
WCHAR* lastSlash = _tcsrchr( pszModelPath, _T( '\\' ) );
if ( lastSlash )
{//删除Exe文件名
*( lastSlash ) = _T( '\0' );
}
//使用WIC类厂对象接口加载纹理图片,并得到一个WIC解码器对象接口,图片信息就在这个接口代表的对象中了
WCHAR pszTexcuteFileName[MAX_PATH] = {};
ID3D12Resource* pITex = nullptr;
ID3D12Resource* pITexUp = nullptr;
D3D12_SHADER_RESOURCE_VIEW_DESC stSRVDesc = {};
stSRVDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
stSRVDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
stSRVDesc.Texture2D.MipLevels = 1;
D3D12_CPU_DESCRIPTOR_HANDLE stSRVHandle = { pICBVSRVHeap->GetCPUDescriptorHandleForHeapStart() };
// 堆上第三个开始是纹理的SRV
stSRVHandle.ptr += (size_t) 2 * nCBVSRVDescriptorSize;
//stMeshData.m_mapIndex2TextureName.SetAt(i, strTextureFileName);
if ( g_stMeshData.m_mapTextrueName2Index.GetCount() <= 0 )
{// 当纹理不存在时加载默认纹理
StringCchPrintfW( pszTexcuteFileName
, MAX_PATH
, L"D:\\Projects_2018_08\\GRSD3D12Samples\\Assimp_Study\\asset\\default.jpg" );
g_stMeshData.m_mapTextrueName2Index.SetAt( W2A( pszTexcuteFileName ), 0 );
}
POSITION pos;
CStringA strTextureName;
UINT nTextureIndex = 0;
pos = g_stMeshData.m_mapTextrueName2Index.GetStartPosition();
while ( nullptr != pos )
{
strTextureName = g_stMeshData.m_mapTextrueName2Index.GetKeyAt( pos );
nTextureIndex = g_stMeshData.m_mapTextrueName2Index.GetNextValue( pos );
StringCchPrintfW( pszTexcuteFileName, MAX_PATH, L"%s\\%s", pszModelPath, A2W( strTextureName ) );
if ( ( INVALID_FILE_ATTRIBUTES == ::GetFileAttributes( pszTexcuteFileName ) ) )
{// 当纹理不存在或者找不到纹理时加载默认纹理
StringCchPrintfW( pszTexcuteFileName
, MAX_PATH
, L"D:\\Projects_2018_08\\GRSD3D12Samples\\Assimp_Study\\asset\\default.jpg" );
}
ATLTRACE( _T( "加载纹理:\"%s\"\n" ), pszTexcuteFileName );
if ( !LoadTextureFromFile( pszTexcuteFileName, pICopyCMDList.Get(), pITexUp, pITex ) )
{
ATLTRACE( _T( "纹理:\"%s\" 加载失败!\n" ), pszTexcuteFileName );
AtlThrowLastWin32();
}
arTexture.Add( ComPtr<ID3D12Resource>( pITex ) );
arTextureUp.Add( ComPtr<ID3D12Resource>( pITexUp ) );
GRS_SetD3D12DebugNameIndexed( pITex, L"pITex", nTextureIndex );
GRS_SetD3D12DebugNameIndexed( pITexUp, L"pITex", nTextureIndex );
stSRVDesc.Format = pITex->GetDesc().Format;
D3D12_CPU_DESCRIPTOR_HANDLE stSRVHandleTmp = stSRVHandle;
stSRVHandleTmp.ptr += nTextureIndex * nCBVSRVDescriptorSize;
pID3D12Device4->CreateShaderResourceView( pITex, &stSRVDesc, stSRVHandleTmp );
}
// Create Sample
D3D12_CPU_DESCRIPTOR_HANDLE hSamplerHeap = pISamplerHeap->GetCPUDescriptorHandleForHeapStart();
D3D12_SAMPLER_DESC stSamplerDesc = {};
stSamplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
stSamplerDesc.MinLOD = 0;
stSamplerDesc.MaxLOD = D3D12_FLOAT32_MAX;
stSamplerDesc.MipLODBias = 0.0f;
stSamplerDesc.MaxAnisotropy = 1;
stSamplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
// Sampler 1
stSamplerDesc.BorderColor[0] = 1.0f;
stSamplerDesc.BorderColor[1] = 1.0f;
stSamplerDesc.BorderColor[2] = 1.0f;
stSamplerDesc.BorderColor[3] = 1.0f;
stSamplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
stSamplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
stSamplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
pID3D12Device4->CreateSampler( &stSamplerDesc, hSamplerHeap );
}
// 13、上传
{
GRS_THROW_IF_FAILED( pICopyCMDList->Close() );
//执行命令列表
ID3D12CommandList* ppCommandLists[] = { pICopyCMDList.Get() };
pICopyCMDQueue->ExecuteCommandLists( _countof( ppCommandLists ), ppCommandLists );
//开始同步GPU与CPU的执行,先记录围栏标记值
const UINT64 n64CurrentFenceValue = n64FenceValue;
GRS_THROW_IF_FAILED( pICopyCMDQueue->Signal( pIFence.Get(), n64CurrentFenceValue ) );
n64FenceValue++;
GRS_THROW_IF_FAILED( pIFence->SetEventOnCompletion( n64CurrentFenceValue, hEventFence ) );
}
// 14、填充资源屏障结构
{
stBeginResBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
stBeginResBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
stBeginResBarrier.Transition.pResource = pIARenderTargets[nFrameIndex].Get();
stBeginResBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
stBeginResBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
stBeginResBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
stEneResBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
stEneResBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
stEneResBarrier.Transition.pResource = pIARenderTargets[nFrameIndex].Get();
stEneResBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
stEneResBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
stEneResBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
}
DWORD dwRet = 0;
BOOL bExit = FALSE;
D3D12_CPU_DESCRIPTOR_HANDLE stRTVHandle = pIRTVHeap->GetCPUDescriptorHandleForHeapStart();
D3D12_CPU_DESCRIPTOR_HANDLE stDSVHandle = pIDSVHeap->GetCPUDescriptorHandleForHeapStart();
GRS_THROW_IF_FAILED( pIMainCMDList->Close() );
FLOAT fStartTime = ( FLOAT )::GetTickCount64();
FLOAT fCurrentTime = fStartTime;
FLOAT fTimeInSeconds = ( fCurrentTime - fStartTime ) / 1000.0f;
CGRSARMatrix arBoneMatrixs;
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
// 16、消息循环
while ( !bExit )
{
dwRet = ::MsgWaitForMultipleObjects( 1, &hEventFence, FALSE, INFINITE, QS_ALLINPUT );
switch ( dwRet - WAIT_OBJECT_0 )
{
case 0:
{
//-----------------------------------------------------------------------------------------------------
// OnUpdate()
// Animation Calculate
if ( g_stMeshData.m_paiModel->HasAnimations() )
{
fCurrentTime = ( FLOAT )::GetTickCount64();
//fTimeInSeconds = (fCurrentTime - fStartTime) / 1000.0f;
fTimeInSeconds = ( fCurrentTime - fStartTime ) / 5.0f;
arBoneMatrixs.RemoveAll();
CalcAnimation( g_stMeshData, fTimeInSeconds, arBoneMatrixs );
memcpy( pstBones->mxBones, arBoneMatrixs.GetData(), arBoneMatrixs.GetCount() * sizeof( arBoneMatrixs[0] ) );
}
// Model Matrix
// 1 -------------------------
// 先绕x轴旋转
//XMMATRIX mxModel = XMMatrixRotationX(-XM_2PI / 4.0f);
//// 再向上移动
//float fyUp = g_stMeshData.m_paiModel->mMeshes[0]->mAABB.mMax.y - g_stMeshData.m_paiModel->mMeshes[0]->mAABB.mMin.y;
//float fzBack = g_stMeshData.m_paiModel->mMeshes[0]->mAABB.mMax.z - g_stMeshData.m_paiModel->mMeshes[0]->mAABB.mMin.z;
//mxModel = XMMatrixMultiply(mxModel, XMMatrixTranslation(0.0f, fyUp, fzBack));
// 2 -------------------------
//XMMATRIX mxModel = g_stMeshData.m_mxModel;
// 3 -------------------------
// Model Matrix (这里只是进行缩放)
XMMATRIX mxModel = XMMatrixScaling( g_fScaling, g_fScaling, g_fScaling );
// World Matrix
XMMATRIX mxWorld = XMMatrixIdentity();
mxWorld = XMMatrixMultiply( mxModel, mxWorld );
XMStoreFloat4x4( &pstCBMVP->mxWorld, mxWorld );
// View Matrix
XMMATRIX mxView = XMMatrixLookAtLH( g_v4EyePos, g_v4LookAt, g_v4UpDir );
XMStoreFloat4x4( &pstCBMVP->mxView, mxView );
// Projection Matrix
XMMATRIX mxProjection = XMMatrixPerspectiveFovLH( XM_PIDIV4, (FLOAT) iWidth / (FLOAT) iHeight, 0.1f, 1000.0f );
XMStoreFloat4x4( &pstCBMVP->mxProjection, mxProjection );
// View Matrix * Projection Matrix
XMMATRIX mxViewProj = XMMatrixMultiply( mxView, mxProjection );
XMStoreFloat4x4( &pstCBMVP->mxViewProj, mxViewProj );
// World Matrix * View Matrix * Projection Matrix
XMMATRIX mxMVP = XMMatrixMultiply( mxWorld, mxViewProj );
XMStoreFloat4x4( &pstCBMVP->mxMVP, mxMVP );
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
// OnRender()
//-----------------------------------------------------------------------------------------------------
//命令分配器先Reset一下
GRS_THROW_IF_FAILED( pIMainCMDAlloc->Reset() );
//Reset命令列表,并重新指定命令分配器和PSO对象
if ( g_bWireFrame )
{// 网格化显示
GRS_THROW_IF_FAILED( pIMainCMDList->Reset( pIMainCMDAlloc.Get(), pIPSOWireFrame.Get() ) );
}
else
{
GRS_THROW_IF_FAILED( pIMainCMDList->Reset( pIMainCMDAlloc.Get(), pIPSOModel.Get() ) );
}
nFrameIndex = pISwapChain3->GetCurrentBackBufferIndex();
pIMainCMDList->RSSetViewports( 1, &stViewPort );
pIMainCMDList->RSSetScissorRects( 1, &stScissorRect );
// 通过资源屏障判定后缓冲已经切换完毕可以开始渲染了
stBeginResBarrier.Transition.pResource = pIARenderTargets[nFrameIndex].Get();
pIMainCMDList->ResourceBarrier( 1, &stBeginResBarrier );
//开始记录命令
stRTVHandle = pIRTVHeap->GetCPUDescriptorHandleForHeapStart();
stRTVHandle.ptr += (size_t) nFrameIndex * nRTVDescriptorSize;
//设置渲染目标
pIMainCMDList->OMSetRenderTargets( 1, &stRTVHandle, FALSE, &stDSVHandle );
// 继续记录命令,并真正开始新一帧的渲染
pIMainCMDList->ClearRenderTargetView( stRTVHandle, faClearColor, 0, nullptr );
pIMainCMDList->ClearDepthStencilView( pIDSVHeap->GetCPUDescriptorHandleForHeapStart()
, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr );
// 渲染物体
pIMainCMDList->SetGraphicsRootSignature( pIRootSignature.Get() );
// 注意我们使用的渲染手法是三角形列表,也就是通常的Mesh网格
pIMainCMDList->IASetPrimitiveTopology( D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
// Multi Input Slot 第一种方式 IASetVertexBuffers
pIMainCMDList->IASetVertexBuffers( 0, g_ncSlotCnt, staVBV );
// Multi Input Slot 第二种方式 IASetVertexBuffers
//for (UINT i = 0; i < g_ncSlotCnt; i++)
//{
// pIMainCMDList->IASetVertexBuffers(i, 1, &staVBV[i]);
//}
pIMainCMDList->IASetIndexBuffer( &stIBV );
ID3D12DescriptorHeap* ppHeaps[] = { pICBVSRVHeap.Get(),pISamplerHeap.Get() };
pIMainCMDList->SetDescriptorHeaps( _countof( ppHeaps ), ppHeaps );
D3D12_GPU_DESCRIPTOR_HANDLE stGPUSRVHandle = { pICBVSRVHeap->GetGPUDescriptorHandleForHeapStart() };
// 设置CBV
pIMainCMDList->SetGraphicsRootDescriptorTable( 0, stGPUSRVHandle );
// 设置SRV
stGPUSRVHandle.ptr += ( 2 * nCBVSRVDescriptorSize );
//pIMainCMDList->SetGraphicsRootDescriptorTable(1, stGPUSRVHandle);
// 设置Sample
pIMainCMDList->SetGraphicsRootDescriptorTable( 2, pISamplerHeap->GetGPUDescriptorHandleForHeapStart() );
// Draw Call
for ( UINT i = 0; i < g_stMeshData.m_arSubMeshInfo.GetCount(); i++ )
{
UINT nHeapIndex = 0;
D3D12_GPU_DESCRIPTOR_HANDLE stHSRV = stGPUSRVHandle;
if ( g_stMeshData.m_mapTextureIndex2HeapIndex.Lookup( g_stMeshData.m_arSubMeshInfo[i].m_nMaterialIndex, nHeapIndex ) )
{
stHSRV.ptr += ( (size_t) nHeapIndex * nCBVSRVDescriptorSize );
}
pIMainCMDList->SetGraphicsRootDescriptorTable( 1, stHSRV );
pIMainCMDList->DrawIndexedInstanced( g_stMeshData.m_arSubMeshInfo[i].m_nNumIndices
, 1
, g_stMeshData.m_arSubMeshInfo[i].m_nBaseIndex
, g_stMeshData.m_arSubMeshInfo[i].m_nBaseVertex
, 0 );
}
//pIMainCMDList->DrawIndexedInstanced(g_stMeshData.m_arSubMeshInfo[0].m_nNumIndices
// , 1
// , g_stMeshData.m_arSubMeshInfo[0].m_nBaseIndex
// , g_stMeshData.m_arSubMeshInfo[0].m_nBaseVertex
// , 0);
//又一个资源屏障,用于确定渲染已经结束可以提交画面去显示了
stEneResBarrier.Transition.pResource = pIARenderTargets[nFrameIndex].Get();
pIMainCMDList->ResourceBarrier( 1, &stEneResBarrier );
//关闭命令列表,可以去执行了
GRS_THROW_IF_FAILED( pIMainCMDList->Close() );
//执行命令列表
ID3D12CommandList* ppCommandLists[] = { pIMainCMDList.Get() };
pIMainCMDQueue->ExecuteCommandLists( _countof( ppCommandLists ), ppCommandLists );
//提交画面
GRS_THROW_IF_FAILED( pISwapChain3->Present( 1, 0 ) );
//开始同步GPU与CPU的执行,先记录围栏标记值
const UINT64 n64CurrentFenceValue = n64FenceValue;
GRS_THROW_IF_FAILED( pIMainCMDQueue->Signal( pIFence.Get(), n64CurrentFenceValue ) );
n64FenceValue++;
GRS_THROW_IF_FAILED( pIFence->SetEventOnCompletion( n64CurrentFenceValue, hEventFence ) );
//-----------------------------------------------------------------------------------------------------
}
break;
case 1:
{
while ( ::PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
{
if ( WM_QUIT != msg.message )
{
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
else
{
bExit = TRUE;
}
}
}
default:
break;
}
}
arTexture.RemoveAll();
arTextureUp.RemoveAll();
}
catch ( CAtlException& e )
{//发生了COM异常
e;
}
catch ( ... )
{
}
return 0;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_DESTROY:
PostQuitMessage( 0 );
break;
case WM_KEYDOWN:
{
USHORT n16KeyCode = ( wParam & 0xFF );
if ( VK_TAB == n16KeyCode )
{// 按Tab键切换选择模型文件
OPENFILENAMEA ofn = {};
ofn.lStructSize = sizeof( ofn );
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = "x 文件\0*.x;*.X\0OBJ文件\0*.obj\0FBX文件\0*.fbx\0所有文件\0*.*\0";
ofn.lpstrFile = g_pszModelFile;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrTitle = "请选择一个要显示的3D模型文件...";
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
if ( !GetOpenFileNameA( &ofn ) )
{
StringCchPrintfA( g_pszModelFile, MAX_PATH, "%sasset\\rgbgame\\hero.x", g_pszAppPathA );
}
}
if ( VK_SPACE == n16KeyCode )
{// 切换动画序列
if ( g_stMeshData.m_paiModel->HasAnimations() )
{
g_stMeshData.m_nCurrentAnimIndex = ++g_stMeshData.m_nCurrentAnimIndex % g_stMeshData.m_paiModel->mNumAnimations;
ATLTRACE( "切换到动画序列(%u):%s\n"
, g_stMeshData.m_nCurrentAnimIndex
, g_stMeshData.m_paiModel->mAnimations[g_stMeshData.m_nCurrentAnimIndex]->mName.C_Str() );
}
}
if ( VK_F3 == n16KeyCode )
{// F3键切换网格显示
g_bWireFrame = !g_bWireFrame;
}
XMVECTOR vDelta = { 0.0f,0.0f,1.0f,0.0f };
if ( VK_UP == n16KeyCode )
{
g_v4EyePos = XMVectorAdd( g_v4EyePos, vDelta );
}
if ( VK_DOWN == n16KeyCode )
{
g_v4EyePos = XMVectorSubtract( g_v4EyePos, vDelta );
}
vDelta = { 1.0f,0.0f,0.0f,0.0f };
if ( VK_LEFT == n16KeyCode )
{
g_v4EyePos = XMVectorAdd( g_v4EyePos, vDelta );
}
if ( VK_RIGHT == n16KeyCode )
{
g_v4EyePos = XMVectorSubtract( g_v4EyePos, vDelta );
}
if ( VK_ADD == n16KeyCode || VK_OEM_PLUS == n16KeyCode )
{
g_fScaling += 1.0f;
}
if ( VK_SUBTRACT == n16KeyCode || VK_OEM_MINUS == n16KeyCode )
{
g_fScaling -= 1.0f;
if ( g_fScaling <= 1.0f )
{
g_fScaling = 1.0f;
}
}
}
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return DefWindowProc( hWnd, message, wParam, lParam );
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{6bffbd6c-b171-4c22-8878-4bcafbe4cf0f}</ProjectGuid>
<RootNamespace>My17D3D12AssimpAnimation</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)Include;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)Include;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent>
<Command>Copy /Y /V $(SolutionDir)Lib\assimp-vc142-mtd.dll $(OutDirFullPath)</Command>
<Message>复制Assimp库文件......</Message>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<PreBuildEvent>
<Command>Copy /Y /V $(SolutionDir)Lib\assimp-vc142-mtd.dll $(OutDirFullPath)</Command>
<Message>复制Assimp库文件......</Message>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\Commons\GRS_Assimp_Loader.cpp" />
<ClCompile Include="17-D3D12_Assimp_Animation.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Commons\GRS_Assimp_Loader.h" />
<ClInclude Include="..\Commons\GRS_D3D12_Utility.h" />
<ClInclude Include="..\Commons\GRS_Def.h" />
<ClInclude Include="..\Commons\GRS_Mem.h" />
<ClInclude Include="..\Commons\GRS_Texture_Loader.h" />
<ClInclude Include="..\Commons\GRS_WIC_Utility.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="17-D3D12_Assimp_Animation.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\Commons\GRS_Assimp_Loader.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Commons\GRS_Assimp_Loader.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Commons\GRS_D3D12_Utility.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Commons\GRS_Def.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Commons\GRS_Texture_Loader.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Commons\GRS_WIC_Utility.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\Commons\GRS_Mem.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
\ No newline at end of file
// 02-3D_Animation_With_Assimp_D3D12 Vertex Shader
cbuffer cbMVP : register(b0)
{
float4x4 mxWorld; //世界矩阵,这里其实是Model->World的转换矩阵
float4x4 mxView; //视矩阵
float4x4 mxProjection; //投影矩阵
float4x4 mxViewProj; //视矩阵*投影
float4x4 mxMVP; //世界*视矩阵*投影
};
cbuffer cbBones : register(b1)
{
float4x4 mxBones[256]; //骨骼动画“调色板” 最多256根"大骨头"。内存大,显存多,任性!
};
struct VSInput
{
float4 position : POSITION0; //顶点位置
float4 normal : NORMAL0; //法线
float2 texuv : TEXCOORD0; //纹理坐标
uint4 bonesID : BLENDINDICES0; //骨骼索引
float4 fWeights : BLENDWEIGHT0; //骨骼权重
};
struct PSInput
{
float4 position : SV_POSITION0; //位置
float4 normal : NORMAL0; //法线
float2 texuv : TEXCOORD0; //纹理坐标
};
PSInput VSMain(VSInput vin)
{
PSInput vout;
// 根据骨头索引以及权重计算骨头变换的复合矩阵
float4x4 mxBonesTrans
= vin.fWeights[0] * mxBones[vin.bonesID[0]]
+ vin.fWeights[1] * mxBones[vin.bonesID[1]]
+ vin.fWeights[2] * mxBones[vin.bonesID[2]]
+ vin.fWeights[3] * mxBones[vin.bonesID[3]];
// 变换骨头对顶点的影响
vout.position = mul(vin.position, mxBonesTrans);
//最终变换到视空间
vout.position = mul(vout.position, mxMVP);
//vout.position = mul(vin.position, mxMVP);
// 向量仅做世界矩阵变换
vout.normal = mul(vin.normal, mxWorld);
// 纹理坐标原样输出
vout.texuv = vin.texuv;
return vout;
}
Texture2D g_txDiffuse : register(t0);
SamplerState g_sampler : register(s0);
float4 PSMain(PSInput input) : SV_TARGET
{
//return float4( 0.9f, 0.9f, 0.9f, 1.0f );
return float4(g_txDiffuse.Sample(g_sampler, input.texuv).rgb,1.0f);
}
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
#include "GRS_Assimp_Loader.h"
#define GRS_USEPRINTFA() CHAR pBuf[1024] = {};
#define GRS_TRACEA(...) \
StringCchPrintfA(pBuf,1024,__VA_ARGS__);\
OutputDebugStringA(pBuf);
static Assimp::Importer g_aiImporter;
BOOL LoadMesh(LPCSTR pszFileName, ST_GRS_MESH_DATA& stMeshData)
{
stMeshData.m_nCurrentAnimIndex = 0;
stMeshData.m_paiModel = g_aiImporter.ReadFile(pszFileName, ASSIMP_LOAD_FLAGS);
if (nullptr == stMeshData.m_paiModel)
{
ATLTRACE("无法解析文件(%s):%s (%d)\n", pszFileName, g_aiImporter.GetErrorString(), ::GetLastError());
return FALSE;
}
// 获取根节点的变换矩阵,其实就是 Module->World 的变换矩阵
stMeshData.m_mxModel = XMMatrixTranspose(MXEqual(stMeshData.m_mxModel, stMeshData.m_paiModel->mRootNode->mTransformation));
// 获取网格数量
UINT nMeshCnt = stMeshData.m_paiModel->mNumMeshes;
if ( 0 == nMeshCnt )
{
ATLTRACE("文件(%s)中没有网格数据!\n", pszFileName);
return FALSE;
}
const aiMesh* paiSubMesh = nullptr;
const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
UINT nNumBones = 0;
UINT nNumVertices = 0;
UINT nNumIndices = 0;
stMeshData.m_arSubMeshInfo.SetCount(nMeshCnt);
// 加载Vertex基本信息
for (UINT i = 0; i < nMeshCnt; i++)
{
paiSubMesh = stMeshData.m_paiModel->mMeshes[i];
stMeshData.m_arSubMeshInfo[i].m_nMaterialIndex = paiSubMesh->mMaterialIndex;
stMeshData.m_arSubMeshInfo[i].m_nNumIndices = paiSubMesh->mNumFaces * GRS_INDICES_PER_FACE;
stMeshData.m_arSubMeshInfo[i].m_nBaseVertex = nNumVertices;
stMeshData.m_arSubMeshInfo[i].m_nBaseIndex = nNumIndices;
// 当前Mesh的顶点数量和索引数量累加后,就是下个Mesh顶点和索引在整体缓冲中的索引开始位置
nNumVertices += stMeshData.m_paiModel->mMeshes[i]->mNumVertices;
nNumIndices += stMeshData.m_arSubMeshInfo[i].m_nNumIndices;
// 加载顶点常规数据
for (UINT j = 0; j < paiSubMesh->mNumVertices; j++)
{
stMeshData.m_arPositions.Add(XMFLOAT4(paiSubMesh->mVertices[j].x
, paiSubMesh->mVertices[j].y
, paiSubMesh->mVertices[j].z
, 1.0f));
stMeshData.m_arNormals.Add(XMFLOAT4(paiSubMesh->mNormals[j].x
, paiSubMesh->mNormals[j].y
, paiSubMesh->mNormals[j].z
, 0.0f));
// 注意这个地方只考虑一个纹理的情况,其实最多可以有八个,可以再做个循环进行加载
const aiVector3D* pTexCoord = paiSubMesh->HasTextureCoords(0)
? &(paiSubMesh->mTextureCoords[0][j])
: &Zero3D;
stMeshData.m_arTexCoords.Add(XMFLOAT2(pTexCoord->x, pTexCoord->y));
}
// 加载索引数据
for (UINT j = 0; j < paiSubMesh->mNumFaces; j++)
{
const aiFace& Face = paiSubMesh->mFaces[j];
// 已经通过导入标志强制为三角形网格了,每个面就三个索引
ATLASSERT(Face.mNumIndices == GRS_INDICES_PER_FACE);
for (UINT k = 0; k < Face.mNumIndices; k++)
{
stMeshData.m_arIndices.Add(Face.mIndices[k]);
}
}
}
stMeshData.m_arBoneIndices.SetCount(nNumVertices);
UINT VertexID = 0;
FLOAT Weight = 0.0f;
UINT nBoneIndex = 0;
CStringA strBoneName;
aiMatrix4x4 mxBoneOffset;
aiBone* pBone = nullptr;
// 加载骨骼数据
for (UINT i = 0; i < nMeshCnt; i++)
{
paiSubMesh = stMeshData.m_paiModel->mMeshes[i];
for (UINT j = 0; j < paiSubMesh->mNumBones; j++)
{
nBoneIndex = 0;
pBone = paiSubMesh->mBones[j];
strBoneName = pBone->mName.data;
if ( nullptr == stMeshData.m_mapName2Bone.Lookup(strBoneName) )
{
// 新骨头索引
nBoneIndex = nNumBones ++;
stMeshData.m_arBoneDatas.SetCount(nNumBones);
stMeshData.m_arBoneDatas[nBoneIndex].m_mxBoneOffset
= XMMatrixTranspose(MXEqual(stMeshData.m_arBoneDatas[nBoneIndex].m_mxBoneOffset, pBone->mOffsetMatrix));
stMeshData.m_mapName2Bone.SetAt(strBoneName, nBoneIndex);
}
else
{
nBoneIndex = stMeshData.m_mapName2Bone[strBoneName];
}
for (UINT k = 0; k < pBone->mNumWeights; k++)
{
VertexID = stMeshData.m_arSubMeshInfo[i].m_nBaseVertex + pBone->mWeights[k].mVertexId;
Weight = pBone->mWeights[k].mWeight;
stMeshData.m_arBoneIndices[VertexID].AddBoneData(nBoneIndex, Weight);
}
}
}
// 获取材质数量
UINT nMatCnt = stMeshData.m_paiModel->mNumMaterials;
UINT nTextureIndex = 0;
UINT nTmpIndex = 0;
CStringA strTextureFileName;
aiString aistrPath;
for (UINT i = 0; i < stMeshData.m_paiModel->mNumMaterials; i++)
{
const aiMaterial* pMaterial = stMeshData.m_paiModel->mMaterials[i];
if (pMaterial->GetTextureCount(aiTextureType_DIFFUSE) > 0)
{
if ( pMaterial->GetTexture(aiTextureType_DIFFUSE
, 0, &aistrPath, nullptr, nullptr, nullptr, nullptr, nullptr)
== AI_SUCCESS )
{
strTextureFileName = aistrPath.C_Str();
nTmpIndex = 0;
if ( !stMeshData.m_mapTextrueName2Index.Lookup( strTextureFileName , nTmpIndex ) )
{
stMeshData.m_mapTextrueName2Index.SetAt( strTextureFileName, nTextureIndex );
nTmpIndex = nTextureIndex;
++ nTextureIndex;
}
stMeshData.m_mapTextureIndex2HeapIndex.SetAt( i, nTmpIndex );
}
}
}
return TRUE;
}
const aiNodeAnim* FindNodeAnim(const aiAnimation* pAnimation, const CStringA strNodeName)
{
for (UINT i = 0; i < pAnimation->mNumChannels; i++)
{
if ( CStringA(pAnimation->mChannels[i]->mNodeName.data) == strNodeName)
{
return pAnimation->mChannels[i];
}
}
return nullptr;
}
BOOL FindPosition(FLOAT AnimationTime, const aiNodeAnim* pNodeAnim, UINT& nPosIndex)
{
nPosIndex = 0;
if (!(pNodeAnim->mNumPositionKeys > 0))
{
return FALSE;
}
for ( UINT i = 0; i < pNodeAnim->mNumPositionKeys - 1; i++ )
{
// 严格判断时间Tick是否在两个关键帧之间
if ( ( AnimationTime >= (FLOAT)pNodeAnim->mPositionKeys[i].mTime )
&& ( AnimationTime < (FLOAT)pNodeAnim->mPositionKeys[i + 1].mTime) )
{
nPosIndex = i;
return TRUE;
}
}
return FALSE;
}
BOOL FindRotation(FLOAT AnimationTime, const aiNodeAnim* pNodeAnim, UINT& nRotationIndex)
{
nRotationIndex = 0;
if (!(pNodeAnim->mNumRotationKeys > 0))
{
return FALSE;
}
for (UINT i = 0; i < pNodeAnim->mNumRotationKeys - 1; i++)
{
// 严格判断时间Tick是否在两个关键帧之间
if ( (AnimationTime >= (FLOAT)pNodeAnim->mRotationKeys[i].mTime )
&& (AnimationTime < (FLOAT)pNodeAnim->mRotationKeys[i + 1].mTime) )
{
nRotationIndex = i;
return TRUE;
}
}
return FALSE;
}
BOOL FindScaling(FLOAT AnimationTime, const aiNodeAnim* pNodeAnim, UINT& nScalingIndex)
{
nScalingIndex = 0;
if (!(pNodeAnim->mNumScalingKeys > 0))
{
return FALSE;
}
for (UINT i = 0; i < pNodeAnim->mNumScalingKeys - 1; i++)
{
// 严格判断时间Tick是否在两个关键帧之间
if ( ( AnimationTime >= (FLOAT)pNodeAnim->mScalingKeys[i].mTime )
&& ( AnimationTime < (FLOAT)pNodeAnim->mScalingKeys[i + 1].mTime) )
{
nScalingIndex = i;
return TRUE;
}
}
return FALSE;
}
void CalcInterpolatedPosition(XMVECTOR& mxOut, FLOAT AnimationTime, const aiNodeAnim* pNodeAnim)
{
if (pNodeAnim->mNumPositionKeys == 1)
{
VectorEqual(mxOut, pNodeAnim->mPositionKeys[0].mValue);
return;
}
UINT PositionIndex = 0;
if (! FindPosition(AnimationTime, pNodeAnim, PositionIndex))
{// 当前时间段内没有位移的变换,默认返回0.0位移
mxOut = XMVectorSet(0.0f,0.0f,0.0f,0.0f);
return;
}
UINT NextPositionIndex = (PositionIndex + 1);
ATLASSERT(NextPositionIndex < pNodeAnim->mNumPositionKeys);
FLOAT DeltaTime = (FLOAT)(pNodeAnim->mPositionKeys[NextPositionIndex].mTime - pNodeAnim->mPositionKeys[PositionIndex].mTime);
FLOAT Factor = (AnimationTime - (FLOAT)pNodeAnim->mPositionKeys[PositionIndex].mTime) / DeltaTime;
ATLASSERT(Factor >= 0.0f && Factor <= 1.0f);
VectorLerp(mxOut
, pNodeAnim->mPositionKeys[PositionIndex].mValue
, pNodeAnim->mPositionKeys[NextPositionIndex].mValue
, Factor);
}
void CalcInterpolatedRotation(XMVECTOR& mxOut, FLOAT AnimationTime, const aiNodeAnim* pNodeAnim)
{
if (pNodeAnim->mNumRotationKeys == 1)
{
QuaternionEqual(mxOut, pNodeAnim->mRotationKeys[0].mValue);
return;
}
UINT RotationIndex = 0;
if (!FindRotation(AnimationTime, pNodeAnim, RotationIndex))
{// 当前时间段内没有旋转变换,默认返回0.0旋转
mxOut = XMVectorSet(0.0f,0.0f,0.0f,0.0f);
return;
}
UINT NextRotationIndex = (RotationIndex + 1);
ATLASSERT(NextRotationIndex < pNodeAnim->mNumRotationKeys);
FLOAT DeltaTime = (FLOAT)(pNodeAnim->mRotationKeys[NextRotationIndex].mTime
- pNodeAnim->mRotationKeys[RotationIndex].mTime);
FLOAT Factor = (AnimationTime - (FLOAT)pNodeAnim->mRotationKeys[RotationIndex].mTime) / DeltaTime;
ATLASSERT(Factor >= 0.0f && Factor <= 1.0f);
QuaternionSlerp(mxOut
, pNodeAnim->mRotationKeys[RotationIndex].mValue
, pNodeAnim->mRotationKeys[NextRotationIndex].mValue
, Factor);
XMQuaternionNormalize(mxOut);
}
void CalcInterpolatedScaling(XMVECTOR& mxOut, FLOAT AnimationTime, const aiNodeAnim* pNodeAnim)
{
if ( pNodeAnim->mNumScalingKeys == 1 )
{
VectorEqual(mxOut, pNodeAnim->mScalingKeys[0].mValue);
return;
}
UINT ScalingIndex = 0;
if (!FindScaling(AnimationTime, pNodeAnim, ScalingIndex))
{// 当前时间帧没有缩放变换,返回 1.0缩放比例
mxOut = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f);
return;
}
UINT NextScalingIndex = (ScalingIndex + 1);
ATLASSERT(NextScalingIndex < pNodeAnim->mNumScalingKeys);
FLOAT DeltaTime = (FLOAT)(pNodeAnim->mScalingKeys[NextScalingIndex].mTime - pNodeAnim->mScalingKeys[ScalingIndex].mTime);
FLOAT Factor = (AnimationTime - (FLOAT)pNodeAnim->mScalingKeys[ScalingIndex].mTime) / DeltaTime;
ATLASSERT(Factor >= 0.0f && Factor <= 1.0f);
VectorLerp(mxOut
, pNodeAnim->mScalingKeys[ScalingIndex].mValue
, pNodeAnim->mScalingKeys[NextScalingIndex].mValue
, Factor);
}
void ReadNodeHeirarchy(ST_GRS_MESH_DATA& stMeshData
, const aiAnimation* pAnimation
, FLOAT AnimationTime
, const aiNode* pNode
, const XMMATRIX& mxParentTransform)
{
XMMATRIX mxNodeTransformation = XMMatrixIdentity();
MXEqual(mxNodeTransformation, pNode->mTransformation);
mxNodeTransformation = XMMatrixTranspose(mxNodeTransformation);
XMMATRIX mxThisTrans = XMMatrixTranspose(mxNodeTransformation);
//mxThisTrans = XMMatrixTranspose(XMMatrixInverse(nullptr,mxNodeTransformation));
CStringA strNodeName(pNode->mName.data);
const aiNodeAnim* pNodeAnim = FindNodeAnim(pAnimation, strNodeName);
if ( pNodeAnim )
{
// 缩放
XMVECTOR vScaling = {};
CalcInterpolatedScaling(vScaling, AnimationTime, pNodeAnim);
XMMATRIX mxScaling = XMMatrixScalingFromVector(vScaling);
// 四元数旋转
XMVECTOR vRotationQ = {};
CalcInterpolatedRotation(vRotationQ, AnimationTime, pNodeAnim);
XMMATRIX mxRotationM = XMMatrixRotationQuaternion(vRotationQ);
// 位移
XMVECTOR vTranslation = {};
CalcInterpolatedPosition(vTranslation, AnimationTime, pNodeAnim);
XMMATRIX mxTranslationM = XMMatrixTranslationFromVector(vTranslation);
// 骨骼动画中 最经典的 SQT 组合变换
mxNodeTransformation = mxScaling * mxRotationM * mxTranslationM; // TranslationM* RotationM* ScalingM;
}
XMMATRIX mxGlobalTransformation = mxNodeTransformation * mxParentTransform;
UINT nBoneIndex = 0;
if (stMeshData.m_mapName2Bone.Lookup(strNodeName, nBoneIndex))
{
stMeshData.m_arBoneDatas[nBoneIndex].m_mxFinalTransformation
= stMeshData.m_arBoneDatas[nBoneIndex].m_mxBoneOffset
/** mxThisTrans*/
* mxGlobalTransformation
* stMeshData.m_mxModel;
}
for (UINT i = 0; i < pNode->mNumChildren; i++)
{
ReadNodeHeirarchy(stMeshData
, pAnimation
, AnimationTime
, pNode->mChildren[i]
, mxGlobalTransformation);
}
}
VOID CalcAnimation(ST_GRS_MESH_DATA& stMeshData, FLOAT fTimeInSeconds, CGRSARMatrix& arTransforms)
{
XMMATRIX mxIdentity = XMMatrixIdentity();
aiNode* pNode = stMeshData.m_paiModel->mRootNode;
aiAnimation* pAnimation = stMeshData.m_paiModel->mAnimations[stMeshData.m_nCurrentAnimIndex];
FLOAT TicksPerSecond = (FLOAT)(pAnimation->mTicksPerSecond != 0
? pAnimation->mTicksPerSecond
: 25.0f);
FLOAT TimeInTicks = fTimeInSeconds * TicksPerSecond;
FLOAT AnimationTime = fmod(TimeInTicks, (FLOAT)pAnimation->mDuration);
ReadNodeHeirarchy(stMeshData, pAnimation, AnimationTime, pNode, mxIdentity);
UINT nNumBones = (UINT)stMeshData.m_arBoneDatas.GetCount();
for (UINT i = 0; i < nNumBones; i++)
{
arTransforms.Add(stMeshData.m_arBoneDatas[i].m_mxFinalTransformation);
}
}
\ No newline at end of file
#pragma once
#include <strsafe.h>
#include <atlbase.h>
#include <atlcoll.h>
#include <atlchecked.h>
#include <atlstr.h>
#include <atlconv.h>
#include <DirectXMath.h>
using namespace DirectX;
#include "assimp/Importer.hpp" // 导入器在该头文件中定义
#include "assimp/scene.h" // 读取到的模型数据都放在scene中
#include "assimp/postprocess.h"
// 导入文件时预处理的标志
// aiProcess_LimitBoneWeights
// aiProcess_OptimizeMeshes
// aiProcess_MakeLeftHanded
// aiProcess_ConvertToLeftHanded
// aiProcess_MakeLeftHanded
// aiProcess_ConvertToLeftHanded
//| aiProcess_MakeLeftHanded\
#define ASSIMP_LOAD_FLAGS (aiProcess_Triangulate\
| aiProcess_GenSmoothNormals\
| aiProcess_GenBoundingBoxes\
| aiProcess_JoinIdenticalVertices\
| aiProcess_FlipUVs\
| aiProcess_ConvertToLeftHanded\
| aiProcess_LimitBoneWeights)
// 每个表面的索引数,(根据上面的导入标志,导入的模型应该都是严格的三角形网格)
#define GRS_INDICES_PER_FACE 3
// 定义每个骨骼数据中子项的个数(根据上面的导入标志,现在严格限定每个顶点被最多4根骨头影响)
#define GRS_BONE_DATACNT 4
// 定义最大可支持的骨头数量
#define GRS_MAX_BONES 256
struct ST_GRS_VERTEX_BONE
{
public:
UINT32 m_nBonesIDs[GRS_BONE_DATACNT];
FLOAT m_fWeights[GRS_BONE_DATACNT];
public:
VOID AddBoneData(UINT nBoneID, FLOAT fWeight)
{
for (UINT32 i = 0; i < GRS_BONE_DATACNT; i++)
{
if ( m_fWeights[i] == 0.0 )
{
m_nBonesIDs[i] = nBoneID;
m_fWeights[i] = fWeight;
break;
}
}
}
};
// 基本骨骼动画中每根骨头相对于模型空间的位移矩阵
// 其中BoneOffset是位移
// FinalTransformation用于解算最终动画时保存真实的每根骨头的变换
struct ST_GRS_BONE_DATA
{
XMMATRIX m_mxBoneOffset;
XMMATRIX m_mxFinalTransformation;
};
typedef CAtlArray<XMFLOAT4> CGRSARPositions;
typedef CAtlArray<XMFLOAT4> CGRSARNormals;
typedef CAtlArray<XMFLOAT2> CGRSARTexCoords;
typedef CAtlArray<UINT> CGRSARIndices;
typedef CAtlArray<ST_GRS_VERTEX_BONE> CGRSARVertexBones;
typedef CAtlArray<ST_GRS_BONE_DATA> CGRSARBoneDatas;
typedef CAtlArray<CStringA> CGRSARTTextureName;
typedef CAtlArray<XMMATRIX> CGRSARMatrix;
typedef CAtlMap<UINT, CStringA> CGRSMapUINT2String;
typedef CAtlMap<CStringA, UINT> CGRSMapString2UINT;
typedef CAtlMap<UINT, UINT> CGRSMapUINT2UINT;
// 模型中子网格的顶点偏移等信息
struct ST_GRS_SUBMESH_DATA
{
UINT m_nNumIndices;
UINT m_nBaseVertex;
UINT m_nBaseIndex;
UINT m_nMaterialIndex;
};
typedef CAtlArray<ST_GRS_SUBMESH_DATA> CGRSSubMesh;
const UINT g_ncSlotCnt = 4; // 用4个插槽上传顶点数据
struct ST_GRS_MESH_DATA
{
XMMATRIX m_mxModel;
CStringA m_strFileName;
const aiScene* m_paiModel;
CGRSSubMesh m_arSubMeshInfo;
CGRSARPositions m_arPositions;
CGRSARNormals m_arNormals;
CGRSARTexCoords m_arTexCoords;
CGRSARVertexBones m_arBoneIndices;
CGRSARIndices m_arIndices;
//CGRSARTTextureName m_arTextureName;
CGRSMapString2UINT m_mapTextrueName2Index;
CGRSMapUINT2UINT m_mapTextureIndex2HeapIndex;
CGRSARBoneDatas m_arBoneDatas;
CGRSMapString2UINT m_mapName2Bone; //名称->骨骼的索引
CGRSMapString2UINT m_mapAnimName2Index; //名称->动画的索引
UINT m_nCurrentAnimIndex; // 当前播放的动画序列索引
};
__inline const XMMATRIX& MXEqual(XMMATRIX& mxDX, const aiMatrix4x4& mxAI)
{
mxDX = XMMatrixSet(mxAI.a1, mxAI.a2, mxAI.a3, mxAI.a4,
mxAI.b1, mxAI.b2, mxAI.b3, mxAI.b4,
mxAI.c1, mxAI.c2, mxAI.c3, mxAI.c4,
mxAI.d1, mxAI.d2, mxAI.d3, mxAI.d4);
return mxDX;
}
__inline const XMVECTOR& VectorEqual(XMVECTOR& vDX, const aiVector3D& vAI)
{
vDX = XMVectorSet(vAI.x, vAI.y, vAI.z, 0);
return vDX;
}
__inline const XMVECTOR& QuaternionEqual(XMVECTOR& qDX, const aiQuaternion& qAI)
{
qDX = XMVectorSet(qAI.x, qAI.y, qAI.z, qAI.w);
return qDX;
}
__inline VOID VectorLerp(XMVECTOR& vOut, aiVector3D& aivStart, aiVector3D& aivEnd, FLOAT t)
{
XMVECTOR vStart = XMVectorSet(aivStart.x, aivStart.y, aivStart.z, 0);
XMVECTOR vEnd = XMVectorSet(aivEnd.x, aivEnd.y, aivEnd.z, 0);
vOut = XMVectorLerp(vStart, vEnd, t);
}
__inline VOID QuaternionSlerp(XMVECTOR& vOut, aiQuaternion& qStart, aiQuaternion& qEnd, FLOAT t)
{
//DirectXMath四元数函数使用XMVECTOR 4 - vector来表示四元数,其中X、Y和Z分量是矢量部分,W分量是标量部分。
XMVECTOR qdxStart;
XMVECTOR qdxEnd;
QuaternionEqual(qdxStart, qStart);
QuaternionEqual(qdxEnd, qEnd);
vOut = XMQuaternionSlerp(qdxStart, qdxEnd, t);
}
BOOL LoadMesh(LPCSTR pszFileName, ST_GRS_MESH_DATA& stMeshData);
VOID CalcAnimation(ST_GRS_MESH_DATA& stMeshData, FLOAT fTimeInSeconds, CGRSARMatrix& arTransforms);
#pragma once
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
#include <windows.h>
#include <d3d12.h> //for d3d12
//------------------------------------------------------------------------------------------------------------
// 为了调试加入下面的内联函数和宏定义,为每个接口对象设置名称,方便查看调试输出
#if defined(_DEBUG)
inline void GRS_SetD3D12DebugName(ID3D12Object* pObject, LPCWSTR name)
{
pObject->SetName(name);
}
inline void GRS_SetD3D12DebugNameIndexed(ID3D12Object* pObject, LPCWSTR name, UINT index)
{
WCHAR _DebugName[MAX_PATH] = {};
if (SUCCEEDED(StringCchPrintfW(_DebugName, _countof(_DebugName), L"%s[%u]", name, index)))
{
pObject->SetName(_DebugName);
}
}
#else
inline void GRS_SetD3D12DebugName(ID3D12Object*, LPCWSTR)
{
}
inline void GRS_SetD3D12DebugNameIndexed(ID3D12Object*, LPCWSTR, UINT)
{
}
#endif
#define GRS_SET_D3D12_DEBUGNAME(x) GRS_SetD3D12DebugName(x, L#x)
#define GRS_SET_D3D12_DEBUGNAME_INDEXED(x, n) GRS_SetD3D12DebugNameIndexed(x[n], L#x, n)
#define GRS_SET_D3D12_DEBUGNAME_COMPTR(x) GRS_SetD3D12DebugName(x.Get(), L#x)
#define GRS_SET_D3D12_DEBUGNAME_INDEXED_COMPTR(x, n) GRS_SetD3D12DebugNameIndexed(x[n].Get(), L#x, n)
#if defined(_DEBUG)
inline void GRS_SetDXGIDebugName(IDXGIObject* pObject, LPCWSTR name)
{
size_t szLen = 0;
StringCchLengthW(name, MAX_PATH, &szLen);
pObject->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(szLen - 1), name);
}
inline void GRS_SetDXGIDebugNameIndexed(IDXGIObject* pObject, LPCWSTR name, UINT index)
{
size_t szLen = 0;
WCHAR _DebugName[MAX_PATH] = {};
if (SUCCEEDED(StringCchPrintfW(_DebugName, _countof(_DebugName), L"%s[%u]", name, index)))
{
StringCchLengthW(_DebugName, _countof(_DebugName), &szLen);
pObject->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(szLen), _DebugName);
}
}
#else
inline void GRS_SetDXGIDebugName(IDXGIObject*, LPCWSTR)
{
}
inline void GRS_SetDXGIDebugNameIndexed(IDXGIObject*, LPCWSTR, UINT)
{
}
#endif
#define GRS_SET_DXGI_DEBUGNAME(x) GRS_SetDXGIDebugName(x, L#x)
#define GRS_SET_DXGI_DEBUGNAME_INDEXED(x, n) GRS_SetDXGIDebugNameIndexed(x[n], L#x, n)
#define GRS_SET_DXGI_DEBUGNAME_COMPTR(x) GRS_SetDXGIDebugName(x.Get(), L#x)
#define GRS_SET_DXGI_DEBUGNAME_INDEXED_COMPTR(x, n) GRS_SetDXGIDebugNameIndexed(x[n].Get(), L#x, n)
//------------------------------------------------------------------------------------------------------------
#pragma once
#include <atlexcept.h>
#ifndef GRS_THROW_IF_FAILED
#define GRS_THROW_IF_FAILED(hr) {HRESULT _hr = (hr);if (FAILED(_hr)){ ATLTRACE("Error: 0x%08x\n",_hr); AtlThrow(_hr); }}
#endif
//更简洁的向上边界对齐算法 内存管理中常用 请记住
#ifndef GRS_UPPER
#define GRS_UPPER(A,B) ((size_t)(((A)+((B)-1))&~((B) - 1)))
#endif
//上取整除法
#ifndef GRS_UPPER_DIV
#define GRS_UPPER_DIV(A,B) ((UINT)(((A)+((B)-1))/(B)))
#endif
#pragma once
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
#include <windows.h>
#define GRS_ALLOC(sz) ::HeapAlloc(GetProcessHeap(),0,sz)
#define GRS_CALLOC(sz) ::HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz)
#define GRS_REALLOC(p,sz) ::HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,p,sz)
//下面这个表达式可能会引起副作用,p参数尽量使用指针变量,而不是表达式
#define GRS_SAFE_FREE(p) if(nullptr != (p)){::HeapFree(GetProcessHeap(),0,(p));(p)=nullptr;}
#define GRS_FREE(p) GRS_SAFE_FREE(p)
#define GRS_MSIZE(p) ::HeapSize(GetProcessHeap(),0,p)
#define GRS_MVALID(p) ::HeapValidate(GetProcessHeap(),0,p)
#pragma once
#include <strsafe.h>
#include <wrl.h>
#include <atlconv.h>
#include <atltrace.h>
#include <atlexcept.h>
#include "GRS_WIC_Utility.h"
using namespace ATL;
using namespace Microsoft;
using namespace Microsoft::WRL;
// 加载纹理
__inline BOOL LoadTextureFromMem( ID3D12GraphicsCommandList* pCMDList
, const BYTE* pbImageData
, const size_t& szImageBufferSize
, const DXGI_FORMAT emTextureFormat
, const UINT nTextureW
, const UINT nTextureH
, const UINT nPicRowPitch
, ID3D12Resource*& pITextureUpload
, ID3D12Resource*& pITexture )
{
BOOL bRet = TRUE;
try
{
ComPtr<ID3D12Device> pID3D12Device;
ComPtr<ID3D12GraphicsCommandList> pICMDList( pCMDList );
GRS_THROW_IF_FAILED( pICMDList->GetDevice( IID_PPV_ARGS( &pID3D12Device ) ) );
D3D12_HEAP_PROPERTIES stTextureHeapProp = {};
stTextureHeapProp.Type = D3D12_HEAP_TYPE_DEFAULT;
D3D12_RESOURCE_DESC stTextureDesc = {};
stTextureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
stTextureDesc.MipLevels = 1;
stTextureDesc.Format = emTextureFormat;
stTextureDesc.Width = nTextureW;
stTextureDesc.Height = nTextureH;
stTextureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
stTextureDesc.DepthOrArraySize = 1;
stTextureDesc.SampleDesc.Count = 1;
stTextureDesc.SampleDesc.Quality = 0;
GRS_THROW_IF_FAILED( pID3D12Device->CreateCommittedResource(
&stTextureHeapProp
, D3D12_HEAP_FLAG_NONE
, &stTextureDesc //可以使用CD3DX12_RESOURCE_DESC::Tex2D来简化结构体的初始化
, D3D12_RESOURCE_STATE_COPY_DEST
, nullptr
, IID_PPV_ARGS( &pITexture ) ) );
//获取需要的上传堆资源缓冲的大小,这个尺寸通常大于实际图片的尺寸
D3D12_RESOURCE_DESC Desc = pITexture->GetDesc();
UINT64 n64UploadBufferSize = 0;
pID3D12Device->GetCopyableFootprints( &Desc, 0, 1, 0, nullptr, nullptr, nullptr, &n64UploadBufferSize );
stTextureHeapProp.Type = D3D12_HEAP_TYPE_UPLOAD;
D3D12_RESOURCE_DESC stUploadTextureDesc = {};
stUploadTextureDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
stUploadTextureDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
stUploadTextureDesc.Width = n64UploadBufferSize;
stUploadTextureDesc.Height = 1;
stUploadTextureDesc.DepthOrArraySize = 1;
stUploadTextureDesc.MipLevels = 1;
stUploadTextureDesc.Format = DXGI_FORMAT_UNKNOWN;
stUploadTextureDesc.SampleDesc.Count = 1;
stUploadTextureDesc.SampleDesc.Quality = 0;
stUploadTextureDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
stUploadTextureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
GRS_THROW_IF_FAILED( pID3D12Device->CreateCommittedResource(
&stTextureHeapProp
, D3D12_HEAP_FLAG_NONE
, &stUploadTextureDesc
, D3D12_RESOURCE_STATE_GENERIC_READ
, nullptr
, IID_PPV_ARGS( &pITextureUpload ) ) );
//获取向上传堆拷贝纹理数据的一些纹理转换尺寸信息
//对于复杂的DDS纹理这是非常必要的过程
UINT nNumSubresources = 1u; //我们只有一副图片,即子资源个数为1
UINT nTextureRowNum = 0u;
UINT64 n64TextureRowSizes = 0u;
UINT64 n64RequiredSize = 0u;
D3D12_PLACED_SUBRESOURCE_FOOTPRINT stTxtLayouts = {};
D3D12_RESOURCE_DESC stDestDesc = pITexture->GetDesc();
pID3D12Device->GetCopyableFootprints( &stDestDesc
, 0
, nNumSubresources
, 0
, &stTxtLayouts
, &nTextureRowNum
, &n64TextureRowSizes
, &n64RequiredSize );
//因为上传堆实际就是CPU传递数据到GPU的中介
//所以我们可以使用熟悉的Map方法将它先映射到CPU内存地址中
//然后我们按行将数据复制到上传堆中
//需要注意的是之所以按行拷贝是因为GPU资源的行大小
//与实际图片的行大小是有差异的,二者的内存边界对齐要求是不一样的
BYTE* pData = nullptr;
GRS_THROW_IF_FAILED( pITextureUpload->Map( 0, NULL, reinterpret_cast<void**>( &pData ) ) );
BYTE* pDestSlice = reinterpret_cast<BYTE*>( pData ) + stTxtLayouts.Offset;
const BYTE* pSrcSlice = reinterpret_cast<const BYTE*>( pbImageData );
for ( UINT y = 0; y < nTextureRowNum; ++y )
{
memcpy( pDestSlice + static_cast<SIZE_T>( stTxtLayouts.Footprint.RowPitch ) * y
, pSrcSlice + static_cast<SIZE_T>( nPicRowPitch ) * y
, nPicRowPitch );
}
//取消映射 对于易变的数据如每帧的变换矩阵等数据,可以撒懒不用Unmap了,
//让它常驻内存,以提高整体性能,因为每次Map和Unmap是很耗时的操作
//因为现在起码都是64位系统和应用了,地址空间是足够的,被长期占用不会影响什么
pITextureUpload->Unmap( 0, NULL );
////释放图片数据,做一个干净的程序员
//GRS_SAFE_FREE((VOID*)pbImageData);
D3D12_TEXTURE_COPY_LOCATION stDstCopyLocation = {};
stDstCopyLocation.pResource = pITexture;
stDstCopyLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
stDstCopyLocation.SubresourceIndex = 0;
D3D12_TEXTURE_COPY_LOCATION stSrcCopyLocation = {};
stSrcCopyLocation.pResource = pITextureUpload;
stSrcCopyLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
stSrcCopyLocation.PlacedFootprint = stTxtLayouts;
pICMDList->CopyTextureRegion( &stDstCopyLocation, 0, 0, 0, &stSrcCopyLocation, nullptr );
//设置一个资源屏障,同步并确认复制操作完成
//直接使用结构体然后调用的形式
D3D12_RESOURCE_BARRIER stResBar = {};
stResBar.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
stResBar.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
stResBar.Transition.pResource = pITexture;
stResBar.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
stResBar.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON;
stResBar.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
pICMDList->ResourceBarrier( 1, &stResBar );
}
catch ( CAtlException& e )
{//发生了COM异常
e;
bRet = FALSE;
}
catch ( ... )
{
bRet = FALSE;
}
return bRet;
}
// 加载纹理
__inline BOOL LoadTextureFromFile(
LPCWSTR pszTextureFile
, ID3D12GraphicsCommandList* pCMDList
, ID3D12Resource*& pITextureUpload
, ID3D12Resource*& pITexture )
{
BOOL bRet = TRUE;
try
{
BYTE* pbImageData = nullptr;
size_t szImageBufferSize = 0;
DXGI_FORMAT emTextureFormat = DXGI_FORMAT_UNKNOWN;
UINT nTextureW = 0;
UINT nTextureH = 0;
UINT nPicRowPitch = 0;
if ( WICLoadImageFromFile( pszTextureFile
, emTextureFormat
, nTextureW
, nTextureH
, nPicRowPitch
, pbImageData
, szImageBufferSize ) )
{
bRet = LoadTextureFromMem( pCMDList
, pbImageData
, szImageBufferSize
, emTextureFormat
, nTextureW
, nTextureH
, nPicRowPitch
, pITextureUpload
, pITexture
);
GRS_SAFE_FREE( pbImageData );
}
}
catch ( CAtlException& e )
{//发生了COM异常
e;
bRet = FALSE;
}
catch ( ... )
{
bRet = FALSE;
}
return bRet;
}
\ No newline at end of file
#pragma once
#include <SDKDDKVer.h>
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
#include <windows.h>
#include <wincodec.h> //for WIC
#include <d3d12.h> //for d3d12
#include <wrl.h> //添加WTL支持 方便使用COM
#include "GRS_Def.h"
#include "GRS_Mem.h"
using namespace Microsoft;
using namespace Microsoft::WRL;
struct WICTranslate
{
GUID wic;
DXGI_FORMAT format;
};
static WICTranslate g_WICFormats[] =
{//WIC格式与DXGI像素格式的对应表,该表中的格式为被支持的格式
{ GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT },
{ GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT },
{ GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM },
{ GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM },
{ GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1
{ GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1
{ GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1
{ GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM },
{ GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM },
{ GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM },
{ GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT },
{ GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT },
{ GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM },
{ GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM },
{ GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM },
};
// WIC 像素格式转换表.
struct WICConvert
{
GUID source;
GUID target;
};
static WICConvert g_WICConvert[] =
{
// 目标格式一定是最接近的被支持的格式
{ GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
{ GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
{ GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
{ GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT
{ GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT
{ GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM
{ GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM
{ GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
{ GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat32bppRGBE, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
{ GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
{ GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
{ GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
};
bool GetTargetPixelFormat(const GUID* pSourceFormat, GUID* pTargetFormat)
{//查表确定兼容的最接近格式是哪个
*pTargetFormat = *pSourceFormat;
for (size_t i = 0; i < _countof(g_WICConvert); ++i)
{
if (InlineIsEqualGUID(g_WICConvert[i].source, *pSourceFormat))
{
*pTargetFormat = g_WICConvert[i].target;
return true;
}
}
return false;
}
DXGI_FORMAT GetDXGIFormatFromPixelFormat(const GUID* pPixelFormat)
{//查表确定最终对应的DXGI格式是哪一个
for (size_t i = 0; i < _countof(g_WICFormats); ++i)
{
if (InlineIsEqualGUID(g_WICFormats[i].wic, *pPixelFormat))
{
return g_WICFormats[i].format;
}
}
return DXGI_FORMAT_UNKNOWN;
}
// 加载纹理
__inline BOOL WICLoadImageFromFile(LPCWSTR pszTextureFile
, DXGI_FORMAT& emTextureFormat
, UINT& nTextureW
, UINT& nTextureH
, UINT& nPicRowPitch
, BYTE*& pbImageData
, size_t& szBufferSize )
{
BOOL bRet = TRUE;
try
{
static ComPtr<IWICImagingFactory> pIWICFactory;
ComPtr<IWICBitmapDecoder> pIWICDecoder;
ComPtr<IWICBitmapFrameDecode> pIWICFrame;
ComPtr<IWICBitmapSource> pIBMP;
UINT nBPP = 0;
USES_CONVERSION;
//使用纯COM方式创建WIC类厂对象,也是调用WIC第一步要做的事情
GRS_THROW_IF_FAILED(CoCreateInstance(CLSID_WICImagingFactory
, nullptr
, CLSCTX_INPROC_SERVER
, IID_PPV_ARGS(&pIWICFactory)));
WCHAR pszTextureFileName[MAX_PATH] = {};
StringCchCopyW(pszTextureFileName, MAX_PATH, pszTextureFile);
GRS_THROW_IF_FAILED(pIWICFactory->CreateDecoderFromFilename(
pszTextureFileName, // 文件名
NULL, // 不指定解码器,使用默认
GENERIC_READ, // 访问权限
WICDecodeMetadataCacheOnDemand, // 若需要就缓冲数据
&pIWICDecoder // 解码器对象
));
// 获取第一帧图片(因为GIF等格式文件可能会有多帧图片,其他的格式一般只有一帧图片)
// 实际解析出来的往往是位图格式数据
GRS_THROW_IF_FAILED(pIWICDecoder->GetFrame(0, &pIWICFrame));
WICPixelFormatGUID wpf = {};
//获取WIC图片格式
GRS_THROW_IF_FAILED(pIWICFrame->GetPixelFormat(&wpf));
GUID tgFormat = {};
//通过第一道转换之后获取DXGI的等价格式
if (GetTargetPixelFormat(&wpf, &tgFormat))
{
emTextureFormat = GetDXGIFormatFromPixelFormat(&tgFormat);
}
if (DXGI_FORMAT_UNKNOWN == emTextureFormat)
{// 不支持的图片格式 目前退出了事
// 一般 在实际的引擎当中都会提供纹理格式转换工具,
// 图片都需要提前转换好,所以不会出现不支持的现象
AtlThrow(S_FALSE);
}
if (!InlineIsEqualGUID(wpf, tgFormat))
{// 这个判断很重要,如果原WIC格式不是直接能转换为DXGI格式的图片时
// 我们需要做的就是转换图片格式为能够直接对应DXGI格式的形式
//创建图片格式转换器
ComPtr<IWICFormatConverter> pIConverter;
GRS_THROW_IF_FAILED(pIWICFactory->CreateFormatConverter(&pIConverter));
//初始化一个图片转换器,实际也就是将图片数据进行了格式转换
GRS_THROW_IF_FAILED(pIConverter->Initialize(
pIWICFrame.Get(), // 输入原图片数据
tgFormat, // 指定待转换的目标格式
WICBitmapDitherTypeNone, // 指定位图是否有调色板,现代都是真彩位图,不用调色板,所以为None
NULL, // 指定调色板指针
0.f, // 指定Alpha阀值
WICBitmapPaletteTypeCustom // 调色板类型,实际没有使用,所以指定为Custom
));
// 调用QueryInterface方法获得对象的位图数据源接口
GRS_THROW_IF_FAILED(pIConverter.As(&pIBMP));
}
else
{
//图片数据格式不需要转换,直接获取其位图数据源接口
GRS_THROW_IF_FAILED(pIWICFrame.As(&pIBMP));
}
//获得图片大小(单位:像素)
GRS_THROW_IF_FAILED(pIBMP->GetSize(&nTextureW, &nTextureH));
//获取图片像素的位大小的BPP(Bits Per Pixel)信息,用以计算图片行数据的真实大小(单位:字节)
ComPtr<IWICComponentInfo> pIWICmntinfo;
GRS_THROW_IF_FAILED(pIWICFactory->CreateComponentInfo(tgFormat, pIWICmntinfo.GetAddressOf()));
WICComponentType type;
GRS_THROW_IF_FAILED(pIWICmntinfo->GetComponentType(&type));
if (type != WICPixelFormat)
{
AtlThrow(S_FALSE);
}
ComPtr<IWICPixelFormatInfo> pIWICPixelinfo;
GRS_THROW_IF_FAILED(pIWICmntinfo.As(&pIWICPixelinfo));
// 到这里终于可以得到BPP了,这也是我看的比较吐血的地方,为了BPP居然饶了这么多环节
GRS_THROW_IF_FAILED(pIWICPixelinfo->GetBitsPerPixel(&nBPP));
// 计算图片实际的行大小(单位:字节),这里使用了一个上取整除法即(A+B-1)/B ,
// 这曾经被传说是微软的面试题,希望你已经对它了如指掌
nPicRowPitch = (UINT)GRS_UPPER_DIV(uint64_t(nTextureW) * uint64_t(nBPP), 8);
size_t szImageBuffer = nPicRowPitch * nTextureH;
//按照实际图片数据存储的内存大小
BYTE* pbPicData = (BYTE*)GRS_CALLOC(szImageBuffer);
if (nullptr == pbPicData)
{
AtlThrowLastWin32();
}
//从图片中读取出数据
GRS_THROW_IF_FAILED(pIBMP->CopyPixels(nullptr
, nPicRowPitch
, static_cast<UINT>(szImageBuffer)
, pbPicData) );
pbImageData = pbPicData;
szBufferSize = szImageBuffer;
}
catch (CAtlException& e)
{//发生了COM异常
e;
bRet = FALSE;
}
catch (...)
{
bRet = FALSE;
}
return bRet;
}
\ No newline at end of file
......@@ -35,6 +35,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "15-CPUThreadsBarrier", "15-
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16-Assimp_Data_Display", "16-Assimp_Data_Display\16-Assimp_Data_Display.vcxproj", "{BE6996B3-DFB4-47C8-8EA2-1209D181D534}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "17-D3D12_Assimp_Animation", "17-D3D12_Assimp_Animation\17-D3D12_Assimp_Animation.vcxproj", "{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
......@@ -237,6 +239,18 @@ Global
{BE6996B3-DFB4-47C8-8EA2-1209D181D534}.Release|x64.Build.0 = Release|x64
{BE6996B3-DFB4-47C8-8EA2-1209D181D534}.Release|x86.ActiveCfg = Release|Win32
{BE6996B3-DFB4-47C8-8EA2-1209D181D534}.Release|x86.Build.0 = Release|Win32
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Debug|x64.ActiveCfg = Debug|x64
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Debug|x64.Build.0 = Debug|x64
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Debug|x86.ActiveCfg = Debug|Win32
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Debug|x86.Build.0 = Debug|Win32
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Profile|x64.ActiveCfg = Debug|x64
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Profile|x64.Build.0 = Debug|x64
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Profile|x86.ActiveCfg = Debug|Win32
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Profile|x86.Build.0 = Debug|Win32
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Release|x64.ActiveCfg = Release|x64
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Release|x64.Build.0 = Release|x64
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Release|x86.ActiveCfg = Release|Win32
{6BFFBD6C-B171-4C22-8878-4BCAFBE4CF0F}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......
......@@ -104,3 +104,8 @@
![image-20210604111201535](ScreenShot/image-20210604111201535.jpg)
# 17-D3D12_Assimp_Animation
&emsp;&emsp;该示例展示了使用Assimp导入动画文件,并用基本的D3D12渲染框架渲染,还没有加任何的光照效果,只是简单的展示3D骨骼动画的基本原理。
![16233246465942021610193211](ScreenShot/16233246465942021610193211.gif)
......@@ -65,3 +65,6 @@ D3D12 ERROR: ID3D12CommandQueue::Present: Resource state (0x800: D3D12_RESOURCE_
1、去除了示例14多线程阴影渲染示例中所有d3dx12.h的引用;目前阴影矩阵还有点问题,没有来及修复,明天看时间调试修复一下;
2021-6-10
1、添加了Assimp导入3D模型,并运行3D骨骼动画的第17号示例;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册