I figured it would be a bit difficult to pull PRS out of the matrix. I started looking into how shaders work.
I found this vertex shader that will hopefully get me started.
Code: Select all
uniform mat4 bones[100];
uniform int use_skinning;
void main(void)
{
mat4 mfinal = gl_ModelViewMatrix;
// skinning
if(use_skinning==1)
{
vec3 weights= gl_Color.xyz;
vec3 boneid = gl_Vertex.w * vec3( 1.0/128.0 , 1.0 , 128.0 );
boneid = (boneid - floor(boneid))*128.0;
mat4 mskin = bones[int(boneid.x)]*weights.x+
bones[int(boneid.y)]*weights.y+
bones[int(boneid.z)]*weights.z;
mfinal = mfinal * mskin;
}
gl_Position = gl_ProjectionMatrix * mfinal * vec4(gl_Vertex.xyz,1.0);
}
Simple pass-through fragment shader (just displays an unlit, presumably untextured, model)
Code: Select all
#version 330
uniform sampler2D tex;
uniform vec2 tex_size;
layout(location = 0) out vec4 out_color;
void main()
{
vec4 in_color = texture(tex, gl_FragCoord.xy / tex_size);
out_color = in_color;
}
Now we convert from OZZ Matrix4x4 to IRR matrix4
Code: Select all
// Convert from OZZ Float4x4 into IRR matrix4
size_t bone = 0;
while (bone < models_.Count())
{
ozz::math::Float4x4 mat = models_[bone];
Bones_[bone].setM((mat.cols)->m128_f32);
bone++;
}
Code: Select all
class SkinningCallback : public irr::video::IShaderConstantSetCallBack
{
public:
// Matrix array of bone translations in model-space
irr::core::matrix4 *Bones_;
irr::f32 useSkinning;
void OnSetConstants(irr::video::IMaterialRendererServices* services, irr::s32 userData)
{
services->setPixelShaderConstant("bones", Bones_->pointer(), 100);
services->setPixelShaderConstant("useSkinning", &useSkinning, 1);
}
};
Code: Select all
void CreateSkinningShader(irr::IrrlichtDevice* device, irr::video::IVideoDriver* driver, irr::core::matrix4* TranslationMatrix, irr::scene::IAnimatedMeshSceneNode* SceneNode)
{
irr::video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
irr::s32 mtlSkinningShader = irr::video::EMT_SOLID; // Fallback Material
SkinningCallback* callback = new SkinningCallback;
callback->Bones_ = TranslationMatrix;
callback->useSkinning = 1;
irr::io::path VertPath = "skinning.vert";
irr::io::path FragPath = "skinning.frag";
mtlSkinningShader = gpu->addHighLevelShaderMaterialFromFiles(
VertPath, "main", irr::video::EVST_VS_1_1,
FragPath, "main", irr::video::EPST_PS_1_1,
callback, irr::video::EMT_SOLID, 0, irr::video::EGSL_DEFAULT);
SceneNode->setMaterialType((irr::video::E_MATERIAL_TYPE)mtlSkinningShader);
}
From what I understand, the IShaderConstantSetCallBack allows me to initially set parameters to be passed into the shader via setPixelShaderConstant.
Am I able to directly pass ozz::Range<ozz::math::Float4x4>* models_ into the shader with setPixelShaderConstant? (I think I must first convert from OZZ Float4x4 into IRR matrix4).
How do I update the value of this variable later? Or does simply changing the value (since it's a pointer/reference) allow the shader to receive the updated value?
In the shader code, where does it get the variable 'boneid' from?
Finally, what about the fragment shader? I want to continue to let Irrlicht handle the lighting/texturing or do I now have to do this myself since we've overridden the material type with this shader?
The application compiles and displays an unlit and presumably untextured model in it's default T-Pose. I made OZZ step through the animation but the model does not change.
Some quick debugging shows that each call to setPixelShaderConstant return false.
Dream Big Or Go Home.
Help Me Help You.