First version of hardware skinning

Todo: shadow, non-instanced shaders, culling, changeable offset...
This commit is contained in:
Benau 2016-12-07 02:15:11 +08:00
parent 23883b83c1
commit 57d9e83ed4
27 changed files with 612 additions and 65 deletions

View File

@ -63,5 +63,11 @@ layout (std140) uniform LightingData
float rL21; float rL21;
float rL22; float rL22;
}; };
layout (std140) uniform SkinningData
{
mat4 joint_matrices[1000];
};
#endif #endif
#endif // HEADER_TXT #endif // HEADER_TXT

View File

@ -0,0 +1,120 @@
layout(location = 0) in vec3 Position;
layout(location = 1) in vec3 Normal;
layout(location = 2) in vec4 Color;
layout(location = 3) in vec4 Data1;
layout(location = 4) in vec4 Data2;
layout(location = 5) in ivec4 Joint;
layout(location = 6) in vec4 Weight;
layout(location = 7) in vec3 Origin;
layout(location = 8) in vec3 Orientation;
layout(location = 9) in vec3 Scale;
layout(location = 10) in vec4 misc_data;
#ifdef Use_Bindless_Texture
layout(location = 11) in sampler2D Handle;
layout(location = 12) in sampler2D SecondHandle;
layout(location = 13) in sampler2D ThirdHandle;
layout(location = 14) in sampler2D FourthHandle;
#endif
layout(location = 15) in uint skinning_offset;
out vec3 nor;
out vec3 tangent;
out vec3 bitangent;
out vec2 uv;
out vec4 color;
out vec2 color_change;
#ifdef Use_Bindless_Texture
flat out sampler2D handle;
flat out sampler2D secondhandle;
flat out sampler2D thirdhandle;
flat out sampler2D fourthhandle;
#endif
#stk_include "utils/getworldmatrix.vert"
void main(void)
{
mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale);
mat4 TransposeInverseModelView = transpose(getInverseWorldMatrix(Origin, Orientation, Scale) * InverseViewMatrix);
vec4 idle_position = vec4(Position, 1.);
vec4 idle_normal = vec4(Normal, 0.);
vec4 skinned_position = vec4(0.);
vec4 skinned_normal = vec4(0.);
// Note : For normal we assume no scale factor in bone (otherwise we'll have to compute inversematrix for each bones...)
vec4 single_bone_influenced_position;
vec4 single_bone_influenced_normal;
if (Joint[0] >= 0)
{
single_bone_influenced_position = joint_matrices[Joint[0] + skinning_offset] * idle_position;
single_bone_influenced_position /= single_bone_influenced_position.w;
single_bone_influenced_normal = joint_matrices[Joint[0] + skinning_offset] * idle_normal;
}
else
{
single_bone_influenced_position = idle_position;
single_bone_influenced_normal = idle_normal;
}
skinned_position += Weight[0] * single_bone_influenced_position;
skinned_normal += Weight[0] * single_bone_influenced_normal;
if (Joint[1] >= 0)
{
single_bone_influenced_position= joint_matrices[Joint[1] + skinning_offset] * idle_position;
single_bone_influenced_position /= single_bone_influenced_position.w;
single_bone_influenced_normal = joint_matrices[Joint[1] + skinning_offset] * idle_normal;
}
else
{
single_bone_influenced_position = idle_position;
single_bone_influenced_normal = idle_normal;
}
skinned_position += Weight[1] * single_bone_influenced_position;
skinned_normal += Weight[1] * single_bone_influenced_normal;
if (Joint[2] >= 0)
{
single_bone_influenced_position = joint_matrices[Joint[2] + skinning_offset] * idle_position;
single_bone_influenced_position /= single_bone_influenced_position.w;
single_bone_influenced_normal = joint_matrices[Joint[2] + skinning_offset] * idle_normal;
}
else
{
single_bone_influenced_position = idle_position;
single_bone_influenced_normal = idle_normal;
}
skinned_position += Weight[2] * single_bone_influenced_position;
skinned_normal += Weight[2] * single_bone_influenced_normal;
if (Joint[3] >= 0)
{
single_bone_influenced_position = joint_matrices[Joint[3] + skinning_offset] * idle_position;
single_bone_influenced_position /= single_bone_influenced_position.w;
single_bone_influenced_normal = joint_matrices[Joint[3] + skinning_offset] * idle_normal;
}
else
{
single_bone_influenced_position = idle_position;
single_bone_influenced_normal = idle_normal;
}
skinned_position += Weight[3] * single_bone_influenced_position;
skinned_normal += Weight[3] * single_bone_influenced_normal;
gl_Position = ProjectionViewMatrix * ModelMatrix * skinned_position;
// Keep orthogonality
nor = (TransposeInverseModelView * skinned_normal).xyz;
// Keep direction
tangent = (ViewMatrix * ModelMatrix * vec4(Data1.z, Data1.w, Data2.x, 0.)).xyz;
bitangent = (ViewMatrix * ModelMatrix * vec4(Data2.y, Data2.z, Data2.w, 0.)).xyz;
uv = vec2(Data1.x + misc_data.x, Data1.y + misc_data.y);
color = Color.zyxw;
color_change = misc_data.zw;
#ifdef Use_Bindless_Texture
handle = Handle;
secondhandle = SecondHandle;
thirdhandle = ThirdHandle;
fourthhandle = FourthHandle;
#endif
}

View File

@ -116,6 +116,8 @@ namespace scene
NewVertices=new CSpecificVertexList<video::S3DVertexTangents>; NewVertices=new CSpecificVertexList<video::S3DVertexTangents>;
break; break;
} }
default:
break;
} }
if (Vertices) if (Vertices)
{ {

View File

@ -371,6 +371,8 @@ protected:
func(verts[i]); func(verts[i]);
} }
break; break;
default:
break;
} }
if (boundingBoxUpdate) if (boundingBoxUpdate)
{ {

View File

@ -26,7 +26,9 @@ enum E_VERTEX_TYPE
//! Vertex with a tangent and binormal vector, video::S3DVertexTangents. //! Vertex with a tangent and binormal vector, video::S3DVertexTangents.
/** Usually used for tangent space normal mapping. */ /** Usually used for tangent space normal mapping. */
EVT_TANGENTS EVT_TANGENTS,
EVT_SKINNED_MESH
}; };
//! Array holding the built in vertex type names //! Array holding the built in vertex type names
@ -251,6 +253,22 @@ struct S3DVertexTangents : public S3DVertex
} }
}; };
struct S3DVertexSkinnedMesh : public S3DVertexTangents
{
s32 m_joint_idx1;
s32 m_joint_idx2;
s32 m_joint_idx3;
s32 m_joint_idx4;
f32 m_weight1;
f32 m_weight2;
f32 m_weight3;
f32 m_weight4;
E_VERTEX_TYPE getType() const
{
return EVT_SKINNED_MESH;
}
};
inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType) inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType)
@ -261,6 +279,8 @@ inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType)
return sizeof(video::S3DVertex2TCoords); return sizeof(video::S3DVertex2TCoords);
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return sizeof(video::S3DVertexTangents); return sizeof(video::S3DVertexTangents);
case video::EVT_SKINNED_MESH:
return sizeof(video::S3DVertexSkinnedMesh);
default: default:
return sizeof(video::S3DVertex); return sizeof(video::S3DVertex);
} }

View File

