Directx11教程四十二下之進行骨骼動畫的渲染

2021-08-02 02:03:30 字數 4597 閱讀 9180

前面兩小節分別說明了骨骼動畫的數學原理和一種骨骼動畫格式m3d的讀取,這一節講解渲染的思路。

其實,進行骨骼動畫的渲染,整體思路是:

第一,求出某個動畫片段下某乙個時間點下所有骨骼的finalmatrix(由骨骼在某一幀的pos,scale,quat求出)

第二,由於「第一」中渲染骨骼動畫的時間點可能不在整數幀數上,比如我假設某個動畫片段存在50幀畫面,開始時間為0s,結束時間為2.0s,而第48幀畫面的開始時間為1.8s,第49幀的畫面的開始時間為1.9s,而假設你想渲染的動畫時間點為1.85s,所以你想求出所有骨骼的finalmatrix,就需要進行相應的插值,進行平滑過度。

//得到某個骨頭在時間t的變換矩陣

void boneanimation::interpolate(float t, xmfloat4x4& m)const

else if (t >= keyframes.back().timepos)

else}}}

//得到所有骨頭在時間t的變換矩陣陣列,bonetransform[i]代表第i根骨頭在時間t的變換矩陣

void animationclip::interpolate(float t, vector& bonetransform)const

}

bool graphicsclass::renderskeletalcharacter(float deltatime)

//更新第乙個人物的骨骼動畫時間

mcharacterinstance1.update(deltatime);

/*---------------繪製第乙個人物例項(characterinstance1)--------------------*/

//第一,(更新)獲取viewmatrix(根據cameraclass的mpostion和mrotation來生成的)

mfirstcameraclass->updateviewmatrix();

//第二,獲取三個變換矩陣(worldmatrix和projmatrixviewmatrix來自cameraclass)

worldmatrix =xmloadfloat4x4(&mcharacterinstance1.world);

viewmatrix = mfirstcameraclass->getviewmatrix();

projmatrix = md3d->getprojmatrix();

//第三,進行渲染(人物頂點資料,索引資料,各種常量快取,紋理資源等)

for (uint subset = 0; subset < mcharacterinstance1.model->subsetcount; ++subset)

return true;

}

skeletalcharactershader.fx

texture2d diffusemap:register(t0);  //漫反射紋理資源

texture2d normalmap:register(t1); //法線紋理資源

samplerstate sampletype:register(s0); //取樣方式

//vertexshader

cbuffer cbmatrix:register(b0)

;cbuffer cblight:register(b1)

cbuffer cbbonetranform:register(b2)

cbuffer material : register(b3)

cbuffer camera : register(b4)

struct vertexin

;struct vertexout

;float3 normalsampletoworldspace(float3 normalmapsample, float3 unitnormalw, float4 tangentw)

vertexout vs(vertexin ina)

; weights[0] = ina.weights.x;

weights[1] = ina.weights.y;

weights[2] = ina.weights.z;

weights[3] = 1- ina.weights.x- ina.weights.y- ina.weights.z;

float3 posl = float3(0.0f, 0.0f, 0.0f);

float3 normall= float3(0.0f, 0.0f, 0.0f);

float3 tangentl = float3(0.0f, 0.0f, 0.0f);

//將頂點按骨骼權重比進行相應的骨骼變換

for (int i = 0; i < 4; ++i)

//變換到齊次裁剪空間

= mul(ina.posl, world); float3*float4x4 這個並不報錯,忽略了分值w為1.0f

outa.pos = mul(float4(posl, 1.0f), world);

outa.w_pos = outa.pos.xyz;

outa.pos = mul(outa.pos, view);

outa.pos = mul(outa.pos, proj);

//法線變換到世界空間

outa.w_normal = mul(normall, (float3x3)worldinvtranspose); //此事世界逆轉置矩陣的第四行本來就沒啥用

outa.w_normal = normalize(outa.w_normal);

outa.tex= ina.tex;

//切線變換到世界空間

outa.w_tangent = float4(normalize(mul(tangentl, (float3x3)world)), ina.tangentl.w);

return outa;

}float4 ps(vertexout outa) : sv_target

程式執行gif畫面:

//第二十二,例項化skinmodelclass

mcharacterinstance1.model = mcharactermodel;

mcharacterinstance2.model = mcharactermodel;

mcharacterinstance1.timepos = 0.0f;

mcharacterinstance2.timepos = 0.0f;

mcharacterinstance1.clipname = "take1";

mcharacterinstance2.clipname = "take1";

mcharacterinstance1.finaltransforms.resize(mcharactermodel->skinneddata.bonecount());

mcharacterinstance2.finaltransforms.resize(mcharactermodel->skinneddata.bonecount());

xmmatrix modelscale = xmmatrixscaling(0.15f, 0.15f, -0.15f); //

xmmatrix modelrot = xmmatrixrotationy(0);

xmmatrix modeloffset = xmmatrixtranslation(55.0f, 10.0f, 36.0f);

xmstorefloat4x4(&mcharacterinstance1.world, modelscale*modelrot*modeloffset);

xmstorefloat4x4(&mcharacterinstance2.world, modelscale*modelrot*modeloffset);

若不將座標進行z翻轉(乘以負數),人物的渲染結果將出現問題,如下所示:

在寫骨骼動畫渲染的時候,碰上了記憶體訪問錯誤問題,如下圖所示:

一般這種問題的出現,是你訪問了未分配記憶體的位址或者是訪問null指標指向的位址。

在寫這個demo的時候。碰上乙個到目前為止都沒碰上的問題,就是使用float3的posl乘以float4x4,導致圖形完全無法顯示,如下所示:

outa.pos = mul(ina.posl, world)
其中outa.pos為float4型別, float3*float4x4按道理編譯shader會報錯,但實際上並沒有報錯,導致了outa.pos.w預設值為0,而讓圖形無法顯示,這種錯誤有時候真的難以察覺,因為圖形無法顯示,連debug vertexshader和pixelshader的機會都沒有。

Directx11教程四十三之glow 邊緣發光

這一節教程是關於渲染3d物體的發光邊緣,結構如下 這裡借用下虛幻四引擎演示下 邊緣發光效果 如下圖所示 如上面圖中虛幻四引擎中被選中的立方體的邊緣是發光的,我實現的就是這種發光效果 這裡有篇部落格介紹了 glow 是怎麼實現的 unity3d shader 著色器 給物體邊緣加高光輪廓的辦法 這裡大...

Directx11教程37 紋理對映 7

本章是在教程35 36的基礎上來實現乙個光照紋理結合的程式,就是把場景中旋轉的cube加上紋理。lighttex.vs中頂點的結構現在為 struct vertexinputtype 紋理座標 output.tex input.tex 紋理座標不做任何變化,只是單純的從vs輸出到ps中。lightt...

Directx11教程38 紋理對映 8

上篇日誌中,我們用紋理和光照顏色調製的方式得到最終顏色,本章我們嘗試用紋理取樣的顏色,直接做為材質的漫反射係數kd,並用它來做光照計算,最後再做個gamma校正,如果不做的話,效果會偏亮。lighttex.ps主要改動 float4 texturecolor shadertexture.sample...