From 57d9e83ed49703244486dd93b2deebe869c705d2 Mon Sep 17 00:00:00 2001 From: Benau Date: Wed, 7 Dec 2016 02:15:11 +0800 Subject: [PATCH] First version of hardware skinning Todo: shadow, non-instanced shaders, culling, changeable offset... --- data/shaders/header.txt | 6 + data/shaders/instanced_skinning.vert | 120 ++++++++++++ lib/irrlicht/include/CVertexBuffer.h | 2 + lib/irrlicht/include/IMeshManipulator.h | 2 + lib/irrlicht/include/S3DVertex.h | 22 ++- lib/irrlicht/include/SSkinMeshBuffer.h | 52 +++++ lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp | 177 ++++++++++++++---- lib/irrlicht/source/Irrlicht/CSkinnedMesh.h | 32 +++- src/graphics/command_buffer.cpp | 5 +- src/graphics/command_buffer.hpp | 2 +- src/graphics/draw_calls.cpp | 40 +++- src/graphics/draw_calls.hpp | 5 + src/graphics/glwrap.hpp | 16 ++ src/graphics/material.hpp | 1 + src/graphics/materials.cpp | 8 + src/graphics/materials.hpp | 53 ++++++ src/graphics/mesh_tools.cpp | 2 +- src/graphics/shader.hpp | 1 + src/graphics/shader_based_renderer.cpp | 2 + src/graphics/shared_gpu_objects.cpp | 15 +- src/graphics/shared_gpu_objects.hpp | 8 + src/graphics/stk_animated_mesh.cpp | 51 ++++- src/graphics/stk_animated_mesh.hpp | 10 + src/graphics/stk_mesh.cpp | 21 ++- src/graphics/stk_mesh.hpp | 6 + src/graphics/vao_manager.cpp | 14 +- src/graphics/vao_manager.hpp | 4 +- 27 files changed, 612 insertions(+), 65 deletions(-) create mode 100644 data/shaders/instanced_skinning.vert diff --git a/data/shaders/header.txt b/data/shaders/header.txt index a14e9539a..253e82a29 100644 --- a/data/shaders/header.txt +++ b/data/shaders/header.txt @@ -63,5 +63,11 @@ layout (std140) uniform LightingData float rL21; float rL22; }; + +layout (std140) uniform SkinningData +{ + mat4 joint_matrices[1000]; +}; + #endif #endif // HEADER_TXT diff --git a/data/shaders/instanced_skinning.vert b/data/shaders/instanced_skinning.vert new file mode 100644 index 000000000..fb22ca2e0 --- /dev/null +++ b/data/shaders/instanced_skinning.vert @@ -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 +} diff --git a/lib/irrlicht/include/CVertexBuffer.h b/lib/irrlicht/include/CVertexBuffer.h index c721419dd..826873023 100644 --- a/lib/irrlicht/include/CVertexBuffer.h +++ b/lib/irrlicht/include/CVertexBuffer.h @@ -116,6 +116,8 @@ namespace scene NewVertices=new CSpecificVertexList; break; } + default: + break; } if (Vertices) { diff --git a/lib/irrlicht/include/IMeshManipulator.h b/lib/irrlicht/include/IMeshManipulator.h index 3476c5789..b4c7d8710 100644 --- a/lib/irrlicht/include/IMeshManipulator.h +++ b/lib/irrlicht/include/IMeshManipulator.h @@ -371,6 +371,8 @@ protected: func(verts[i]); } break; + default: + break; } if (boundingBoxUpdate) { diff --git a/lib/irrlicht/include/S3DVertex.h b/lib/irrlicht/include/S3DVertex.h index bf0fd5b89..3d12edde6 100644 --- a/lib/irrlicht/include/S3DVertex.h +++ b/lib/irrlicht/include/S3DVertex.h @@ -26,7 +26,9 @@ enum E_VERTEX_TYPE //! Vertex with a tangent and binormal vector, video::S3DVertexTangents. /** Usually used for tangent space normal mapping. */ - EVT_TANGENTS + EVT_TANGENTS, + + EVT_SKINNED_MESH }; //! 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) @@ -261,6 +279,8 @@ inline u32 getVertexPitchFromType(E_VERTEX_TYPE vertexType) return sizeof(video::S3DVertex2TCoords); case video::EVT_TANGENTS: return sizeof(video::S3DVertexTangents); + case video::EVT_SKINNED_MESH: + return sizeof(video::S3DVertexSkinnedMesh); default: return sizeof(video::S3DVertex); } diff --git a/lib/irrlicht/include/SSkinMeshBuffer.h b/lib/irrlicht/include/SSkinMeshBuffer.h index 046378d3b..d510741eb 100644 --- a/lib/irrlicht/include/SSkinMeshBuffer.h +++ b/lib/irrlicht/include/SSkinMeshBuffer.h @@ -50,6 +50,8 @@ struct SSkinMeshBuffer : public IMeshBuffer return (video::S3DVertex*)&Vertices_2TCoords[index]; case video::EVT_TANGENTS: return (video::S3DVertex*)&Vertices_Tangents[index]; + case video::EVT_SKINNED_MESH: + return (video::S3DVertex*)&Vertices_SkinnedMesh[index]; default: return &Vertices_Standard[index]; } @@ -64,6 +66,8 @@ struct SSkinMeshBuffer : public IMeshBuffer return Vertices_2TCoords.const_pointer(); case video::EVT_TANGENTS: return Vertices_Tangents.const_pointer(); + case video::EVT_SKINNED_MESH: + return Vertices_SkinnedMesh.const_pointer(); default: return Vertices_Standard.const_pointer(); } @@ -78,6 +82,8 @@ struct SSkinMeshBuffer : public IMeshBuffer return Vertices_2TCoords.pointer(); case video::EVT_TANGENTS: return Vertices_Tangents.pointer(); + case video::EVT_SKINNED_MESH: + return Vertices_SkinnedMesh.pointer(); default: return Vertices_Standard.pointer(); } @@ -92,6 +98,8 @@ struct SSkinMeshBuffer : public IMeshBuffer return Vertices_2TCoords.size(); case video::EVT_TANGENTS: return Vertices_Tangents.size(); + case video::EVT_SKINNED_MESH: + return Vertices_SkinnedMesh.size(); default: return Vertices_Standard.size(); } @@ -180,6 +188,20 @@ struct SSkinMeshBuffer : public IMeshBuffer } 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_Tangents; core::array Vertices_2TCoords; + core::array Vertices_SkinnedMesh; core::array Vertices_Standard; core::array Indices; diff --git a/lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp b/lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp index 92ec49820..01cf773a6 100644 --- a/lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp +++ b/lib/irrlicht/source/Irrlicht/CSkinnedMesh.cpp @@ -18,7 +18,7 @@ namespace scene //! constructor 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), InterpolationMode(EIM_LINEAR), HasAnimation(false), PreparedForSkinning(false), @@ -27,7 +27,6 @@ CSkinnedMesh::CSkinnedMesh() #ifdef _DEBUG setDebugName("CSkinnedMesh"); #endif - 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. 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); if (frame==-1) return this; animateMesh((f32)frame, 1.0f); skinMesh(); + + if (is_hw_skinning_before) + HardwareSkinning = true; + return this; } @@ -456,7 +462,13 @@ void CSkinnedMesh::skinMesh(f32 strength) //----------------- 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.... u32 i; @@ -493,52 +505,58 @@ void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint, f32 strength) //Find this joints pull on vertices... core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING); jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix); - - core::vector3df thisVertexMove, thisNormalMove; - - core::array &buffersUsed=*SkinningBuffers; - - //Skin Vertices Positions and Normals... - for (u32 i=0; iWeights.size(); ++i) + if (HardwareSkinning) { - SWeight& weight = joint->Weights[i]; + m_joint_matrixes.push_back(jointVertexPull); + } + else + { + core::vector3df thisVertexMove, thisNormalMove; - // Pull this vertex... - jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); + core::array &buffersUsed=*SkinningBuffers; - if (AnimateNormals) - jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal); - - // Apply animation strength - if(strength != 1.f) + //Skin Vertices Positions and Normals... + for (u32 i=0; iWeights.size(); ++i) { - thisVertexMove = core::lerp(weight.StaticPos, thisVertexMove, strength); - if(AnimateNormals) - thisNormalMove = core::lerp(weight.StaticNormal, thisNormalMove, strength); - } + SWeight& weight = joint->Weights[i]; - if (! (*(weight.Moved)) ) - { - *(weight.Moved) = true; - - buffersUsed[weight.buffer_id]->getVertex(weight.vertex_id)->Pos = thisVertexMove * weight.strength; + // Pull this vertex... + jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); 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 &jointChildSceneNodes, 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> ()); + for (u32 i = 0; i < LocalBuffers[b]->getVertexCount(); i++) + wi[b].push_back(core::array()); + } + + 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 this_influence; + core::array 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() { diff --git a/lib/irrlicht/source/Irrlicht/CSkinnedMesh.h b/lib/irrlicht/source/Irrlicht/CSkinnedMesh.h index 2c66bbf9b..086590c64 100644 --- a/lib/irrlicht/source/Irrlicht/CSkinnedMesh.h +++ b/lib/irrlicht/source/Irrlicht/CSkinnedMesh.h @@ -14,6 +14,20 @@ #include "matrix4.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 > > WeightInfluence; + namespace irr { namespace scene @@ -25,7 +39,6 @@ namespace scene class CSkinnedMesh: public ISkinnedMesh { public: - //! constructor CSkinnedMesh(); @@ -159,6 +172,19 @@ namespace scene void addJoints(core::array &jointChildSceneNodes, IAnimatedMeshSceneNode* node, 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: void checkForAnimation(); @@ -204,7 +230,9 @@ private: bool HasAnimation; bool PreparedForSkinning; bool AnimateNormals; - bool HardwareSkinning; + bool HardwareSkinning; + core::array m_joint_matrixes; + u32 m_joint_total_size; }; } // end namespace scene diff --git a/src/graphics/command_buffer.cpp b/src/graphics/command_buffer.cpp index c0bc3fa11..b12445016 100644 --- a/src/graphics/command_buffer.cpp +++ b/src/graphics/command_buffer.cpp @@ -27,6 +27,7 @@ void InstanceFiller::add(GLMesh* mesh, { fillOriginOrientationScale(STK::tuple_get<0>(is), instance); instance.Texture = mesh->TextureHandles[0]; + instance.skinning_offset = STK::tuple_get<3>(is); } // ---------------------------------------------------------------------------- @@ -60,6 +61,7 @@ void InstanceFiller::add(GLMesh* mesh, instance.SecondTexture = mesh->TextureHandles[1]; instance.ThirdTexture = mesh->TextureHandles[2]; 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 four_tex_material_list = createVector(Material::SHADERTYPE_DETAIL_MAP, - Material::SHADERTYPE_NORMAL_MAP); + Material::SHADERTYPE_NORMAL_MAP, + Material::SHADERTYPE_SOLID_SKINNED_MESH); fillInstanceData (mesh_map, four_tex_material_list, InstanceTypeFourTex); diff --git a/src/graphics/command_buffer.hpp b/src/graphics/command_buffer.hpp index 506e882e4..9befd35aa 100644 --- a/src/graphics/command_buffer.hpp +++ b/src/graphics/command_buffer.hpp @@ -29,7 +29,7 @@ #include #include -typedef STK::Tuple InstanceSettings; +typedef STK::Tuple InstanceSettings; struct InstanceList { diff --git a/src/graphics/draw_calls.cpp b/src/graphics/draw_calls.cpp index 166175030..269a35a02 100644 --- a/src/graphics/draw_calls.cpp +++ b/src/graphics/draw_calls.cpp @@ -22,6 +22,7 @@ #include "graphics/lod_node.hpp" #include "graphics/materials.hpp" #include "graphics/shadow_matrices.hpp" +#include "graphics/stk_animated_mesh.hpp" #include "graphics/stk_billboard.hpp" #include "graphics/stk_mesh.hpp" #include "graphics/stk_mesh_scene_node.hpp" @@ -30,6 +31,8 @@ #include "tracks/track.hpp" #include "utils/profiler.hpp" +#include + // ---------------------------------------------------------------------------- void DrawCalls::clearLists() { @@ -175,6 +178,28 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node, return; } + uint32_t skinning_offset = 0; + STKAnimatedMesh* am = dynamic_cast(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& 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 }; culled_for_cams[0] = isCulledPrecise(cam, Node, 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_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) { @@ -267,15 +292,12 @@ void DrawCalls::handleSTKCommon(scene::ISceneNode *Node, } else { - // Only take render info into account if the node is not static (animated) - // So they can have different animation - std::pair mesh_render_info(mesh->mb, - dynamic_cast(Node) == NULL ? mesh->m_render_info : NULL); + std::pair mesh_render_info(mesh->mb, NULL); 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, (mesh->m_render_info && mesh->m_material ? 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_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 @@ -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_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->drawIndirectFirstPass(); + m_solid_cmd_buffer->drawIndirectFirstPass(); m_solid_cmd_buffer->drawIndirectFirstPass(); m_solid_cmd_buffer->drawIndirectFirstPass(); m_solid_cmd_buffer->drawIndirectFirstPass(); @@ -718,6 +741,7 @@ void DrawCalls::drawIndirectSolidSecondPass(const std::vector &prefilled { m_solid_cmd_buffer->bind(); m_solid_cmd_buffer->drawIndirectSecondPass(prefilled_tex); + m_solid_cmd_buffer->drawIndirectSecondPass(prefilled_tex); m_solid_cmd_buffer->drawIndirectSecondPass(prefilled_tex); m_solid_cmd_buffer->drawIndirectSecondPass(prefilled_tex); m_solid_cmd_buffer->drawIndirectSecondPass(prefilled_tex); diff --git a/src/graphics/draw_calls.hpp b/src/graphics/draw_calls.hpp index 4222c39f5..febf51644 100644 --- a/src/graphics/draw_calls.hpp +++ b/src/graphics/draw_calls.hpp @@ -24,8 +24,11 @@ class ParticleSystemProxy; class ShadowMatrices; +class STKAnimatedMesh; class STKBillboard; +typedef std::unordered_map SkinningOffset; + class DrawCalls { private: @@ -36,6 +39,7 @@ private: std::vector m_immediate_draw_list; std::vector m_billboard_list; std::vector m_particles_list; + SkinningOffset m_skinning_offsets; std::vector m_bounding_boxes; @@ -105,6 +109,7 @@ public: void drawIndirectGlow() const; void multidrawGlow() const; void renderBoundingBoxes(); + void resetSkinningOffsets() { m_skinning_offsets.clear(); } }; #endif //HEADER_DRAW_CALLS_HPP diff --git a/src/graphics/glwrap.hpp b/src/graphics/glwrap.hpp index dbb7522e9..791a5ed8d 100644 --- a/src/graphics/glwrap.hpp +++ b/src/graphics/glwrap.hpp @@ -140,6 +140,22 @@ public: glEnableVertexAttribArray(6); glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(tp), (GLvoid*)48); 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; } } }; diff --git a/src/graphics/material.hpp b/src/graphics/material.hpp index 69df9ad21..69d2bfac3 100644 --- a/src/graphics/material.hpp +++ b/src/graphics/material.hpp @@ -48,6 +48,7 @@ public: enum ShaderType { SHADERTYPE_SOLID = 0, + SHADERTYPE_SOLID_SKINNED_MESH, SHADERTYPE_ALPHA_TEST, SHADERTYPE_ALPHA_BLEND, SHADERTYPE_ADDITIVE, diff --git a/src/graphics/materials.cpp b/src/graphics/materials.cpp index c700832dc..5acbda0fd 100644 --- a/src/graphics/materials.cpp +++ b/src/graphics/materials.cpp @@ -24,6 +24,14 @@ const STK::Tuple DefaultMaterial::SecondPassTextures const STK::Tuple<> DefaultMaterial::ShadowTextures; const STK::Tuple DefaultMaterial::RSMTextures = STK::Tuple(0); +// ---------------------------------------------------------------------------- +const STK::Tuple SkinnedSolid::FirstPassTextures + = STK::Tuple(1); +const STK::Tuple SkinnedSolid::SecondPassTextures + = STK::Tuple(0, 1, 2); +const STK::Tuple<> SkinnedSolid::ShadowTextures; +const STK::Tuple SkinnedSolid::RSMTextures = STK::Tuple(0); + // ---------------------------------------------------------------------------- const STK::Tuple AlphaRef::FirstPassTextures = STK::Tuple(0, 1); diff --git a/src/graphics/materials.hpp b/src/graphics/materials.hpp index acc063d36..f40a04466 100644 --- a/src/graphics/materials.hpp +++ b/src/graphics/materials.hpp @@ -616,8 +616,61 @@ public: } // InstancedDetailedObjectPass2Shader }; // InstancedDetailedObjectPass2Shader +// ============================================================================ +class InstancedSkinnedMeshPass1Shader : public TextureShader +{ +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 +{ +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 FirstPassTextures; + static const STK::Tuple SecondPassTextures; + static const STK::Tuple<> ShadowTextures; + static const STK::Tuple RSMTextures; +}; // struct DefaultMaterial + +// ---------------------------------------------------------------------------- struct DefaultMaterial { typedef InstancedObjectPass1Shader InstancedFirstPassShader; diff --git a/src/graphics/mesh_tools.cpp b/src/graphics/mesh_tools.cpp index 95bf286ee..6104cb35e 100644 --- a/src/graphics/mesh_tools.cpp +++ b/src/graphics/mesh_tools.cpp @@ -476,7 +476,7 @@ scene::IMesh* MeshTools::createMeshWithTangents(scene::IMesh* mesh, void MeshTools::createSkinnedMeshWithTangents(scene::ISkinnedMesh* mesh, bool(*predicate)(scene::IMeshBuffer*)) -{ +{return; core::array& all_mb = mesh->getMeshBuffers(); const int all_mb_size = all_mb.size(); for (int i = 0; i < all_mb_size; i++) diff --git a/src/graphics/shader.hpp b/src/graphics/shader.hpp index adfc64cde..785075f2d 100644 --- a/src/graphics/shader.hpp +++ b/src/graphics/shader.hpp @@ -150,6 +150,7 @@ private: { bindPoint("MatrixData", 0); bindPoint("LightingData", 1); + bindPoint("SkinningData", 2); } // assignUniformsImpl // ------------------------------------------------------------------------ diff --git a/src/graphics/shader_based_renderer.cpp b/src/graphics/shader_based_renderer.cpp index ff56248ff..34ba6b05a 100644 --- a/src/graphics/shader_based_renderer.cpp +++ b/src/graphics/shader_based_renderer.cpp @@ -270,6 +270,7 @@ void ShaderBasedRenderer::renderScene(scene::ICameraSceneNode * const camnode, { glBindBufferBase(GL_UNIFORM_BUFFER, 0, SharedGPUObjects::getViewProjectionMatricesUBO()); glBindBufferBase(GL_UNIFORM_BUFFER, 1, SharedGPUObjects::getLightingDataUBO()); + glBindBufferBase(GL_UNIFORM_BUFFER, 2, SharedGPUObjects::getSkinningUBO()); } irr_driver->getSceneManager()->setActiveCamera(camnode); @@ -697,6 +698,7 @@ void ShaderBasedRenderer::onUnloadWorld() delete m_rtts; m_rtts = NULL; removeSkyBox(); + m_draw_calls.resetSkinningOffsets(); } // ---------------------------------------------------------------------------- diff --git a/src/graphics/shared_gpu_objects.cpp b/src/graphics/shared_gpu_objects.cpp index 7104c1761..68305ddff 100644 --- a/src/graphics/shared_gpu_objects.cpp +++ b/src/graphics/shared_gpu_objects.cpp @@ -29,6 +29,7 @@ GLuint SharedGPUObjects::m_full_screen_quad_vao; GLuint SharedGPUObjects::m_ui_vao; GLuint SharedGPUObjects::m_quad_buffer; GLuint SharedGPUObjects::m_quad_vbo; +GLuint SharedGPUObjects::m_skinning_ubo; bool SharedGPUObjects::m_has_been_initialised = false; /** Initialises m_full_screen_quad_vbo. @@ -166,6 +167,17 @@ void SharedGPUObjects::initLightingDataUBO() glBindBuffer(GL_UNIFORM_BUFFER, 0); } // 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() { @@ -198,7 +210,8 @@ void SharedGPUObjects::init() if(CVS->isARBUniformBufferObjectUsable()) { initShadowVPMUBO(); - initLightingDataUBO(); + initLightingDataUBO(); + initSkinningUBO(); } m_has_been_initialised = true; diff --git a/src/graphics/shared_gpu_objects.hpp b/src/graphics/shared_gpu_objects.hpp index edcf5093e..df2436884 100644 --- a/src/graphics/shared_gpu_objects.hpp +++ b/src/graphics/shared_gpu_objects.hpp @@ -37,6 +37,7 @@ private: static GLuint m_ui_vao; static GLuint m_quad_buffer; static GLuint m_quad_vbo; + static GLuint m_skinning_ubo; static void initQuadVBO(); static void initQuadBuffer(); @@ -46,6 +47,7 @@ private: static void initShadowVPMUBO(); static void initLightingDataUBO(); static void initParticleQuadVBO(); + static void initSkinningUBO(); public: static void init(); @@ -116,6 +118,12 @@ public: assert(m_has_been_initialised); return m_quad_vbo; } // getQuadVBO + // ------------------------------------------------------------------------ + static GLuint getSkinningUBO() + { + assert(m_has_been_initialised); + return m_skinning_ubo; + } // getSkinningUBO }; // class SharedGPUObjecctS diff --git a/src/graphics/stk_animated_mesh.cpp b/src/graphics/stk_animated_mesh.cpp index d51bd8698..148f6353a 100644 --- a/src/graphics/stk_animated_mesh.cpp +++ b/src/graphics/stk_animated_mesh.cpp @@ -20,12 +20,13 @@ #include "graphics/central_settings.hpp" #include "graphics/material_manager.hpp" #include "graphics/render_info.hpp" +#include "graphics/shared_gpu_objects.hpp" #include "graphics/stk_mesh.hpp" #include "graphics/vao_manager.hpp" #include #include -#include +#include "../../lib/irrlicht/source/Irrlicht/CSkinnedMesh.h" 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& rotation, 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; isMaterialInitialized = false; @@ -43,6 +44,10 @@ const core::vector3df& scale, RenderInfo* render_info, bool all_parts_colorized) #ifdef DEBUG m_debug_name = debug_name; #endif + m_skinning_offset = -1; + m_skinned_mesh = dynamic_cast(Mesh); + if (m_skinned_mesh) + m_skinned_mesh->convertForSkinning(); } STKAnimatedMesh::~STKAnimatedMesh() @@ -108,6 +113,16 @@ void STKAnimatedMesh::updateNoGL() for (u32 i = 0; i < mb_count; ++i) { scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); + if (!mb) + continue; + + scene::SSkinMeshBuffer* ssmb = NULL; + if (m_skinned_mesh) + { + ssmb = dynamic_cast(mb); + ssmb->VertexType = video::EVT_SKINNED_MESH; + } + bool affected = false; RenderInfo* cur_ri = m_mesh_render_info; if (!m_all_parts_colorized && mb && cur_ri) @@ -142,6 +157,8 @@ void STKAnimatedMesh::updateNoGL() GLmeshes.push_back(allocateMeshBuffer(mb, m_debug_name, affected || m_all_parts_colorized || (cur_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) @@ -162,7 +179,7 @@ void STKAnimatedMesh::updateNoGL() GLMesh &mesh = GLmeshes[i]; Material* material = material_manager->getMaterialFor(mb->getMaterial().getTexture(0), mb); - if (rnd->isTransparent()) + /*if (rnd->isTransparent()) { TransparentMaterial TranspMat = getTransparentMaterialFromType(type, MaterialTypeParam, material); TransparentMesh[TranspMat].push_back(&mesh); @@ -174,10 +191,10 @@ void STKAnimatedMesh::updateNoGL() else TransparentMesh[TM_TRANSLUCENT_STD].push_back(&mesh); } - else + else*/ { 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; @@ -213,6 +230,13 @@ void STKAnimatedMesh::updateGL() scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); if (!mb) continue; + scene::SSkinMeshBuffer* ssmb = NULL; + if (m_skinned_mesh) + { + ssmb = dynamic_cast(mb); + ssmb->VertexType = video::EVT_SKINNED_MESH; + } + video::IVideoDriver* driver = SceneManager->getVideoDriver(); video::E_MATERIAL_TYPE type = mb->getMaterial().MaterialType; video::IMaterialRenderer* rnd = driver->getMaterialRenderer(type); @@ -233,7 +257,7 @@ void STKAnimatedMesh::updateGL() if (CVS->isARBBaseInstanceUsable()) { - std::pair p = VAOManager::getInstance()->getBase(mb, GLmeshes[i].m_render_info); + std::pair p = VAOManager::getInstance()->getBase(mb,NULL /*GLmeshes[i].m_render_info*/); mesh.vaoBaseVertex = p.first; mesh.vaoOffset = p.second; } @@ -243,10 +267,20 @@ void STKAnimatedMesh::updateGL() mesh.vao = createVAO(mesh.vertex_buffer, mesh.index_buffer, mb->getVertexType()); glBindVertexArray(0); } + if (m_skinned_mesh) ssmb->VertexType = video::EVT_STANDARD; } 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; igetMeshBufferCount(); ++i) { scene::IMeshBuffer* mb = m->getMeshBuffer(i); @@ -289,3 +323,8 @@ void STKAnimatedMesh::render() updateNoGL(); updateGL(); } + +int STKAnimatedMesh::getTotalJointSize() const +{ + return m_skinned_mesh->getTotalJointSize(); +} diff --git a/src/graphics/stk_animated_mesh.hpp b/src/graphics/stk_animated_mesh.hpp index f7c10019e..0afb27ee7 100644 --- a/src/graphics/stk_animated_mesh.hpp +++ b/src/graphics/stk_animated_mesh.hpp @@ -26,6 +26,10 @@ #include class RenderInfo; +namespace irr +{ + namespace scene { class CSkinnedMesh; } +} class STKAnimatedMesh : public irr::scene::CAnimatedMeshSceneNode, public STKMeshCommon { @@ -50,9 +54,15 @@ public: virtual void render(); virtual void setMesh(irr::scene::IAnimatedMesh* mesh); 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: RenderInfo* m_mesh_render_info; bool m_all_parts_colorized; + irr::scene::CSkinnedMesh* m_skinned_mesh; + int m_skinning_offset; }; #endif // STKANIMATEDMESH_HPP diff --git a/src/graphics/stk_mesh.cpp b/src/graphics/stk_mesh.cpp index e58faece5..9cd2df055 100644 --- a/src/graphics/stk_mesh.cpp +++ b/src/graphics/stk_mesh.cpp @@ -155,6 +155,22 @@ GLuint createVAO(GLuint vbo, GLuint idx, video::E_VERTEX_TYPE type) glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, getVertexPitchFromType(type), (GLvoid*)48); 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: assert(0 && "Wrong vertex type"); } @@ -346,8 +362,8 @@ static void setTexture(GLMesh &mesh, unsigned i, bool is_srgb, { if (!mesh.textures[i]) { - Log::error("STKMesh", "Missing texture %d for material %s", i, - mat_name.c_str()); + //Log::error("STKMesh", "Missing texture %d for material %s", i, + // mat_name.c_str()); // use unicolor texture to replace missing texture mesh.textures[i] = getUnicolorTexture(video::SColor(255, 127, 127, 127)); @@ -413,6 +429,7 @@ void initTextures(GLMesh &mesh, Material::ShaderType mat) break; case Material::SHADERTYPE_DETAIL_MAP: case Material::SHADERTYPE_NORMAL_MAP: + case Material::SHADERTYPE_SOLID_SKINNED_MESH: setTexture(mesh, 0, true, getShaderTypeName(mat)); setTexture(mesh, 1, false, getShaderTypeName(mat)); setTexture(mesh, 2, false, getShaderTypeName(mat)); diff --git a/src/graphics/stk_mesh.hpp b/src/graphics/stk_mesh.hpp index 3e089bcac..39a113422 100644 --- a/src/graphics/stk_mesh.hpp +++ b/src/graphics/stk_mesh.hpp @@ -116,6 +116,12 @@ class ListMatDefault : public MeshList {}; +// ---------------------------------------------------------------------------- +class ListSkinnedSolid : public MeshList +{}; + // ---------------------------------------------------------------------------- class ListMatAlphaRef : public MeshList::SetVertexAttrib() glEnableVertexAttribArray(11); glVertexAttribIPointer(11, 2, GL_UNSIGNED_INT, sizeof(InstanceDataSingleTex), (GLvoid*)(9 * sizeof(float))); glVertexAttribDivisorARB(11, 1); + glEnableVertexAttribArray(15); + glVertexAttribIPointer(15, 1, GL_UNSIGNED_INT, sizeof(InstanceDataSingleTex), (GLvoid*)(11 * sizeof(float))); + glVertexAttribDivisorARB(15, 1); } template<> @@ -200,6 +203,9 @@ void VAOInstanceUtil::SetVertexAttrib() glEnableVertexAttribArray(14); glVertexAttribIPointer(14, 2, GL_UNSIGNED_INT, sizeof(InstanceDataFourTex), (GLvoid*)(13 * sizeof(float) + 6 * sizeof(unsigned))); glVertexAttribDivisorARB(14, 1); + glEnableVertexAttribArray(15); + glVertexAttribIPointer(15, 1, GL_UNSIGNED_INT, sizeof(InstanceDataFourTex), (GLvoid*)(13 * sizeof(float) + 8 * sizeof(unsigned))); + glVertexAttribDivisorARB(15, 1); } template<> @@ -216,7 +222,7 @@ void VAOManager::regenerateInstancedVAO() { 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++) { video::E_VERTEX_TYPE tp = IrrVT[i]; @@ -264,6 +270,8 @@ size_t VAOManager::getVertexPitch(enum VTXTYPE tp) const return getVertexPitchFromType(video::EVT_2TCOORDS); case VTXTYPE_TANGENT: return getVertexPitchFromType(video::EVT_TANGENTS); + case VTXTYPE_SKINNED_MESH: + return getVertexPitchFromType(video::EVT_SKINNED_MESH); default: assert(0 && "Wrong vtxtype"); return -1; @@ -282,6 +290,8 @@ VAOManager::VTXTYPE VAOManager::getVTXTYPE(video::E_VERTEX_TYPE type) return VTXTYPE_TCOORD; case video::EVT_TANGENTS: 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; case VTXTYPE_TANGENT: return video::EVT_TANGENTS; + case VTXTYPE_SKINNED_MESH: + return video::EVT_SKINNED_MESH; } } diff --git a/src/graphics/vao_manager.hpp b/src/graphics/vao_manager.hpp index 62bd9d23d..d15bd2072 100644 --- a/src/graphics/vao_manager.hpp +++ b/src/graphics/vao_manager.hpp @@ -62,6 +62,7 @@ struct InstanceDataSingleTex float Z; } Scale; uint64_t Texture; + uint32_t skinning_offset; #ifdef WIN32 }; #else @@ -135,6 +136,7 @@ struct InstanceDataFourTex uint64_t SecondTexture; uint64_t ThirdTexture; uint64_t FourthTexture; + uint32_t skinning_offset; #ifdef WIN32 }; #else @@ -197,7 +199,7 @@ struct MeshRenderInfoEquals : std::binary_function class VAOManager : public Singleton { - 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 instance_vbo[InstanceTypeCount]; void *Ptr[InstanceTypeCount];