@ -50,6 +50,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return (video::S3DVertex*)&Vertices_2TCoords[index]; return (video::S3DVertex*)&Vertices_2TCoords[index];
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return (video::S3DVertex*)&Vertices_Tangents[index]; return (video::S3DVertex*)&Vertices_Tangents[index];
case video::EVT_SKINNED_MESH:
return (video::S3DVertex*)&Vertices_SkinnedMesh[index];
default: default:
return &Vertices_Standard[index]; return &Vertices_Standard[index];
} }
@ -64,6 +66,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords.const_pointer(); return Vertices_2TCoords.const_pointer();
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents.const_pointer(); return Vertices_Tangents.const_pointer();
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh.const_pointer();
default: default:
return Vertices_Standard.const_pointer(); return Vertices_Standard.const_pointer();
} }
@ -78,6 +82,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords.pointer(); return Vertices_2TCoords.pointer();
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents.pointer(); return Vertices_Tangents.pointer();
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh.pointer();
default: default:
return Vertices_Standard.pointer(); return Vertices_Standard.pointer();
} }
@ -92,6 +98,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords.size(); return Vertices_2TCoords.size();
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents.size(); return Vertices_Tangents.size();
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh.size();
default: default:
return Vertices_Standard.size(); return Vertices_Standard.size();
} }
@ -180,6 +188,20 @@ struct SSkinMeshBuffer : public IMeshBuffer
} }
break; break;
} }
case video::EVT_SKINNED_MESH:
{
if (Vertices_SkinnedMesh.empty())
BoundingBox.reset(0,0,0);
else
{
BoundingBox.reset(Vertices_SkinnedMesh[0].Pos);
for (u32 i=1; i<Vertices_SkinnedMesh.size(); ++i)
BoundingBox.addInternalPoint(Vertices_SkinnedMesh[i].Pos);
}
break;
}
default:
break;
} }
} }
@ -208,6 +230,23 @@ struct SSkinMeshBuffer : public IMeshBuffer
} }
} }
void convertForSkinning()
{
if (VertexType==video::EVT_STANDARD)
{
for(u32 n=0;n<Vertices_Standard.size();++n)
{
video::S3DVertexSkinnedMesh Vertex = {};
Vertex.Color=Vertices_Standard[n].Color;
Vertex.Pos=Vertices_Standard[n].Pos;
Vertex.Normal=Vertices_Standard[n].Normal;
Vertex.TCoords=Vertices_Standard[n].TCoords;
Vertices_SkinnedMesh.push_back(Vertex);
}
}
}
//! Convert to tangents vertex type //! Convert to tangents vertex type
virtual void convertToTangents() virtual void convertToTangents()
{ {
@ -250,6 +289,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].Pos; return Vertices_2TCoords[i].Pos;
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents[i].Pos; return Vertices_Tangents[i].Pos;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].Pos;
default: default:
return Vertices_Standard[i].Pos; return Vertices_Standard[i].Pos;
} }
@ -264,6 +305,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].Pos; return Vertices_2TCoords[i].Pos;
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents[i].Pos; return Vertices_Tangents[i].Pos;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].Pos;
default: default:
return Vertices_Standard[i].Pos; return Vertices_Standard[i].Pos;
} }
@ -278,6 +321,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].Normal; return Vertices_2TCoords[i].Normal;
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents[i].Normal; return Vertices_Tangents[i].Normal;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].Normal;
default: default:
return Vertices_Standard[i].Normal; return Vertices_Standard[i].Normal;
} }
@ -292,6 +337,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].Normal; return Vertices_2TCoords[i].Normal;
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents[i].Normal; return Vertices_Tangents[i].Normal;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].Normal;
default: default:
return Vertices_Standard[i].Normal; return Vertices_Standard[i].Normal;
} }
@ -306,6 +353,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].TCoords; return Vertices_2TCoords[i].TCoords;
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents[i].TCoords; return Vertices_Tangents[i].TCoords;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].TCoords;
default: default:
return Vertices_Standard[i].TCoords; return Vertices_Standard[i].TCoords;
} }
@ -320,6 +369,8 @@ struct SSkinMeshBuffer : public IMeshBuffer
return Vertices_2TCoords[i].TCoords; return Vertices_2TCoords[i].TCoords;
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return Vertices_Tangents[i].TCoords; return Vertices_Tangents[i].TCoords;
case video::EVT_SKINNED_MESH:
return Vertices_SkinnedMesh[i].TCoords;
default: default:
return Vertices_Standard[i].TCoords; return Vertices_Standard[i].TCoords;
} }
@ -381,6 +432,7 @@ struct SSkinMeshBuffer : public IMeshBuffer
core::array<video::S3DVertexTangents> Vertices_Tangents; core::array<video::S3DVertexTangents> Vertices_Tangents;
core::array<video::S3DVertex2TCoords> Vertices_2TCoords; core::array<video::S3DVertex2TCoords> Vertices_2TCoords;
core::array<video::S3DVertexSkinnedMesh> Vertices_SkinnedMesh;
core::array<video::S3DVertex> Vertices_Standard; core::array<video::S3DVertex> Vertices_Standard;
core::array<u16> Indices; core::array<u16> Indices;

View File

