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

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

上级 75eacf58
此差异已折叠。
<?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
此差异已折叠。
#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.
先完成此消息的编辑!
想要评论请 注册