Re: Setting Bones From Matrix
Posted: Wed Jan 31, 2018 8:58 pm
Check this out
https://mmmovania.blogspot.com/2012/11/ ... nning.html
https://mmmovania.blogspot.com/2012/11/ ... nning.html
Official forum of the Irrlicht Engine
https://irrlicht.sourceforge.io/forum/
Code: Select all
class irrSkinningCallback : public irr::video::IShaderConstantSetCallBack
{
public:
irr::u32 MaxBones = 70;
irr::scene::ISkinnedMesh* Mesh;
irr::f32* Uniforms = new irr::f32[MaxBones * 16];
irr::f32* Uniforms_Scratch = Uniforms;
irr::core::matrix4 BoneTranslation;
bool Update = true;
irrSkinningCallback() : BoneTranslation(irr::core::matrix4::EM4CONST_NOTHING) {}
~irrSkinningCallback()
{
delete[] Uniforms;
}
void SetupNode(irr::video::IVideoDriver* driver, irr::scene::IAnimatedMeshSceneNode* Node)
{
Mesh = (irr::scene::ISkinnedMesh*)Node->getMesh();
MaxBones = Mesh->getAllJoints().size();
Mesh->setHardwareMappingHint(irr::scene::EHM_STATIC, irr::scene::EBT_VERTEX_AND_INDEX);
Mesh->setHardwareSkinning(true);
irr::video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
irr::io::path VertPath = "skinning.vert";
irr::io::path FragPath = "";
irr::s32 mtlSkinningShader = gpu->addHighLevelShaderMaterialFromFiles(
VertPath, "main", irr::video::EVST_VS_4_1,
FragPath, "main", irr::video::EPST_PS_4_1,
this, irr::video::EMT_SOLID, 0, irr::video::EGSL_DEFAULT);
Node->setMaterialType((irr::video::E_MATERIAL_TYPE)mtlSkinningShader);
}
void OnSetConstants(irr::video::IMaterialRendererServices* services, irr::s32 userData)
{
if (Update) {
Update = false;
}
else {
Update = true;
return;
}
Uniforms_Scratch = Uniforms;
for (irr::u32 Bone = 0; Bone < MaxBones; ++Bone)
{
BoneTranslation.setbyproduct(
Mesh->getAllJoints()[Bone]->GlobalAnimatedMatrix,
Mesh->getAllJoints()[Bone]->GlobalInversedMatrix);
for (irr::u8 Float = 0; Float < 16; ++Float) {
*Uniforms_Scratch++ = BoneTranslation[Float];
}
}
services->setVertexShaderConstant("bones[0]", Uniforms, MaxBones * 16);
}
};
class irrAnimator
{
irr::scene::ISceneManager* smgr;
irr::scene::IAnimatedMeshSceneNode* Node;
// Shader Callback
irrSkinningCallback* callback;
public:
irr::scene::IAnimatedMeshSceneNode* GetNode() { return Node; }
irrAnimator(irr::video::IVideoDriver* driver, irr::scene::ISceneManager* SceneManager) : smgr(SceneManager)
{
callback = new irrSkinningCallback;
Node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("dwarf.x"));
Node->setMaterialFlag(irr::video::EMF_LIGHTING, false);
callback->SetupNode(driver, Node); // Apply Skinning Shader
// Hacky way to set vertex weights
irr::scene::ISkinnedMesh* SkinnedMesh = (irr::scene::ISkinnedMesh*)Node->getMesh();
for (irr::u32 Buffer = 0; Buffer < SkinnedMesh->getMeshBuffers().size(); ++Buffer)
{
for (irr::u32 Vert = 0; Vert < SkinnedMesh->getMeshBuffers()[Buffer]->getVertexCount(); ++Vert)
{
SkinnedMesh->getMeshBuffers()[Buffer]->getVertex(Vert)->Color = irr::video::SColor(0, 0, 0, 0);
}
}
for (irr::u32 Joint = 0; Joint < SkinnedMesh->getAllJoints().size(); ++Joint)
{
for (irr::u32 Weight = 0; Weight < SkinnedMesh->getAllJoints()[Joint]->Weights.size(); ++Weight)
{
const irr::u32 buffId = SkinnedMesh->getAllJoints()[Joint]->Weights[Weight].buffer_id;
const irr::u32 vertexId = SkinnedMesh->getAllJoints()[Joint]->Weights[Weight].vertex_id;
irr::video::SColor* vColor = &SkinnedMesh->getMeshBuffers()[buffId]->getVertex(vertexId)->Color;
if (vColor->getRed() == 0)
vColor->setRed(Joint + 1);
else if (vColor->getGreen() == 0)
vColor->setGreen(Joint + 1);
else if (vColor->getBlue() == 0)
vColor->setBlue(Joint + 1);
else if (vColor->getAlpha() == 0)
vColor->setAlpha(Joint + 1);
}
}
}
~irrAnimator()
{
delete callback;
}
};
Code: Select all
uniform mat4 bones[100];
void main(void)
{
int BoneID = int(gl_Color.r * 255);
mat4 vertTran = bones[BoneID - 1];
BoneID = int(gl_Color.g * 255);
if(BoneID > 0)
vertTran += bones[BoneID - 1];
BoneID = int(gl_Color.b * 255);
if(BoneID > 0)
vertTran += bones[BoneID - 1];
BoneID = int(gl_Color.a * 255);
if(BoneID > 0)
vertTran += bones[BoneID - 1];
gl_Position = gl_ModelViewProjectionMatrix * vertTran * gl_Vertex;
gl_FrontColor = vec4(1,1,1,1);
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
}
Code: Select all
int BoneID = int(gl_Color.r * 255);
mat4 vertTran = bones[BoneID - 1];
BoneID = int(gl_Color.g * 255);
if(BoneID > 0)
vertTran += bones[BoneID - 1];
BoneID = int(gl_Color.b * 255);
if(BoneID > 0)
vertTran += bones[BoneID - 1];
BoneID = int(gl_Color.a * 255);
if(BoneID > 0)
vertTran += bones[BoneID - 1];
We already have this in IrrBAWkklouzal wrote:The next thing I'll do is cut it down to 14x14 (196 nodes) and ensure they only update at a fixed 30fps
Code: Select all
//! only for EBUM_NONE and EBUM_READ, it dictates what is the actual frequency we want to bother updating the mesh
//! because we don't want to waste CPU time if we can tolerate the bones updating at 120Hz or similar
virtual void setDesiredUpdateFrequency(const float& hertz) = 0;
Do this to your dwarve nodes, and you'll see this statement is wrong.kklouzal wrote:Sadly turning off hardware skinning and removing the shader gives about a 40% speedup.. Doesn't really make any sense, you would think that speed increase would be in the other direction..
Code: Select all
#define kInstanceSquareSize 25
for (size_t x=0; x<kInstanceSquareSize; x++)
for (size_t z=0; z<kInstanceSquareSize; z++)
dwarfNode[x+kInstanceSquareSize*z] = anode->setAnimationSpeed(18.f*float(x+1+(z+1)*kInstanceSquareSize)/float(kInstanceSquareSize*kInstanceSquareSize));
I'll try to figure these out when I get home from work tonight. I quickly tried the 4x3 matrix tweak but was getting shader compilation errors.One note, instead of accumulating your bone matrices, accumulate vertices transformed by matrices.
..
Final remark, use mat4x3 for the bone matrices, you'll save 25% of the Uniform memory and increase your FPS by 10-25%.