@ -18,7 +18,7 @@ namespace scene
//! constructor //! constructor
CSkinnedMesh::CSkinnedMesh() CSkinnedMesh::CSkinnedMesh()
: SkinningBuffers(0), AnimationFrames(0.f), FramesPerSecond(25.f), : m_joint_total_size(0), SkinningBuffers(0), AnimationFrames(0.f), FramesPerSecond(25.f),
LastAnimatedFrame(-1), SkinnedLastFrame(false), LastAnimatedFrame(-1), SkinnedLastFrame(false),
InterpolationMode(EIM_LINEAR), InterpolationMode(EIM_LINEAR),
HasAnimation(false), PreparedForSkinning(false), HasAnimation(false), PreparedForSkinning(false),
@ -27,7 +27,6 @@ CSkinnedMesh::CSkinnedMesh()
#ifdef _DEBUG #ifdef _DEBUG
setDebugName("CSkinnedMesh"); setDebugName("CSkinnedMesh");
#endif #endif
SkinningBuffers=&LocalBuffers; SkinningBuffers=&LocalBuffers;
} }
@ -74,12 +73,19 @@ void CSkinnedMesh::setAnimationSpeed(f32 fps)
//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level. //! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) IMesh* CSkinnedMesh::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
{ {
const bool is_hw_skinning_before = HardwareSkinning;
if (is_hw_skinning_before)
HardwareSkinning = false;
//animate(frame,startFrameLoop, endFrameLoop); //animate(frame,startFrameLoop, endFrameLoop);
if (frame==-1) if (frame==-1)
return this; return this;
animateMesh((f32)frame, 1.0f); animateMesh((f32)frame, 1.0f);
skinMesh(); skinMesh();
if (is_hw_skinning_before)
HardwareSkinning = true;
return this; return this;
} }
@ -456,7 +462,13 @@ void CSkinnedMesh::skinMesh(f32 strength)
//----------------- //-----------------
SkinnedLastFrame=true; SkinnedLastFrame=true;
if (!HardwareSkinning) m_joint_matrixes.clear();
if (HardwareSkinning)
{
for (u32 i = 0; i < RootJoints.size(); i++)
skinJoint(RootJoints[i], 0, strength);
}
else
{ {
//Software skin.... //Software skin....
u32 i; u32 i;
@ -493,52 +505,58 @@ void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint, f32 strength)
//Find this joints pull on vertices... //Find this joints pull on vertices...
core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING); core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING);
jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix); jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix);
if (HardwareSkinning)
core::vector3df thisVertexMove, thisNormalMove;
core::array<scene::SSkinMeshBuffer*> &buffersUsed=*SkinningBuffers;
//Skin Vertices Positions and Normals...
for (u32 i=0; i<joint->Weights.size(); ++i)
{ {
SWeight& weight = joint->Weights[i]; m_joint_matrixes.push_back(jointVertexPull);
}
else
{
core::vector3df thisVertexMove, thisNormalMove;
// Pull this vertex... core::array<scene::SSkinMeshBuffer*> &buffersUsed=*SkinningBuffers;
jointVertexPull.transformVect(thisVertexMove, weight.StaticPos);
if (AnimateNormals) //Skin Vertices Positions and Normals...
jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal); for (u32 i=0; i<joint->Weights.size(); ++i)
// Apply animation strength
if(strength != 1.f)
{ {
thisVertexMove = core::lerp(weight.StaticPos, thisVertexMove, strength); SWeight& weight = joint->Weights[i];
if(AnimateNormals)
thisNormalMove = core::lerp(weight.StaticNormal, thisNormalMove, strength);
}
if (! (*(weight.Moved)) ) // Pull this vertex...
{ jointVertexPull.transformVect(thisVertexMove, weight.StaticPos);
*(weight.Moved) = true;
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength;
if (AnimateNormals) if (AnimateNormals)
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength; jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal);
//*(weight._Pos) = thisVertexMove * weight.strength; // Apply animation strength
if(strength != 1.f)
{
thisVertexMove = core::lerp(weight.StaticPos, thisVertexMove, strength);
if(AnimateNormals)
thisNormalMove = core::lerp(weight.StaticNormal, thisNormalMove, strength);
}
if (! (*(weight.Moved)) )
{
*(weight.Moved) = true;
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength;
if (AnimateNormals)
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal = thisNormalMove * weight.strength;
//*(weight._Pos) = thisVertexMove * weight.strength;
}
else
{
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength;
if (AnimateNormals)
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength;
//*(weight._Pos) += thisVertexMove * weight.strength;
}
buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated();
} }
else
{
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos += thisVertexMove * weight.strength;
if (AnimateNormals)
buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Normal += thisNormalMove * weight.strength;
//*(weight._Pos) += thisVertexMove * weight.strength;
}
buffersUsed[weight.buffer_id]->boundingBoxNeedsRecalculated();
} }
} }
@ -1382,6 +1400,85 @@ void CSkinnedMesh::addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes,
SkinnedLastFrame=false; SkinnedLastFrame=false;
} }
void CSkinnedMesh::convertForSkinning()
{
if (HardwareSkinning) return;
setHardwareSkinning(true);
WeightInfluence wi;
for (u32 b = 0; b < LocalBuffers.size(); b++)
{
if (LocalBuffers[b])
LocalBuffers[b]->convertForSkinning();
wi.push_back(core::array<core::array<JointInfluence>> ());
for (u32 i = 0; i < LocalBuffers[b]->getVertexCount(); i++)
wi[b].push_back(core::array<JointInfluence>());
}
size_t idx = 0;
for (u32 i = 0; i < RootJoints.size(); i++)
computeWeightInfluence(RootJoints[i], idx, wi);
for (u32 b = 0; b < LocalBuffers.size(); b++)
{
if (LocalBuffers[b])
{
const u32 total = wi[b].size();
_IRR_DEBUG_BREAK_IF(LocalBuffers[b]->getVertexCount() != total);
for (u32 i = 0; i < total; i++)
{
core::array<JointInfluence> this_influence;
core::array<JointInfluence> reported_weight = wi[b][i];
reported_weight.sort();
float remaining_weight = 1.0f;
for (u32 j = 0; j < 4; j++)
{
JointInfluence influence;
if (reported_weight.size() > j)
influence = reported_weight[j];
else
{
influence.joint_idx = -1;
influence.weight = remaining_weight;
}
remaining_weight -= influence.weight;
this_influence.push_back(influence);
}
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_joint_idx1 = this_influence[0].joint_idx;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_joint_idx2 = this_influence[1].joint_idx;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_joint_idx3 = this_influence[2].joint_idx;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_joint_idx4 = this_influence[3].joint_idx;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_weight1 = this_influence[0].weight;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_weight2 = this_influence[1].weight;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_weight3 = this_influence[2].weight;
LocalBuffers[b]->Vertices_SkinnedMesh[i].m_weight4 = this_influence[3].weight;
}
}
}
SkinnedLastFrame = false;
skinMesh();
m_joint_total_size = m_joint_matrixes.size() * sizeof(core::matrix4);
}
void CSkinnedMesh::computeWeightInfluence(SJoint *joint, size_t &index, WeightInfluence& wi)
{
if (!joint->Weights.empty())
{
for (u32 i = 0; i < joint->Weights.size(); i++)
{
SWeight& weight = joint->Weights[i];
JointInfluence tmp;
tmp.joint_idx = index;
tmp.weight = weight.strength;
wi[weight.buffer_id][weight.vertex_id].push_back(tmp);
}
index++;
}
for (u32 j = 0; j < joint->Children.size(); j++)
computeWeightInfluence(joint->Children[j], index, wi);
}
void CSkinnedMesh::convertMeshToTangents() void CSkinnedMesh::convertMeshToTangents()
{ {

View File

@ -14,6 +14,20 @@
#include "matrix4.h" #include "matrix4.h"
#include "quaternion.h" #include "quaternion.h"
class JointInfluence
{
public:
int joint_idx;
float weight;
bool operator < (const JointInfluence& other) const
{
return weight < other.weight;
}
};
typedef irr::core::array<irr::core::array
<irr::core::array<JointInfluence> > > WeightInfluence;
namespace irr namespace irr
{ {
namespace scene namespace scene
@ -25,7 +39,6 @@ namespace scene
class CSkinnedMesh: public ISkinnedMesh class CSkinnedMesh: public ISkinnedMesh
{ {
public: public:
//! constructor //! constructor
CSkinnedMesh(); CSkinnedMesh();
@ -159,6 +172,19 @@ namespace scene
void addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes, void addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes,
IAnimatedMeshSceneNode* node, IAnimatedMeshSceneNode* node,
ISceneManager* smgr); ISceneManager* smgr);
void convertForSkinning();
void computeWeightInfluence(SJoint *joint, size_t &index, WeightInfluence& wi);
const void* getJointPointer() const { return m_joint_matrixes.const_pointer(); }
u32 getTotalJointSize() const
{
_IRR_DEBUG_BREAK_IF(m_joint_total_size == 0);
return m_joint_total_size;
}
private: private:
void checkForAnimation(); void checkForAnimation();
@ -204,7 +230,9 @@ private:
bool HasAnimation; bool HasAnimation;
bool PreparedForSkinning; bool PreparedForSkinning;
bool AnimateNormals; bool AnimateNormals;
bool HardwareSkinning; bool HardwareSkinning;
core::array<core::matrix4> m_joint_matrixes;
u32 m_joint_total_size;
}; };
} // end namespace scene } // end namespace scene

View File

@ -27,6 +27,7 @@ void InstanceFiller<InstanceDataSingleTex>::add(GLMesh* mesh,
{ {
fillOriginOrientationScale<InstanceDataSingleTex>(STK::tuple_get<0>(is), instance); fillOriginOrientationScale<InstanceDataSingleTex>(STK::tuple_get<0>(is), instance);
instance.Texture = mesh->TextureHandles[0]; instance.Texture = mesh->TextureHandles[0];
instance.skinning_offset = STK::tuple_get<3>(is);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -60,6 +61,7 @@ void InstanceFiller<InstanceDataFourTex>::add(GLMesh* mesh,
instance.SecondTexture = mesh->TextureHandles[1]; instance.SecondTexture = mesh->TextureHandles[1];
instance.ThirdTexture = mesh->TextureHandles[2]; instance.ThirdTexture = mesh->TextureHandles[2];
instance.FourthTexture = mesh->TextureHandles[3]; instance.FourthTexture = mesh->TextureHandles[3];
instance.skinning_offset = STK::tuple_get<3>(is);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -172,7 +174,8 @@ void SolidCommandBuffer::fill(SolidPassMeshMap *mesh_map)
std::vector<int> four_tex_material_list = std::vector<int> four_tex_material_list =
createVector<int>(Material::SHADERTYPE_DETAIL_MAP, createVector<int>(Material::SHADERTYPE_DETAIL_MAP,
Material::SHADERTYPE_NORMAL_MAP); Material::SHADERTYPE_NORMAL_MAP,
Material::SHADERTYPE_SOLID_SKINNED_MESH);
fillInstanceData<InstanceDataFourTex, SolidPassMeshMap> fillInstanceData<InstanceDataFourTex, SolidPassMeshMap>
(mesh_map, four_tex_material_list, InstanceTypeFourTex); (mesh_map, four_tex_material_list, InstanceTypeFourTex);

View File

@ -29,7 +29,7 @@
#include <array> #include <array>
#include <unordered_map> #include <unordered_map>
typedef STK::Tuple<scene::ISceneNode*, core::vector2df, core::vector2df> InstanceSettings; typedef STK::Tuple<scene::ISceneNode*, core::vector2df, core::vector2df, uint32_t> InstanceSettings;
struct InstanceList struct InstanceList
{ {

View File

@ -22,6 +22,7 @@
#include "graphics/lod_node.hpp" #include "graphics/lod_node.hpp"
#include "graphics/materials.hpp" #include "graphics/materials.hpp"
#include "graphics/shadow_matrices.hpp" #include "graphics/shadow_matrices.hpp"
#include "graphics/stk_animated_mesh.hpp"
#include "graphics/stk_billboard.hpp" #include "graphics/stk_billboard.hpp"
#include "graphics/stk_mesh.hpp" #include "graphics/stk_mesh.hpp"
#include "graphics/stk_mesh_scene_node.hpp" #include "graphics/stk_mesh_scene_node.hpp"
@ -30,6 +31,8 @@
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/profiler.hpp" #include "utils/profiler.hpp"
#include <numeric>
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void DrawCalls::clearLists() void DrawCalls::clearLists()
{ {
@ -175,6 +178,28 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
return; return;
} }
uint32_t skinning_offset = 0;
STKAnimatedMesh* am = dynamic_cast<STKAnimatedMesh*>(Node);
if (am && am->useHardwareSkinning())
{
SkinningOffset::const_iterator it = m_skinning_offsets.find(am);
if (it != m_skinning_offsets.end())
{
skinning_offset = am->getSkinningOffset() / sizeof(core::matrix4);
}
else
{
const uint32_t cur_offset =
std::accumulate(m_skinning_offsets.begin(),
m_skinning_offsets.end(), 0, [] (const size_t previous,
const std::pair<STKAnimatedMesh*, uint32_t>& p)
{ return previous + p.second; });
am->setSkinningOffset(cur_offset);
m_skinning_offsets[am] = am->getTotalJointSize();
skinning_offset = cur_offset / sizeof(core::matrix4);
}
}
bool culled_for_cams[6] = { true, true, true, true, true, true }; bool culled_for_cams[6] = { true, true, true, true, true, true };
culled_for_cams[0] = isCulledPrecise(cam, Node, culled_for_cams[0] = isCulledPrecise(cam, Node,
irr_driver->getBoundingBoxesViz()); irr_driver->getBoundingBoxesViz());
@ -255,7 +280,7 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{ {
m_glow_pass_mesh[mesh->mb].m_mesh = mesh; m_glow_pass_mesh[mesh->mb].m_mesh = mesh;
m_glow_pass_mesh[mesh->mb].m_instance_settings m_glow_pass_mesh[mesh->mb].m_instance_settings
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f)); .emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f), skinning_offset);
} }
if (Mat == Material::SHADERTYPE_SPLATTING) if (Mat == Material::SHADERTYPE_SPLATTING)
{ {
@ -267,15 +292,12 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
} }
else else
{ {
// Only take render info into account if the node is not static (animated) std::pair<scene::IMeshBuffer*, RenderInfo*> mesh_render_info(mesh->mb, NULL);
// So they can have different animation
std::pair<scene::IMeshBuffer*, RenderInfo*> mesh_render_info(mesh->mb,
dynamic_cast<STKMeshSceneNode*>(Node) == NULL ? mesh->m_render_info : NULL);
m_solid_pass_mesh[Mat][mesh_render_info].m_mesh = mesh; m_solid_pass_mesh[Mat][mesh_render_info].m_mesh = mesh;
m_solid_pass_mesh[Mat][mesh_render_info].m_instance_settings.emplace_back(Node, mesh->texture_trans, m_solid_pass_mesh[Mat][mesh_render_info].m_instance_settings.emplace_back(Node, mesh->texture_trans,
(mesh->m_render_info && mesh->m_material ? (mesh->m_render_info && mesh->m_material ?
core::vector2df(mesh->m_render_info->getHue(), mesh->m_material->getColorizationFactor()) : core::vector2df(mesh->m_render_info->getHue(), mesh->m_material->getColorizationFactor()) :
core::vector2df(0.0f, 0.0f))); core::vector2df(0.0f, 0.0f)), skinning_offset);
} }
} }
} }
@ -351,7 +373,7 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{ {
m_shadow_pass_mesh[cascade * Material::SHADERTYPE_COUNT + Mat][mesh->mb].m_mesh = mesh; m_shadow_pass_mesh[cascade * Material::SHADERTYPE_COUNT + Mat][mesh->mb].m_mesh = mesh;
m_shadow_pass_mesh[cascade * Material::SHADERTYPE_COUNT + Mat][mesh->mb].m_instance_settings m_shadow_pass_mesh[cascade * Material::SHADERTYPE_COUNT + Mat][mesh->mb].m_instance_settings
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f)); .emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f), skinning_offset);
} }
} }
else else
@ -419,7 +441,7 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node,
{ {
m_reflective_shadow_map_mesh[Mat][mesh->mb].m_mesh = mesh; m_reflective_shadow_map_mesh[Mat][mesh->mb].m_mesh = mesh;
m_reflective_shadow_map_mesh[Mat][mesh->mb].m_instance_settings m_reflective_shadow_map_mesh[Mat][mesh->mb].m_instance_settings
.emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f)); .emplace_back(Node, core::vector2df(0.0f, 0.0f), core::vector2df(0.0f, 0.0f), skinning_offset);
} }
} }
} }
@ -683,6 +705,7 @@ void DrawCalls::drawIndirectSolidFirstPass() const
{ {
m_solid_cmd_buffer->bind(); m_solid_cmd_buffer->bind();
m_solid_cmd_buffer->drawIndirectFirstPass<DefaultMaterial>(); m_solid_cmd_buffer->drawIndirectFirstPass<DefaultMaterial>();
m_solid_cmd_buffer->drawIndirectFirstPass<SkinnedSolid>();
m_solid_cmd_buffer->drawIndirectFirstPass<AlphaRef>(); m_solid_cmd_buffer->drawIndirectFirstPass<AlphaRef>();
m_solid_cmd_buffer->drawIndirectFirstPass<UnlitMat>(); m_solid_cmd_buffer->drawIndirectFirstPass<UnlitMat>();
m_solid_cmd_buffer->drawIndirectFirstPass<SphereMap>(); m_solid_cmd_buffer->drawIndirectFirstPass<SphereMap>();
@ -718,6 +741,7 @@ void DrawCalls::drawIndirectSolidSecondPass(const std::vector<GLuint> &prefilled
{ {
m_solid_cmd_buffer->bind(); m_solid_cmd_buffer->bind();
m_solid_cmd_buffer->drawIndirectSecondPass<DefaultMaterial>(prefilled_tex); m_solid_cmd_buffer->drawIndirectSecondPass<DefaultMaterial>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<SkinnedSolid>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<AlphaRef>(prefilled_tex); m_solid_cmd_buffer->drawIndirectSecondPass<AlphaRef>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<UnlitMat>(prefilled_tex); m_solid_cmd_buffer->drawIndirectSecondPass<UnlitMat>(prefilled_tex);
m_solid_cmd_buffer->drawIndirectSecondPass<SphereMap>(prefilled_tex); m_solid_cmd_buffer->drawIndirectSecondPass<SphereMap>(prefilled_tex);

View File

@ -24,8 +24,11 @@
class ParticleSystemProxy; class ParticleSystemProxy;
class ShadowMatrices; class ShadowMatrices;
class STKAnimatedMesh;
class STKBillboard; class STKBillboard;
typedef std::unordered_map<STKAnimatedMesh*, uint32_t> SkinningOffset;
class DrawCalls class DrawCalls
{ {
private: private:
@ -36,6 +39,7 @@ private:
std::vector<irr::scene::ISceneNode *> m_immediate_draw_list; std::vector<irr::scene::ISceneNode *> m_immediate_draw_list;
std::vector<STKBillboard *> m_billboard_list; std::vector<STKBillboard *> m_billboard_list;
std::vector<ParticleSystemProxy *> m_particles_list; std::vector<ParticleSystemProxy *> m_particles_list;
SkinningOffset m_skinning_offsets;
std::vector<float> m_bounding_boxes; std::vector<float> m_bounding_boxes;
@ -105,6 +109,7 @@ public:
void drawIndirectGlow() const; void drawIndirectGlow() const;
void multidrawGlow() const; void multidrawGlow() const;
void renderBoundingBoxes(); void renderBoundingBoxes();
void resetSkinningOffsets() { m_skinning_offsets.clear(); }
}; };
#endif //HEADER_DRAW_CALLS_HPP #endif //HEADER_DRAW_CALLS_HPP

View File

@ -140,6 +140,22 @@ public:
glEnableVertexAttribArray(6); glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)48); glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)48);
break; break;
case video::EVT_SKINNED_MESH:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)12);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, getVertexPitchFromType(tp), (GLvoid*)24);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)28);
glEnableVertexAttribArray(3);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)44);
glEnableVertexAttribArray(5);
glVertexAttribIPointer(5, 4, GL_INT, getVertexPitchFromType(tp), (GLvoid*)60);
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)76);
break;
} }
} }
}; };

View File

@ -48,6 +48,7 @@ public:
enum ShaderType enum ShaderType
{ {
SHADERTYPE_SOLID = 0, SHADERTYPE_SOLID = 0,
SHADERTYPE_SOLID_SKINNED_MESH,
SHADERTYPE_ALPHA_TEST, SHADERTYPE_ALPHA_TEST,
SHADERTYPE_ALPHA_BLEND, SHADERTYPE_ALPHA_BLEND,
SHADERTYPE_ADDITIVE, SHADERTYPE_ADDITIVE,

View File

@ -24,6 +24,14 @@ const STK::Tuple<size_t, size_t, size_t> DefaultMaterial::SecondPassTextures
const STK::Tuple<> DefaultMaterial::ShadowTextures; const STK::Tuple<> DefaultMaterial::ShadowTextures;
const STK::Tuple<size_t> DefaultMaterial::RSMTextures = STK::Tuple<size_t>(0); const STK::Tuple<size_t> DefaultMaterial::RSMTextures = STK::Tuple<size_t>(0);
// ----------------------------------------------------------------------------
const STK::Tuple<size_t> SkinnedSolid::FirstPassTextures
= STK::Tuple<size_t>(1);
const STK::Tuple<size_t, size_t, size_t> SkinnedSolid::SecondPassTextures
= STK::Tuple<size_t, size_t, size_t>(0, 1, 2);
const STK::Tuple<> SkinnedSolid::ShadowTextures;
const STK::Tuple<size_t> SkinnedSolid::RSMTextures = STK::Tuple<size_t>(0);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
const STK::Tuple<size_t, size_t> AlphaRef::FirstPassTextures const STK::Tuple<size_t, size_t> AlphaRef::FirstPassTextures
= STK::Tuple<size_t, size_t>(0, 1); = STK::Tuple<size_t, size_t>(0, 1);

View File

@ -616,8 +616,61 @@ public:
} // InstancedDetailedObjectPass2Shader } // InstancedDetailedObjectPass2Shader
}; // InstancedDetailedObjectPass2Shader }; // InstancedDetailedObjectPass2Shader
// ============================================================================
class InstancedSkinnedMeshPass1Shader : public TextureShader<InstancedSkinnedMeshPass1Shader, 1>
{
public:
InstancedSkinnedMeshPass1Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning.vert",
GL_FRAGMENT_SHADER, "instanced_object_pass1.frag");
assignUniforms();
assignSamplerNames(0, "glosstex", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSkinnedMeshPass1Shader
}; // InstancedSkinnedMeshPass1Shader
// ============================================================================ // ============================================================================
class InstancedSkinnedMeshPass2Shader : public TextureShader<InstancedSkinnedMeshPass2Shader, 6>
{
public:
InstancedSkinnedMeshPass2Shader()
{
loadProgram(OBJECT, GL_VERTEX_SHADER, "instanced_skinning.vert",
GL_FRAGMENT_SHADER, "instanced_object_pass2.frag");
assignUniforms();
assignSamplerNames(0, "DiffuseMap", ST_NEAREST_FILTERED,
1, "SpecularMap", ST_NEAREST_FILTERED,
2, "SSAO", ST_BILINEAR_FILTERED,
3, "Albedo", ST_TRILINEAR_ANISOTROPIC_FILTERED,
4, "SpecMap", ST_TRILINEAR_ANISOTROPIC_FILTERED,
5, "colorization_mask", ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // InstancedSkinnedMeshPass2Shader
}; // InstancedSkinnedMeshPass2Shader
// ============================================================================
struct SkinnedSolid
{
typedef InstancedSkinnedMeshPass1Shader InstancedFirstPassShader;
typedef InstancedSkinnedMeshPass2Shader InstancedSecondPassShader;
//typedef InstancedShadowShader InstancedShadowPassShader;
//typedef CInstancedRSMShader InstancedRSMShader;
//typedef Shaders::ObjectPass1Shader FirstPassShader;
//typedef Shaders::ObjectPass2Shader SecondPassShader;
//typedef ShadowShader ShadowPassShader;
//typedef CRSMShader RSMShader;
typedef ListSkinnedSolid List;
static const enum video::E_VERTEX_TYPE VertexType = video::EVT_SKINNED_MESH;
static const enum Material::ShaderType MaterialType
= Material::SHADERTYPE_SOLID_SKINNED_MESH;
static const enum InstanceType Instance = InstanceTypeFourTex;
static const STK::Tuple<size_t> FirstPassTextures;
static const STK::Tuple<size_t, size_t, size_t> SecondPassTextures;
static const STK::Tuple<> ShadowTextures;
static const STK::Tuple<size_t> RSMTextures;
}; // struct DefaultMaterial
// ----------------------------------------------------------------------------
struct DefaultMaterial struct DefaultMaterial
{ {
typedef InstancedObjectPass1Shader InstancedFirstPassShader; typedef InstancedObjectPass1Shader InstancedFirstPassShader;

View File

@ -476,7 +476,7 @@ scene::IMesh* MeshTools::createMeshWithTangents(scene::IMesh* mesh,
void MeshTools::createSkinnedMeshWithTangents(scene::ISkinnedMesh* mesh, void MeshTools::createSkinnedMeshWithTangents(scene::ISkinnedMesh* mesh,
bool(*predicate)(scene::IMeshBuffer*)) bool(*predicate)(scene::IMeshBuffer*))
{ {return;
core::array<scene::SSkinMeshBuffer*>& all_mb = mesh->getMeshBuffers(); core::array<scene::SSkinMeshBuffer*>& all_mb = mesh->getMeshBuffers();
const int all_mb_size = all_mb.size(); const int all_mb_size = all_mb.size();
for (int i = 0; i < all_mb_size; i++) for (int i = 0; i < all_mb_size; i++)

View File

@ -150,6 +150,7 @@ private:
{ {
bindPoint("MatrixData", 0); bindPoint("MatrixData", 0);
bindPoint("LightingData", 1); bindPoint("LightingData", 1);
bindPoint("SkinningData", 2);
} // assignUniformsImpl } // assignUniformsImpl
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -270,6 +270,7 @@ void ShaderBasedRenderer::renderScene(scene::ICameraSceneNode * const camnode,
{ {
glBindBufferBase(GL_UNIFORM_BUFFER, 0, SharedGPUObjects::getViewProjectionMatricesUBO()); glBindBufferBase(GL_UNIFORM_BUFFER, 0, SharedGPUObjects::getViewProjectionMatricesUBO());
glBindBufferBase(GL_UNIFORM_BUFFER, 1, SharedGPUObjects::getLightingDataUBO()); glBindBufferBase(GL_UNIFORM_BUFFER, 1, SharedGPUObjects::getLightingDataUBO());
glBindBufferBase(GL_UNIFORM_BUFFER, 2, SharedGPUObjects::getSkinningUBO());
} }
irr_driver->getSceneManager()->setActiveCamera(camnode); irr_driver->getSceneManager()->setActiveCamera(camnode);
@ -697,6 +698,7 @@ void ShaderBasedRenderer::onUnloadWorld()
delete m_rtts; delete m_rtts;
m_rtts = NULL; m_rtts = NULL;
removeSkyBox(); removeSkyBox();
m_draw_calls.resetSkinningOffsets();
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -29,6 +29,7 @@ GLuint SharedGPUObjects::m_full_screen_quad_vao;
GLuint SharedGPUObjects::m_ui_vao; GLuint SharedGPUObjects::m_ui_vao;
GLuint SharedGPUObjects::m_quad_buffer; GLuint SharedGPUObjects::m_quad_buffer;
GLuint SharedGPUObjects::m_quad_vbo; GLuint SharedGPUObjects::m_quad_vbo;
GLuint SharedGPUObjects::m_skinning_ubo;
bool SharedGPUObjects::m_has_been_initialised = false; bool SharedGPUObjects::m_has_been_initialised = false;
/** Initialises m_full_screen_quad_vbo. /** Initialises m_full_screen_quad_vbo.
@ -166,6 +167,17 @@ void SharedGPUObjects::initLightingDataUBO()
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
} // initLightingDataUBO } // initLightingDataUBO
// ----------------------------------------------------------------------------
void SharedGPUObjects::initSkinningUBO()
{
assert(CVS->isARBUniformBufferObjectUsable());
glGenBuffers(1, &m_skinning_ubo);
glBindBuffer(GL_UNIFORM_BUFFER, m_skinning_ubo);
glBufferData(GL_UNIFORM_BUFFER, 1000 * 16 * sizeof(float), 0,
GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
} // initSkinningUBO
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void SharedGPUObjects::initParticleQuadVBO() void SharedGPUObjects::initParticleQuadVBO()
{ {
@ -198,7 +210,8 @@ void SharedGPUObjects::init()
if(CVS->isARBUniformBufferObjectUsable()) if(CVS->isARBUniformBufferObjectUsable())
{ {
initShadowVPMUBO(); initShadowVPMUBO();
initLightingDataUBO(); initLightingDataUBO();
initSkinningUBO();
} }
m_has_been_initialised = true; m_has_been_initialised = true;

View File

@ -37,6 +37,7 @@ private:
static GLuint m_ui_vao; static GLuint m_ui_vao;
static GLuint m_quad_buffer; static GLuint m_quad_buffer;
static GLuint m_quad_vbo; static GLuint m_quad_vbo;
static GLuint m_skinning_ubo;
static void initQuadVBO(); static void initQuadVBO();
static void initQuadBuffer(); static void initQuadBuffer();
@ -46,6 +47,7 @@ private:
static void initShadowVPMUBO(); static void initShadowVPMUBO();
static void initLightingDataUBO(); static void initLightingDataUBO();
static void initParticleQuadVBO(); static void initParticleQuadVBO();
static void initSkinningUBO();
public: public:
static void init(); static void init();
@ -116,6 +118,12 @@ public:
assert(m_has_been_initialised); assert(m_has_been_initialised);
return m_quad_vbo; return m_quad_vbo;
} // getQuadVBO } // getQuadVBO
// ------------------------------------------------------------------------
static GLuint getSkinningUBO()
{
assert(m_has_been_initialised);
return m_skinning_ubo;
} // getSkinningUBO
}; // class SharedGPUObjecctS }; // class SharedGPUObjecctS

View File

@ -20,12 +20,13 @@
#include "graphics/central_settings.hpp" #include "graphics/central_settings.hpp"
#include "graphics/material_manager.hpp" #include "graphics/material_manager.hpp"
#include "graphics/render_info.hpp" #include "graphics/render_info.hpp"
#include "graphics/shared_gpu_objects.hpp"
#include "graphics/stk_mesh.hpp" #include "graphics/stk_mesh.hpp"
#include "graphics/vao_manager.hpp" #include "graphics/vao_manager.hpp"
#include <IMaterialRenderer.h> #include <IMaterialRenderer.h>
#include <ISceneManager.h> #include <ISceneManager.h>
#include <ISkinnedMesh.h> #include "../../lib/irrlicht/source/Irrlicht/CSkinnedMesh.h"
using namespace irr; using namespace irr;
@ -34,7 +35,7 @@ irr::scene::ISceneManager* mgr, s32 id, const std::string& debug_name,
const core::vector3df& position, const core::vector3df& position,
const core::vector3df& rotation, const core::vector3df& rotation,
const core::vector3df& scale, RenderInfo* render_info, bool all_parts_colorized) : const core::vector3df& scale, RenderInfo* render_info, bool all_parts_colorized) :
CAnimatedMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale) CAnimatedMeshSceneNode(mesh, parent, mgr, id, position, rotation, scale), m_skinned_mesh(NULL)
{ {
isGLInitialized = false; isGLInitialized = false;
isMaterialInitialized = false; isMaterialInitialized = false;
@ -43,6 +44,10 @@ const core::vector3df& scale, RenderInfo* render_info, bool all_parts_colorized)
#ifdef DEBUG #ifdef DEBUG
m_debug_name = debug_name; m_debug_name = debug_name;
#endif #endif
m_skinning_offset = -1;
m_skinned_mesh = dynamic_cast<scene::CSkinnedMesh*>(Mesh);
if (m_skinned_mesh)
m_skinned_mesh->convertForSkinning();
} }
STKAnimatedMesh::~STKAnimatedMesh() STKAnimatedMesh::~STKAnimatedMesh()
@ -108,6 +113,16 @@ void STKAnimatedMesh::updateNoGL()
for (u32 i = 0; i < mb_count; ++i) for (u32 i = 0; i < mb_count; ++i)
{ {
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
if (!mb)
continue;
scene::SSkinMeshBuffer* ssmb = NULL;
if (m_skinned_mesh)
{
ssmb = dynamic_cast<scene::SSkinMeshBuffer*>(mb);
ssmb->VertexType = video::EVT_SKINNED_MESH;
}
bool affected = false; bool affected = false;
RenderInfo* cur_ri = m_mesh_render_info; RenderInfo* cur_ri = m_mesh_render_info;
if (!m_all_parts_colorized && mb && cur_ri) if (!m_all_parts_colorized && mb && cur_ri)
@ -142,6 +157,8 @@ void STKAnimatedMesh::updateNoGL()
GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name, GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name,
affected || m_all_parts_colorized || (cur_ri affected || m_all_parts_colorized || (cur_ri
&& cur_ri->isTransparent()) ? cur_ri : default_ri)); && cur_ri->isTransparent()) ? cur_ri : default_ri));
if (m_skinned_mesh) ssmb->VertexType = video::EVT_STANDARD;
} }
for (u32 i = 0; i < m->getMeshBufferCount(); ++i) for (u32 i = 0; i < m->getMeshBufferCount(); ++i)
@ -162,7 +179,7 @@ void STKAnimatedMesh::updateNoGL()
GLMesh &mesh = GLmeshes[i]; GLMesh &mesh = GLmeshes[i];
Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb); Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb);
if (rnd->isTransparent()) /*if (rnd->isTransparent())
{ {
TransparentMaterial TranspMat = getTransparentMaterialFromType(type, MaterialTypeParam, material); TransparentMaterial TranspMat = getTransparentMaterialFromType(type, MaterialTypeParam, material);
TransparentMesh[TranspMat].push_back(&mesh); TransparentMesh[TranspMat].push_back(&mesh);
@ -174,10 +191,10 @@ void STKAnimatedMesh::updateNoGL()
else else
TransparentMesh[TM_TRANSLUCENT_STD].push_back(&mesh); TransparentMesh[TM_TRANSLUCENT_STD].push_back(&mesh);
} }
else else*/
{ {
Material::ShaderType MatType = getMeshMaterialFromType(type, mb->getVertexType(), material, NULL); Material::ShaderType MatType = getMeshMaterialFromType(type, mb->getVertexType(), material, NULL);
MeshSolidMaterial[MatType].push_back(&mesh); MeshSolidMaterial[m_skinned_mesh ? Material::SHADERTYPE_SOLID_SKINNED_MESH : MatType].push_back(&mesh);
} }
} }
isMaterialInitialized = true; isMaterialInitialized = true;
@ -213,6 +230,13 @@ void STKAnimatedMesh::updateGL()
scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i);
if (!mb) if (!mb)
continue; continue;
scene::SSkinMeshBuffer* ssmb = NULL;
if (m_skinned_mesh)
{
ssmb = dynamic_cast<scene::SSkinMeshBuffer*>(mb);
ssmb->VertexType = video::EVT_SKINNED_MESH;
}
video::IVideoDriver* driver = SceneManager->getVideoDriver(); video::IVideoDriver* driver = SceneManager->getVideoDriver();
video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType; video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType;
video::IMaterialRenderer* rnd = driver->getMaterialRenderer(type); video::IMaterialRenderer* rnd = driver->getMaterialRenderer(type);
@ -233,7 +257,7 @@ void STKAnimatedMesh::updateGL()
if (CVS->isARBBaseInstanceUsable()) if (CVS->isARBBaseInstanceUsable())
{ {
std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb, GLmeshes[i].m_render_info); std::pair<unsigned, unsigned> p = VAOManager::getInstance()->getBase(mb,NULL /*GLmeshes[i].m_render_info*/);
mesh.vaoBaseVertex = p.first; mesh.vaoBaseVertex = p.first;
mesh.vaoOffset = p.second; mesh.vaoOffset = p.second;
} }
@ -243,10 +267,20 @@ void STKAnimatedMesh::updateGL()
mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, mb->getVertexType()); mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, mb->getVertexType());
glBindVertexArray(0); glBindVertexArray(0);
} }
if (m_skinned_mesh) ssmb->VertexType = video::EVT_STANDARD;
} }
isGLInitialized = true; isGLInitialized = true;
} }
if (m_skinned_mesh)
{
assert(m_skinning_offset != -1);
glBindBuffer(GL_UNIFORM_BUFFER, SharedGPUObjects::getSkinningUBO());
glBufferSubData(GL_UNIFORM_BUFFER, m_skinning_offset,
m_skinned_mesh->getTotalJointSize(), m_skinned_mesh->getJointPointer());
return;
}
for (u32 i = 0; i<m->getMeshBufferCount(); ++i) for (u32 i = 0; i<m->getMeshBufferCount(); ++i)
{ {
scene::IMeshBuffer* mb = m->getMeshBuffer(i); scene::IMeshBuffer* mb = m->getMeshBuffer(i);
@ -289,3 +323,8 @@ void STKAnimatedMesh::render()
updateNoGL(); updateNoGL();
updateGL(); updateGL();
} }
int STKAnimatedMesh::getTotalJointSize() const
{
return m_skinned_mesh->getTotalJointSize();
}

View File

@ -26,6 +26,10 @@
#include <irrTypes.h> #include <irrTypes.h>
class RenderInfo; class RenderInfo;
namespace irr
{
namespace scene { class CSkinnedMesh; }
}
class STKAnimatedMesh : public irr::scene::CAnimatedMeshSceneNode, public STKMeshCommon class STKAnimatedMesh : public irr::scene::CAnimatedMeshSceneNode, public STKMeshCommon
{ {
@ -50,9 +54,15 @@ public:
virtual void render(); virtual void render();
virtual void setMesh(irr::scene::IAnimatedMesh* mesh); virtual void setMesh(irr::scene::IAnimatedMesh* mesh);
virtual bool glow() const { return false; } virtual bool glow() const { return false; }
int getTotalJointSize() const;
int getSkinningOffset() const { return m_skinning_offset; }
void setSkinningOffset(int offset) { m_skinning_offset = offset; }
bool useHardwareSkinning() const { return m_skinned_mesh!= NULL; }
private: private:
RenderInfo* m_mesh_render_info; RenderInfo* m_mesh_render_info;
bool m_all_parts_colorized; bool m_all_parts_colorized;
irr::scene::CSkinnedMesh* m_skinned_mesh;
int m_skinning_offset;
}; };
#endif // STKANIMATEDMESH_HPP #endif // STKANIMATEDMESH_HPP

View File

@ -155,6 +155,22 @@ GLuint createVAO(GLuint vbo, GLuint idx, video::E_VERTEX_TYPE type)
glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE,
getVertexPitchFromType(type), (GLvoid*)48); getVertexPitchFromType(type), (GLvoid*)48);
break; break;
case video::EVT_SKINNED_MESH:
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)12);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, getVertexPitchFromType(type), (GLvoid*)24);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)28);
glEnableVertexAttribArray(3);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)44);
glEnableVertexAttribArray(5);
glVertexAttribIPointer(5, 4, GL_INT, getVertexPitchFromType(type), (GLvoid*)60);
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)76);
break;
default: default:
assert(0 && "Wrong vertex type"); assert(0 && "Wrong vertex type");
} }
@ -346,8 +362,8 @@ static void setTexture(GLMesh &mesh, unsigned i, bool is_srgb,
{ {
if (!mesh.textures[i]) if (!mesh.textures[i])
{ {
Log::error("STKMesh", "Missing texture %d for material %s", i, //Log::error("STKMesh", "Missing texture %d for material %s", i,
mat_name.c_str()); // mat_name.c_str());
// use unicolor texture to replace missing texture // use unicolor texture to replace missing texture
mesh.textures[i] = mesh.textures[i] =
getUnicolorTexture(video::SColor(255, 127, 127, 127)); getUnicolorTexture(video::SColor(255, 127, 127, 127));
@ -413,6 +429,7 @@ void initTextures(GLMesh &mesh, Material::ShaderType mat)
break; break;
case Material::SHADERTYPE_DETAIL_MAP: case Material::SHADERTYPE_DETAIL_MAP:
case Material::SHADERTYPE_NORMAL_MAP: case Material::SHADERTYPE_NORMAL_MAP:
case Material::SHADERTYPE_SOLID_SKINNED_MESH:
setTexture(mesh, 0, true, getShaderTypeName(mat)); setTexture(mesh, 0, true, getShaderTypeName(mat));
setTexture(mesh, 1, false, getShaderTypeName(mat)); setTexture(mesh, 1, false, getShaderTypeName(mat));
setTexture(mesh, 2, false, getShaderTypeName(mat)); setTexture(mesh, 2, false, getShaderTypeName(mat));

View File

@ -116,6 +116,12 @@ class ListMatDefault : public MeshList<ListMatDefault, GLMesh *, core::matrix4,
core::vector2df> core::vector2df>
{}; {};
// ----------------------------------------------------------------------------
class ListSkinnedSolid : public MeshList<ListSkinnedSolid, GLMesh *, core::matrix4,
core::matrix4, core::vector2df,
core::vector2df>
{};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class ListMatAlphaRef : public MeshList<ListMatAlphaRef, GLMesh *, core::matrix4, class ListMatAlphaRef : public MeshList<ListMatAlphaRef, GLMesh *, core::matrix4,
core::matrix4, core::vector2df, core::matrix4, core::vector2df,

View File

@ -161,6 +161,9 @@ void VAOInstanceUtil<InstanceDataSingleTex>::SetVertexAttrib()
glEnableVertexAttribArray(11); glEnableVertexAttribArray(11);
glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceDataSingleTex), (GLvoid*)(9 * sizeof(float))); glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceDataSingleTex), (GLvoid*)(9 * sizeof(float)));
glVertexAttribDivisorARB(11, 1); glVertexAttribDivisorARB(11, 1);
glEnableVertexAttribArray(15);
glVertexAttribIPointer(15, 1, GL_UNSIGNED_INT, sizeof(InstanceDataSingleTex), (GLvoid*)(11 * sizeof(float)));
glVertexAttribDivisorARB(15, 1);
} }
template<> template<>
@ -200,6 +203,9 @@ void VAOInstanceUtil<InstanceDataFourTex>::SetVertexAttrib()
glEnableVertexAttribArray(14); glEnableVertexAttribArray(14);
glVertexAttribIPointer(14, 2, GL_UNSIGNED_INT, sizeof(InstanceDataFourTex), (GLvoid*)(13 * sizeof(float) + 6 * sizeof(unsigned))); glVertexAttribIPointer(14, 2, GL_UNSIGNED_INT, sizeof(InstanceDataFourTex), (GLvoid*)(13 * sizeof(float) + 6 * sizeof(unsigned)));
glVertexAttribDivisorARB(14, 1); glVertexAttribDivisorARB(14, 1);
glEnableVertexAttribArray(15);
glVertexAttribIPointer(15, 1, GL_UNSIGNED_INT, sizeof(InstanceDataFourTex), (GLvoid*)(13 * sizeof(float) + 8 * sizeof(unsigned)));
glVertexAttribDivisorARB(15, 1);
} }
template<> template<>
@ -216,7 +222,7 @@ void VAOManager::regenerateInstancedVAO()
{ {
cleanInstanceVAOs(); cleanInstanceVAOs();
enum video::E_VERTEX_TYPE IrrVT[] = { video::EVT_STANDARD, video::EVT_2TCOORDS, video::EVT_TANGENTS }; enum video::E_VERTEX_TYPE IrrVT[] = { video::EVT_STANDARD, video::EVT_2TCOORDS, video::EVT_TANGENTS, video::EVT_SKINNED_MESH };
for (unsigned i = 0; i < VTXTYPE_COUNT; i++) for (unsigned i = 0; i < VTXTYPE_COUNT; i++)
{ {
video::E_VERTEX_TYPE tp = IrrVT[i]; video::E_VERTEX_TYPE tp = IrrVT[i];
@ -264,6 +270,8 @@ size_t VAOManager::getVertexPitch(enum VTXTYPE tp) const
return getVertexPitchFromType(video::EVT_2TCOORDS); return getVertexPitchFromType(video::EVT_2TCOORDS);
case VTXTYPE_TANGENT: case VTXTYPE_TANGENT:
return getVertexPitchFromType(video::EVT_TANGENTS); return getVertexPitchFromType(video::EVT_TANGENTS);
case VTXTYPE_SKINNED_MESH:
return getVertexPitchFromType(video::EVT_SKINNED_MESH);
default: default:
assert(0 && "Wrong vtxtype"); assert(0 && "Wrong vtxtype");
return -1; return -1;
@ -282,6 +290,8 @@ VAOManager::VTXTYPE VAOManager::getVTXTYPE(video::E_VERTEX_TYPE type)
return VTXTYPE_TCOORD; return VTXTYPE_TCOORD;
case video::EVT_TANGENTS: case video::EVT_TANGENTS:
return VTXTYPE_TANGENT; return VTXTYPE_TANGENT;
case video::EVT_SKINNED_MESH:
return VTXTYPE_SKINNED_MESH;
} }
}; };
@ -296,6 +306,8 @@ irr::video::E_VERTEX_TYPE VAOManager::getVertexType(enum VTXTYPE tp)
return video::EVT_2TCOORDS; return video::EVT_2TCOORDS;
case VTXTYPE_TANGENT: case VTXTYPE_TANGENT:
return video::EVT_TANGENTS; return video::EVT_TANGENTS;
case VTXTYPE_SKINNED_MESH:
return video::EVT_SKINNED_MESH;
} }
} }

View File

@ -62,6 +62,7 @@ struct InstanceDataSingleTex
float Z; float Z;
} Scale; } Scale;
uint64_t Texture; uint64_t Texture;
uint32_t skinning_offset;
#ifdef WIN32 #ifdef WIN32
}; };
#else #else
@ -135,6 +136,7 @@ struct InstanceDataFourTex
uint64_t SecondTexture; uint64_t SecondTexture;
uint64_t ThirdTexture; uint64_t ThirdTexture;
uint64_t FourthTexture; uint64_t FourthTexture;
uint32_t skinning_offset;
#ifdef WIN32 #ifdef WIN32
}; };
#else #else
@ -197,7 +199,7 @@ struct MeshRenderInfoEquals : std::binary_function
class VAOManager : public Singleton<VAOManager> class VAOManager : public Singleton<VAOManager>
{ {
enum VTXTYPE { VTXTYPE_STANDARD, VTXTYPE_TCOORD, VTXTYPE_TANGENT, VTXTYPE_COUNT }; enum VTXTYPE { VTXTYPE_STANDARD, VTXTYPE_TCOORD, VTXTYPE_TANGENT, VTXTYPE_SKINNED_MESH, VTXTYPE_COUNT };
GLuint vbo[VTXTYPE_COUNT], ibo[VTXTYPE_COUNT], vao[VTXTYPE_COUNT]; GLuint vbo[VTXTYPE_COUNT], ibo[VTXTYPE_COUNT], vao[VTXTYPE_COUNT];
GLuint instance_vbo[InstanceTypeCount]; GLuint instance_vbo[InstanceTypeCount];
void *Ptr[InstanceTypeCount]; void *Ptr[InstanceTypeCount];