1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648 |
- // Copyright (C) 2002-2012 Nikolaus Gebhardt
- // This file is part of the "Irrlicht Engine".
- // For conditions of distribution and use, see copyright notice in irrlicht.h
- #include "IrrCompileConfig.h"
- #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
- #include "CSkinnedMesh.h"
- #include "CBoneSceneNode.h"
- #include "IAnimatedMeshSceneNode.h"
- #include "os.h"
- #include "irrMap.h"
- namespace irr
- {
- namespace scene
- {
- //! constructor
- CSkinnedMesh::CSkinnedMesh()
- : SkinningBuffers(0), AnimationFrames(0.f), FramesPerSecond(25.f),
- LastAnimatedFrame(-1), SkinnedLastFrame(false),
- InterpolationMode(EIM_LINEAR),
- HasAnimation(false), PreparedForSkinning(false),
- AnimateNormals(true), HardwareSkinning(false), m_total_joints(0),
- m_current_joint(0)
- {
- #ifdef _DEBUG
- setDebugName("CSkinnedMesh");
- #endif
- SkinningBuffers=&LocalBuffers;
- }
- //! destructor
- CSkinnedMesh::~CSkinnedMesh()
- {
- for (u32 i=0; i<AllJoints.size(); ++i)
- delete AllJoints[i];
- for (u32 j=0; j<LocalBuffers.size(); ++j)
- {
- if (LocalBuffers[j])
- LocalBuffers[j]->drop();
- }
- }
- //! returns the amount of frames in milliseconds.
- //! If the amount is 1, it is a static (=non animated) mesh.
- u32 CSkinnedMesh::getFrameCount() const
- {
- return core::floor32(AnimationFrames);
- }
- //! Gets the default animation speed of the animated mesh.
- /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */
- f32 CSkinnedMesh::getAnimationSpeed() const
- {
- return FramesPerSecond;
- }
- //! Gets the frame count of the animated mesh.
- /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated.
- The actual speed is set in the scene node the mesh is instantiated in.*/
- void CSkinnedMesh::setAnimationSpeed(f32 fps)
- {
- FramesPerSecond=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;
- }
- //--------------------------------------------------------------------------
- // Keyframe Animation
- //--------------------------------------------------------------------------
- //! Animates this mesh's joints based on frame input
- //! blend: {0-old position, 1-New position}
- void CSkinnedMesh::animateMesh(f32 frame, f32 blend)
- {
- if (HardwareSkinning && LastAnimatedFrame==frame)
- {
- SkinnedLastFrame=false;
- return;
- }
- if (!HasAnimation || LastAnimatedFrame==frame)
- return;
- LastAnimatedFrame=frame;
- SkinnedLastFrame=false;
- if (blend<=0.f)
- return; //No need to animate
- for (u32 i=0; i<AllJoints.size(); ++i)
- {
- //The joints can be animated here with no input from their
- //parents, but for setAnimationMode extra checks are needed
- //to their parents
- SJoint *joint = AllJoints[i];
- const core::vector3df oldPosition = joint->Animatedposition;
- const core::vector3df oldScale = joint->Animatedscale;
- const core::quaternion oldRotation = joint->Animatedrotation;
- core::vector3df position = oldPosition;
- core::vector3df scale = oldScale;
- core::quaternion rotation = oldRotation;
- getFrameData(frame, joint,
- position, joint->positionHint,
- scale, joint->scaleHint,
- rotation, joint->rotationHint);
- if (blend==1.0f)
- {
- //No blending needed
- joint->Animatedposition = position;
- joint->Animatedscale = scale;
- joint->Animatedrotation = rotation;
- }
- else
- {
- //Blend animation
- joint->Animatedposition = core::lerp(oldPosition, position, blend);
- joint->Animatedscale = core::lerp(oldScale, scale, blend);
- joint->Animatedrotation.slerp(oldRotation, rotation, blend);
- }
- }
- //Note:
- //LocalAnimatedMatrix needs to be built at some point, but this function may be called lots of times for
- //one render (to play two animations at the same time) LocalAnimatedMatrix only needs to be built once.
- //a call to buildAllLocalAnimatedMatrices is needed before skinning the mesh, and before the user gets the joints to move
- //----------------
- // Temp!
- buildAllLocalAnimatedMatrices();
- //-----------------
- updateBoundingBox();
- }
- void CSkinnedMesh::buildAllLocalAnimatedMatrices()
- {
- for (u32 i=0; i<AllJoints.size(); ++i)
- {
- SJoint *joint = AllJoints[i];
- //Could be faster:
- if (joint->UseAnimationFrom &&
- (joint->UseAnimationFrom->PositionKeys.size() ||
- joint->UseAnimationFrom->ScaleKeys.size() ||
- joint->UseAnimationFrom->RotationKeys.size() ))
- {
- joint->GlobalSkinningSpace=false;
- // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility.
- // Not tested so far if this was correct or wrong before quaternion fix!
- joint->Animatedrotation.getMatrix_transposed(joint->LocalAnimatedMatrix);
- // --- joint->LocalAnimatedMatrix *= joint->Animatedrotation.getMatrix() ---
- f32 *m1 = joint->LocalAnimatedMatrix.pointer();
- core::vector3df &Pos = joint->Animatedposition;
- m1[0] += Pos.X*m1[3];
- m1[1] += Pos.Y*m1[3];
- m1[2] += Pos.Z*m1[3];
- m1[4] += Pos.X*m1[7];
- m1[5] += Pos.Y*m1[7];
- m1[6] += Pos.Z*m1[7];
- m1[8] += Pos.X*m1[11];
- m1[9] += Pos.Y*m1[11];
- m1[10] += Pos.Z*m1[11];
- m1[12] += Pos.X*m1[15];
- m1[13] += Pos.Y*m1[15];
- m1[14] += Pos.Z*m1[15];
- // -----------------------------------
- if (joint->ScaleKeys.size())
- {
- /*
- core::matrix4 scaleMatrix;
- scaleMatrix.setScale(joint->Animatedscale);
- joint->LocalAnimatedMatrix *= scaleMatrix;
- */
- // -------- joint->LocalAnimatedMatrix *= scaleMatrix -----------------
- core::matrix4& mat = joint->LocalAnimatedMatrix;
- mat[0] *= joint->Animatedscale.X;
- mat[1] *= joint->Animatedscale.X;
- mat[2] *= joint->Animatedscale.X;
- mat[3] *= joint->Animatedscale.X;
- mat[4] *= joint->Animatedscale.Y;
- mat[5] *= joint->Animatedscale.Y;
- mat[6] *= joint->Animatedscale.Y;
- mat[7] *= joint->Animatedscale.Y;
- mat[8] *= joint->Animatedscale.Z;
- mat[9] *= joint->Animatedscale.Z;
- mat[10] *= joint->Animatedscale.Z;
- mat[11] *= joint->Animatedscale.Z;
- // -----------------------------------
- }
- }
- else
- {
- joint->LocalAnimatedMatrix=joint->LocalMatrix;
- }
- }
- SkinnedLastFrame=false;
- }
- void CSkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint)
- {
- if (!joint)
- {
- for (u32 i=0; i<RootJoints.size(); ++i)
- buildAllGlobalAnimatedMatrices(RootJoints[i], 0);
- return;
- }
- else
- {
- // Find global matrix...
- if (!parentJoint || joint->GlobalSkinningSpace)
- joint->GlobalAnimatedMatrix = joint->LocalAnimatedMatrix;
- else
- joint->GlobalAnimatedMatrix = parentJoint->GlobalAnimatedMatrix * joint->LocalAnimatedMatrix;
- }
- for (u32 j=0; j<joint->Children.size(); ++j)
- buildAllGlobalAnimatedMatrices(joint->Children[j], joint);
- }
- void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint,
- core::vector3df &position, s32 &positionHint,
- core::vector3df &scale, s32 &scaleHint,
- core::quaternion &rotation, s32 &rotationHint)
- {
- s32 foundPositionIndex = -1;
- s32 foundScaleIndex = -1;
- s32 foundRotationIndex = -1;
- if (joint->UseAnimationFrom)
- {
- const core::array<SPositionKey> &PositionKeys=joint->UseAnimationFrom->PositionKeys;
- const core::array<SScaleKey> &ScaleKeys=joint->UseAnimationFrom->ScaleKeys;
- const core::array<SRotationKey> &RotationKeys=joint->UseAnimationFrom->RotationKeys;
- if (PositionKeys.size())
- {
- foundPositionIndex = -1;
- //Test the Hints...
- if (positionHint>=0 && (u32)positionHint < PositionKeys.size())
- {
- //check this hint
- if (positionHint>0 && PositionKeys[positionHint].frame>=frame && PositionKeys[positionHint-1].frame<frame )
- foundPositionIndex=positionHint;
- else if (positionHint+1 < (s32)PositionKeys.size())
- {
- //check the next index
- if ( PositionKeys[positionHint+1].frame>=frame &&
- PositionKeys[positionHint+0].frame<frame)
- {
- positionHint++;
- foundPositionIndex=positionHint;
- }
- }
- }
- //The hint test failed, do a full scan...
- if (foundPositionIndex==-1)
- {
- for (u32 i=0; i<PositionKeys.size(); ++i)
- {
- if (PositionKeys[i].frame >= frame) //Keys should to be sorted by frame
- {
- foundPositionIndex=i;
- positionHint=i;
- break;
- }
- }
- }
- //Do interpolation...
- if (foundPositionIndex!=-1)
- {
- if (InterpolationMode==EIM_CONSTANT || foundPositionIndex==0)
- {
- position = PositionKeys[foundPositionIndex].position;
- }
- else if (InterpolationMode==EIM_LINEAR)
- {
- const SPositionKey& KeyA = PositionKeys[foundPositionIndex];
- const SPositionKey& KeyB = PositionKeys[foundPositionIndex-1];
- const f32 fd1 = frame - KeyA.frame;
- const f32 fd2 = KeyB.frame - frame;
- position = ((KeyB.position-KeyA.position)/(fd1+fd2))*fd1 + KeyA.position;
- }
- }
- }
- //------------------------------------------------------------
- if (ScaleKeys.size())
- {
- foundScaleIndex = -1;
- //Test the Hints...
- if (scaleHint>=0 && (u32)scaleHint < ScaleKeys.size())
- {
- //check this hint
- if (scaleHint>0 && ScaleKeys[scaleHint].frame>=frame && ScaleKeys[scaleHint-1].frame<frame )
- foundScaleIndex=scaleHint;
- else if (scaleHint+1 < (s32)ScaleKeys.size())
- {
- //check the next index
- if ( ScaleKeys[scaleHint+1].frame>=frame &&
- ScaleKeys[scaleHint+0].frame<frame)
- {
- scaleHint++;
- foundScaleIndex=scaleHint;
- }
- }
- }
- //The hint test failed, do a full scan...
- if (foundScaleIndex==-1)
- {
- for (u32 i=0; i<ScaleKeys.size(); ++i)
- {
- if (ScaleKeys[i].frame >= frame) //Keys should to be sorted by frame
- {
- foundScaleIndex=i;
- scaleHint=i;
- break;
- }
- }
- }
- //Do interpolation...
- if (foundScaleIndex!=-1)
- {
- if (InterpolationMode==EIM_CONSTANT || foundScaleIndex==0)
- {
- scale = ScaleKeys[foundScaleIndex].scale;
- }
- else if (InterpolationMode==EIM_LINEAR)
- {
- const SScaleKey& KeyA = ScaleKeys[foundScaleIndex];
- const SScaleKey& KeyB = ScaleKeys[foundScaleIndex-1];
- const f32 fd1 = frame - KeyA.frame;
- const f32 fd2 = KeyB.frame - frame;
- scale = ((KeyB.scale-KeyA.scale)/(fd1+fd2))*fd1 + KeyA.scale;
- }
- }
- }
- //-------------------------------------------------------------
- if (RotationKeys.size())
- {
- foundRotationIndex = -1;
- //Test the Hints...
- if (rotationHint>=0 && (u32)rotationHint < RotationKeys.size())
- {
- //check this hint
- if (rotationHint>0 && RotationKeys[rotationHint].frame>=frame && RotationKeys[rotationHint-1].frame<frame )
- foundRotationIndex=rotationHint;
- else if (rotationHint+1 < (s32)RotationKeys.size())
- {
- //check the next index
- if ( RotationKeys[rotationHint+1].frame>=frame &&
- RotationKeys[rotationHint+0].frame<frame)
- {
- rotationHint++;
- foundRotationIndex=rotationHint;
- }
- }
- }
- //The hint test failed, do a full scan...
- if (foundRotationIndex==-1)
- {
- for (u32 i=0; i<RotationKeys.size(); ++i)
- {
- if (RotationKeys[i].frame >= frame) //Keys should be sorted by frame
- {
- foundRotationIndex=i;
- rotationHint=i;
- break;
- }
- }
- }
- //Do interpolation...
- if (foundRotationIndex!=-1)
- {
- if (InterpolationMode==EIM_CONSTANT || foundRotationIndex==0)
- {
- rotation = RotationKeys[foundRotationIndex].rotation;
- }
- else if (InterpolationMode==EIM_LINEAR)
- {
- const SRotationKey& KeyA = RotationKeys[foundRotationIndex];
- const SRotationKey& KeyB = RotationKeys[foundRotationIndex-1];
- const f32 fd1 = frame - KeyA.frame;
- const f32 fd2 = KeyB.frame - frame;
- const f32 t = fd1/(fd1+fd2);
- /*
- f32 t = 0;
- if (KeyA.frame!=KeyB.frame)
- t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame);
- */
- rotation.slerp(KeyA.rotation, KeyB.rotation, t);
- }
- }
- }
- }
- }
- //--------------------------------------------------------------------------
- // Software Skinning
- //--------------------------------------------------------------------------
- //! Preforms a software skin on this mesh based of joint positions
- void CSkinnedMesh::skinMesh(f32 strength, SkinningCallback sc, int offset)
- {
- if (!HasAnimation || SkinnedLastFrame)
- return;
- //----------------
- // This is marked as "Temp!". A shiny dubloon to whomever can tell me why.
- buildAllGlobalAnimatedMatrices();
- //-----------------
- SkinnedLastFrame=true;
- m_current_joint = 0;
- if (HardwareSkinning)
- {
- for (u32 i = 0; i < RootJoints.size(); i++)
- skinJoint(RootJoints[i], 0, strength, sc, offset);
- }
- else
- {
- //Software skin....
- u32 i;
- //rigid animation
- for (i=0; i<AllJoints.size(); ++i)
- {
- for (u32 j=0; j<AllJoints[i]->AttachedMeshes.size(); ++j)
- {
- SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ];
- Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix;
- }
- }
- //clear skinning helper array
- for (i=0; i<Vertices_Moved.size(); ++i)
- for (u32 j=0; j<Vertices_Moved[i].size(); ++j)
- Vertices_Moved[i][j]=false;
- //skin starting with the root joints
- for (i=0; i<RootJoints.size(); ++i)
- skinJoint(RootJoints[i], 0, strength);
- for (i=0; i<SkinningBuffers->size(); ++i)
- (*SkinningBuffers)[i]->setDirty(EBT_VERTEX);
- }
- updateBoundingBox();
- }
- void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint, f32 strength,
- SkinningCallback sc, int offset)
- {
- if (joint->Weights.size())
- {
- //Find this joints pull on vertices...
- core::matrix4 jointVertexPull(core::matrix4::EM4CONST_NOTHING);
- jointVertexPull.setbyproduct(joint->GlobalAnimatedMatrix, joint->GlobalInversedMatrix);
- if (HardwareSkinning)
- {
- if (sc != NULL) sc(jointVertexPull, m_current_joint, offset);
- m_current_joint++;
- }
- else
- {
- 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];
- // Pull this vertex...
- jointVertexPull.transformVect(thisVertexMove, weight.StaticPos);
- if (AnimateNormals)
- jointVertexPull.rotateVect(thisNormalMove, weight.StaticNormal);
- // 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();
- }
- }
- }
- //Skin all children
- for (u32 j=0; j<joint->Children.size(); ++j)
- skinJoint(joint->Children[j], joint, strength, sc, offset);
- }
- E_ANIMATED_MESH_TYPE CSkinnedMesh::getMeshType() const
- {
- return EAMT_SKINNED;
- }
- //! Gets joint count.
- u32 CSkinnedMesh::getJointCount() const
- {
- return AllJoints.size();
- }
- //! Gets the name of a joint.
- const c8* CSkinnedMesh::getJointName(u32 number) const
- {
- if (number >= AllJoints.size())
- return 0;
- return AllJoints[number]->Name.c_str();
- }
- //! Gets a joint number from its name
- s32 CSkinnedMesh::getJointNumber(const c8* name) const
- {
- for (u32 i=0; i<AllJoints.size(); ++i)
- {
- if (AllJoints[i]->Name == name)
- return i;
- }
- return -1;
- }
- //! returns amount of mesh buffers.
- u32 CSkinnedMesh::getMeshBufferCount() const
- {
- return LocalBuffers.size();
- }
- //! returns pointer to a mesh buffer
- IMeshBuffer* CSkinnedMesh::getMeshBuffer(u32 nr) const
- {
- if (nr < LocalBuffers.size())
- return LocalBuffers[nr];
- else
- return 0;
- }
- //! Returns pointer to a mesh buffer which fits a material
- IMeshBuffer* CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const
- {
- for (u32 i=0; i<LocalBuffers.size(); ++i)
- {
- if (LocalBuffers[i]->getMaterial() == material)
- return LocalBuffers[i];
- }
- return 0;
- }
- //! returns an axis aligned bounding box
- const core::aabbox3d<f32>& CSkinnedMesh::getBoundingBox() const
- {
- return BoundingBox;
- }
- //! set user axis aligned bounding box
- void CSkinnedMesh::setBoundingBox( const core::aabbox3df& box)
- {
- BoundingBox = box;
- }
- //! sets a flag of all contained materials to a new value
- void CSkinnedMesh::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
- {
- for (u32 i=0; i<LocalBuffers.size(); ++i)
- LocalBuffers[i]->Material.setFlag(flag,newvalue);
- }
- //! set the hardware mapping hint, for driver
- void CSkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint,
- E_BUFFER_TYPE buffer)
- {
- for (u32 i=0; i<LocalBuffers.size(); ++i)
- LocalBuffers[i]->setHardwareMappingHint(newMappingHint, buffer);
- }
- //! flags the meshbuffer as changed, reloads hardware buffers
- void CSkinnedMesh::setDirty(E_BUFFER_TYPE buffer)
- {
- for (u32 i=0; i<LocalBuffers.size(); ++i)
- LocalBuffers[i]->setDirty(buffer);
- }
- //! uses animation from another mesh
- bool CSkinnedMesh::useAnimationFrom(const ISkinnedMesh *mesh)
- {
- bool unmatched=false;
- for(u32 i=0;i<AllJoints.size();++i)
- {
- SJoint *joint=AllJoints[i];
- joint->UseAnimationFrom=0;
- if (joint->Name=="")
- unmatched=true;
- else
- {
- for(u32 j=0;j<mesh->getAllJoints().size();++j)
- {
- SJoint *otherJoint=mesh->getAllJoints()[j];
- if (joint->Name==otherJoint->Name)
- {
- joint->UseAnimationFrom=otherJoint;
- }
- }
- if (!joint->UseAnimationFrom)
- unmatched=true;
- }
- }
- checkForAnimation();
- return !unmatched;
- }
- //!Update Normals when Animating
- //!False= Don't animate them, faster
- //!True= Update normals (default)
- void CSkinnedMesh::updateNormalsWhenAnimating(bool on)
- {
- AnimateNormals = on;
- }
- //!Sets Interpolation Mode
- void CSkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode)
- {
- InterpolationMode = mode;
- }
- core::array<scene::SSkinMeshBuffer*> &CSkinnedMesh::getMeshBuffers()
- {
- return LocalBuffers;
- }
- core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints()
- {
- return AllJoints;
- }
- const core::array<CSkinnedMesh::SJoint*> &CSkinnedMesh::getAllJoints() const
- {
- return AllJoints;
- }
- //! (This feature is not implementated in irrlicht yet)
- bool CSkinnedMesh::setHardwareSkinning(bool on)
- {
- if (HardwareSkinning!=on)
- {
- if (on)
- toStaticPose();
- HardwareSkinning=on;
- }
- return HardwareSkinning;
- }
- void CSkinnedMesh::toStaticPose()
- {
- for (u32 i=0; i<AllJoints.size(); ++i)
- {
- SJoint *joint=AllJoints[i];
- for (u32 j=0; j<joint->Weights.size(); ++j)
- {
- const u16 buffer_id=joint->Weights[j].buffer_id;
- const u32 vertex_id=joint->Weights[j].vertex_id;
- LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos;
- LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal;
- LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated();
- }
- }
- }
- void CSkinnedMesh::calculateGlobalMatrices(SJoint *joint,SJoint *parentJoint)
- {
- if (!joint && parentJoint) // bit of protection from endless loops
- return;
- //Go through the root bones
- if (!joint)
- {
- for (u32 i=0; i<RootJoints.size(); ++i)
- calculateGlobalMatrices(RootJoints[i],0);
- return;
- }
- if (!parentJoint)
- joint->GlobalMatrix = joint->LocalMatrix;
- else
- joint->GlobalMatrix = parentJoint->GlobalMatrix * joint->LocalMatrix;
- joint->LocalAnimatedMatrix=joint->LocalMatrix;
- joint->GlobalAnimatedMatrix=joint->GlobalMatrix;
- if (joint->GlobalInversedMatrix.isIdentity())//might be pre calculated
- {
- joint->GlobalInversedMatrix = joint->GlobalMatrix;
- joint->GlobalInversedMatrix.makeInverse(); // slow
- }
- for (u32 j=0; j<joint->Children.size(); ++j)
- calculateGlobalMatrices(joint->Children[j],joint);
- SkinnedLastFrame=false;
- }
- void CSkinnedMesh::checkForAnimation()
- {
- u32 i,j;
- //Check for animation...
- HasAnimation = false;
- for(i=0;i<AllJoints.size();++i)
- {
- if (AllJoints[i]->UseAnimationFrom)
- {
- if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() ||
- AllJoints[i]->UseAnimationFrom->ScaleKeys.size() ||
- AllJoints[i]->UseAnimationFrom->RotationKeys.size() )
- {
- HasAnimation = true;
- break;
- }
- }
- }
- //meshes with weights, are still counted as animated for ragdolls, etc
- if (!HasAnimation)
- {
- for(i=0;i<AllJoints.size();++i)
- {
- if (AllJoints[i]->Weights.size())
- {
- HasAnimation = true;
- break;
- }
- }
- }
- if (HasAnimation)
- {
- //--- Find the length of the animation ---
- AnimationFrames=0;
- for(i=0;i<AllJoints.size();++i)
- {
- if (AllJoints[i]->UseAnimationFrom)
- {
- if (AllJoints[i]->UseAnimationFrom->PositionKeys.size())
- if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > AnimationFrames)
- AnimationFrames=AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame;
- if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size())
- if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > AnimationFrames)
- AnimationFrames=AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame;
- if (AllJoints[i]->UseAnimationFrom->RotationKeys.size())
- if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > AnimationFrames)
- AnimationFrames=AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame;
- }
- }
- }
- if (HasAnimation && !PreparedForSkinning)
- {
- PreparedForSkinning=true;
- //check for bugs:
- for(i=0; i < AllJoints.size(); ++i)
- {
- SJoint *joint = AllJoints[i];
- for (j=0; j<joint->Weights.size(); ++j)
- {
- const u16 buffer_id=joint->Weights[j].buffer_id;
- const u32 vertex_id=joint->Weights[j].vertex_id;
- //check for invalid ids
- if (buffer_id>=LocalBuffers.size())
- {
- os::Printer::log("Skinned Mesh: Weight buffer id too large", ELL_WARNING);
- joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0;
- }
- else if (vertex_id>=LocalBuffers[buffer_id]->getVertexCount())
- {
- os::Printer::log("Skinned Mesh: Weight vertex id too large", ELL_WARNING);
- joint->Weights[j].buffer_id = joint->Weights[j].vertex_id =0;
- }
- }
- }
- //An array used in skinning
- for (i=0; i<Vertices_Moved.size(); ++i)
- for (j=0; j<Vertices_Moved[i].size(); ++j)
- Vertices_Moved[i][j] = false;
- // For skinning: cache weight values for speed
- for (i=0; i<AllJoints.size(); ++i)
- {
- SJoint *joint = AllJoints[i];
- for (j=0; j<joint->Weights.size(); ++j)
- {
- const u16 buffer_id=joint->Weights[j].buffer_id;
- const u32 vertex_id=joint->Weights[j].vertex_id;
- joint->Weights[j].Moved = &Vertices_Moved[buffer_id] [vertex_id];
- joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos;
- joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal;
- //joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos;
- }
- }
- // normalize weights
- normalizeWeights();
- }
- SkinnedLastFrame=false;
- }
- //! called by loader after populating with mesh and bone data
- void CSkinnedMesh::finalize()
- {
- u32 i;
- // Make sure we recalc the next frame
- LastAnimatedFrame=-1;
- SkinnedLastFrame=false;
- //calculate bounding box
- for (i=0; i<LocalBuffers.size(); ++i)
- {
- LocalBuffers[i]->recalculateBoundingBox();
- }
- if (AllJoints.size() || RootJoints.size())
- {
- // populate AllJoints or RootJoints, depending on which is empty
- if (!RootJoints.size())
- {
- for(u32 CheckingIdx=0; CheckingIdx < AllJoints.size(); ++CheckingIdx)
- {
- bool foundParent=false;
- for(i=0; i < AllJoints.size(); ++i)
- {
- for(u32 n=0; n < AllJoints[i]->Children.size(); ++n)
- {
- if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx])
- foundParent=true;
- }
- }
- if (!foundParent)
- RootJoints.push_back(AllJoints[CheckingIdx]);
- }
- }
- else
- {
- AllJoints=RootJoints;
- }
- }
- for(i=0; i < AllJoints.size(); ++i)
- {
- AllJoints[i]->UseAnimationFrom=AllJoints[i];
- }
- //Set array sizes...
- for (i=0; i<LocalBuffers.size(); ++i)
- {
- Vertices_Moved.push_back( core::array<bool>() );
- Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount());
- }
- //Todo: optimise keys here...
- checkForAnimation();
- if (HasAnimation)
- {
- //--- optimize and check keyframes ---
- for(i=0;i<AllJoints.size();++i)
- {
- core::array<SPositionKey> &PositionKeys =AllJoints[i]->PositionKeys;
- core::array<SScaleKey> &ScaleKeys = AllJoints[i]->ScaleKeys;
- core::array<SRotationKey> &RotationKeys = AllJoints[i]->RotationKeys;
- if (PositionKeys.size()>2)
- {
- for(u32 j=0;j<PositionKeys.size()-2;++j)
- {
- if (PositionKeys[j].position == PositionKeys[j+1].position && PositionKeys[j+1].position == PositionKeys[j+2].position)
- {
- PositionKeys.erase(j+1); //the middle key is unneeded
- --j;
- }
- }
- }
- if (PositionKeys.size()>1)
- {
- for(u32 j=0;j<PositionKeys.size()-1;++j)
- {
- if (PositionKeys[j].frame >= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems
- {
- PositionKeys.erase(j+1);
- --j;
- }
- }
- }
- if (ScaleKeys.size()>2)
- {
- for(u32 j=0;j<ScaleKeys.size()-2;++j)
- {
- if (ScaleKeys[j].scale == ScaleKeys[j+1].scale && ScaleKeys[j+1].scale == ScaleKeys[j+2].scale)
- {
- ScaleKeys.erase(j+1); //the middle key is unneeded
- --j;
- }
- }
- }
- if (ScaleKeys.size()>1)
- {
- for(u32 j=0;j<ScaleKeys.size()-1;++j)
- {
- if (ScaleKeys[j].frame >= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems
- {
- ScaleKeys.erase(j+1);
- --j;
- }
- }
- }
- if (RotationKeys.size()>2)
- {
- for(u32 j=0;j<RotationKeys.size()-2;++j)
- {
- if (RotationKeys[j].rotation == RotationKeys[j+1].rotation && RotationKeys[j+1].rotation == RotationKeys[j+2].rotation)
- {
- RotationKeys.erase(j+1); //the middle key is unneeded
- --j;
- }
- }
- }
- if (RotationKeys.size()>1)
- {
- for(u32 j=0;j<RotationKeys.size()-1;++j)
- {
- if (RotationKeys[j].frame >= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems
- {
- RotationKeys.erase(j+1);
- --j;
- }
- }
- }
- //Fill empty keyframe areas
- if (PositionKeys.size())
- {
- SPositionKey *Key;
- Key=&PositionKeys[0];//getFirst
- if (Key->frame!=0)
- {
- PositionKeys.push_front(*Key);
- Key=&PositionKeys[0];//getFirst
- Key->frame=0;
- }
- Key=&PositionKeys.getLast();
- if (Key->frame!=AnimationFrames)
- {
- PositionKeys.push_back(*Key);
- Key=&PositionKeys.getLast();
- Key->frame=AnimationFrames;
- }
- }
- if (ScaleKeys.size())
- {
- SScaleKey *Key;
- Key=&ScaleKeys[0];//getFirst
- if (Key->frame!=0)
- {
- ScaleKeys.push_front(*Key);
- Key=&ScaleKeys[0];//getFirst
- Key->frame=0;
- }
- Key=&ScaleKeys.getLast();
- if (Key->frame!=AnimationFrames)
- {
- ScaleKeys.push_back(*Key);
- Key=&ScaleKeys.getLast();
- Key->frame=AnimationFrames;
- }
- }
- if (RotationKeys.size())
- {
- SRotationKey *Key;
- Key=&RotationKeys[0];//getFirst
- if (Key->frame!=0)
- {
- RotationKeys.push_front(*Key);
- Key=&RotationKeys[0];//getFirst
- Key->frame=0;
- }
- Key=&RotationKeys.getLast();
- if (Key->frame!=AnimationFrames)
- {
- RotationKeys.push_back(*Key);
- Key=&RotationKeys.getLast();
- Key->frame=AnimationFrames;
- }
- }
- }
- }
- //Needed for animation and skinning...
- calculateGlobalMatrices(0,0);
- //animateMesh(0, 1);
- //buildAllLocalAnimatedMatrices();
- //buildAllGlobalAnimatedMatrices();
- //rigid animation for non animated meshes
- for (i=0; i<AllJoints.size(); ++i)
- {
- for (u32 j=0; j<AllJoints[i]->AttachedMeshes.size(); ++j)
- {
- SSkinMeshBuffer* Buffer=(*SkinningBuffers)[ AllJoints[i]->AttachedMeshes[j] ];
- Buffer->Transformation=AllJoints[i]->GlobalAnimatedMatrix;
- }
- }
- //calculate bounding box
- if (LocalBuffers.empty())
- BoundingBox.reset(0,0,0);
- else
- {
- irr::core::aabbox3df bb(LocalBuffers[0]->BoundingBox);
- LocalBuffers[0]->Transformation.transformBoxEx(bb);
- BoundingBox.reset(bb);
- for (u32 j=1; j<LocalBuffers.size(); ++j)
- {
- bb = LocalBuffers[j]->BoundingBox;
- LocalBuffers[j]->Transformation.transformBoxEx(bb);
- BoundingBox.addInternalBox(bb);
- }
- }
- }
- void CSkinnedMesh::updateBoundingBox(void)
- {
- if(HardwareSkinning || !SkinningBuffers)
- return;
- core::array<SSkinMeshBuffer*> & buffer = *SkinningBuffers;
- BoundingBox.reset(0,0,0);
- if (!buffer.empty())
- {
- for (u32 j=0; j<buffer.size(); ++j)
- {
- buffer[j]->recalculateBoundingBox();
- core::aabbox3df bb = buffer[j]->BoundingBox;
- buffer[j]->Transformation.transformBoxEx(bb);
- BoundingBox.addInternalBox(bb);
- }
- }
- }
- scene::SSkinMeshBuffer *CSkinnedMesh::addMeshBuffer()
- {
- scene::SSkinMeshBuffer *buffer=new scene::SSkinMeshBuffer();
- LocalBuffers.push_back(buffer);
- return buffer;
- }
- CSkinnedMesh::SJoint *CSkinnedMesh::addJoint(SJoint *parent)
- {
- SJoint *joint=new SJoint;
- AllJoints.push_back(joint);
- if (!parent)
- {
- //Add root joints to array in finalize()
- }
- else
- {
- //Set parent (Be careful of the mesh loader also setting the parent)
- parent->Children.push_back(joint);
- }
- return joint;
- }
- CSkinnedMesh::SPositionKey *CSkinnedMesh::addPositionKey(SJoint *joint)
- {
- if (!joint)
- return 0;
- joint->PositionKeys.push_back(SPositionKey());
- return &joint->PositionKeys.getLast();
- }
- CSkinnedMesh::SScaleKey *CSkinnedMesh::addScaleKey(SJoint *joint)
- {
- if (!joint)
- return 0;
- joint->ScaleKeys.push_back(SScaleKey());
- return &joint->ScaleKeys.getLast();
- }
- CSkinnedMesh::SRotationKey *CSkinnedMesh::addRotationKey(SJoint *joint)
- {
- if (!joint)
- return 0;
- joint->RotationKeys.push_back(SRotationKey());
- return &joint->RotationKeys.getLast();
- }
- CSkinnedMesh::SWeight *CSkinnedMesh::addWeight(SJoint *joint)
- {
- if (!joint)
- return 0;
- joint->Weights.push_back(SWeight());
- return &joint->Weights.getLast();
- }
- bool CSkinnedMesh::isStatic()
- {
- return !HasAnimation;
- }
- void CSkinnedMesh::normalizeWeights()
- {
- // note: unsure if weights ids are going to be used.
- // Normalise the weights on bones....
- u32 i,j;
- core::array< core::array<f32> > verticesTotalWeight;
- verticesTotalWeight.reallocate(LocalBuffers.size());
- for (i=0; i<LocalBuffers.size(); ++i)
- {
- verticesTotalWeight.push_back(core::array<f32>());
- verticesTotalWeight[i].set_used(LocalBuffers[i]->getVertexCount());
- }
- for (i=0; i<verticesTotalWeight.size(); ++i)
- for (j=0; j<verticesTotalWeight[i].size(); ++j)
- verticesTotalWeight[i][j] = 0;
- for (i=0; i<AllJoints.size(); ++i)
- {
- SJoint *joint=AllJoints[i];
- for (j=0; j<joint->Weights.size(); ++j)
- {
- if (joint->Weights[j].strength<=0)//Check for invalid weights
- {
- joint->Weights.erase(j);
- --j;
- }
- else
- {
- verticesTotalWeight[joint->Weights[j].buffer_id] [joint->Weights[j].vertex_id] += joint->Weights[j].strength;
- }
- }
- }
- for (i=0; i<AllJoints.size(); ++i)
- {
- SJoint *joint=AllJoints[i];
- for (j=0; j< joint->Weights.size(); ++j)
- {
- const f32 total = verticesTotalWeight[joint->Weights[j].buffer_id] [joint->Weights[j].vertex_id];
- if (total != 0 && total != 1)
- joint->Weights[j].strength /= total;
- }
- }
- }
- void CSkinnedMesh::recoverJointsFromMesh(core::array<IBoneSceneNode*> &jointChildSceneNodes)
- {
- for (u32 i=0; i<AllJoints.size(); ++i)
- {
- IBoneSceneNode* node=jointChildSceneNodes[i];
- SJoint *joint=AllJoints[i];
- node->setPosition(joint->LocalAnimatedMatrix.getTranslation());
- node->setRotation(joint->LocalAnimatedMatrix.getRotationDegrees());
- node->setScale(joint->LocalAnimatedMatrix.getScale());
- node->positionHint=joint->positionHint;
- node->scaleHint=joint->scaleHint;
- node->rotationHint=joint->rotationHint;
- node->updateAbsolutePosition();
- }
- }
- void CSkinnedMesh::transferJointsToMesh(const core::array<IBoneSceneNode*> &jointChildSceneNodes)
- {
- for (u32 i=0; i<AllJoints.size(); ++i)
- {
- const IBoneSceneNode* const node=jointChildSceneNodes[i];
- SJoint *joint=AllJoints[i];
- joint->LocalAnimatedMatrix.setRotationDegrees(node->getRotation());
- joint->LocalAnimatedMatrix.setTranslation(node->getPosition());
- joint->LocalAnimatedMatrix *= core::matrix4().setScale(node->getScale());
- joint->positionHint=node->positionHint;
- joint->scaleHint=node->scaleHint;
- joint->rotationHint=node->rotationHint;
- joint->GlobalSkinningSpace=(node->getSkinningSpace()==EBSS_GLOBAL);
- }
- // Make sure we recalc the next frame
- LastAnimatedFrame=-1;
- SkinnedLastFrame=false;
- }
- void CSkinnedMesh::transferOnlyJointsHintsToMesh(const core::array<IBoneSceneNode*> &jointChildSceneNodes)
- {
- for (u32 i=0; i<AllJoints.size(); ++i)
- {
- const IBoneSceneNode* const node=jointChildSceneNodes[i];
- SJoint *joint=AllJoints[i];
- joint->positionHint=node->positionHint;
- joint->scaleHint=node->scaleHint;
- joint->rotationHint=node->rotationHint;
- }
- SkinnedLastFrame=false;
- }
- void CSkinnedMesh::addJoints(core::array<IBoneSceneNode*> &jointChildSceneNodes,
- IAnimatedMeshSceneNode* node, ISceneManager* smgr)
- {
- //Create new joints
- for (u32 i=0; i<AllJoints.size(); ++i)
- {
- jointChildSceneNodes.push_back(new CBoneSceneNode(0, smgr, 0, i, AllJoints[i]->Name.c_str()));
- }
- //Match up parents
- for (u32 i=0; i<jointChildSceneNodes.size(); ++i)
- {
- const SJoint* const joint=AllJoints[i]; //should be fine
- s32 parentID=-1;
- for (u32 j=0;(parentID==-1)&&(j<AllJoints.size());++j)
- {
- if (i!=j)
- {
- const SJoint* const parentTest=AllJoints[j];
- for (u32 n=0; n<parentTest->Children.size(); ++n)
- {
- if (parentTest->Children[n]==joint)
- {
- parentID=j;
- break;
- }
- }
- }
- }
- IBoneSceneNode* bone=jointChildSceneNodes[i];
- if (parentID!=-1)
- bone->setParent(jointChildSceneNodes[parentID]);
- else
- bone->setParent(node);
- bone->drop();
- }
- SkinnedLastFrame=false;
- }
- bool CSkinnedMesh::sortJointInfluenceFunc(const JointInfluence& a,
- const JointInfluence& b)
- {
- return a.weight > b.weight;
- }
- 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(sortJointInfluenceFunc);
- 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 = -100000;
- 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_total_joints = m_current_joint;
- }
- 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(bool(*predicate)(IMeshBuffer*))
- {
- bool recalculate_animation = false;
- toStaticPose();
- for (u32 b = 0; b < LocalBuffers.size(); b++)
- {
- bool recalculate_joints = false;
- core::map<u32, u32> vert_loc_map;
- SSkinMeshBuffer* ssmb = LocalBuffers[b];
- if (ssmb)
- {
- if (!predicate(ssmb)) continue;
- recalculate_joints = true;
- recalculate_animation = true;
- core::map<video::S3DVertexTangents, u32> vert_map;
- core::array<u16> tmp_indices;
- for (u32 i = 0; i < ssmb->Indices.size(); i++)
- {
- u32 vert_location = 0;
- const u32 cur_ver_loc = ssmb->Indices[i];
- const video::S3DVertex& v_old = ssmb->Vertices_Standard[cur_ver_loc];
- video::S3DVertexTangents v(v_old.Pos, v_old.Normal, v_old.Color, v_old.TCoords);
- core::map<video::S3DVertexTangents, u32>::Node *n = vert_map.find(v);
- if (n)
- {
- vert_location = n->getValue();
- }
- else
- {
- vert_location = ssmb->Vertices_Tangents.size();
- ssmb->Vertices_Tangents.push_back(v);
- vert_map.insert(v, vert_location);
- }
- vert_loc_map[cur_ver_loc] = vert_location;
- tmp_indices.push_back(vert_location);
- }
- const s32 index_count = tmp_indices.size();
- u16* idx = tmp_indices.pointer();
- video::S3DVertexTangents* v = ssmb->Vertices_Tangents.pointer();
- core::vector3df local_normal;
- for (s32 i = 0; i < index_count; i += 3)
- {
- calculateTangents(
- local_normal,
- v[idx[i+0]].Tangent,
- v[idx[i+0]].Binormal,
- v[idx[i+0]].Pos,
- v[idx[i+1]].Pos,
- v[idx[i+2]].Pos,
- v[idx[i+0]].TCoords,
- v[idx[i+1]].TCoords,
- v[idx[i+2]].TCoords);
- calculateTangents(
- local_normal,
- v[idx[i+1]].Tangent,
- v[idx[i+1]].Binormal,
- v[idx[i+1]].Pos,
- v[idx[i+2]].Pos,
- v[idx[i+0]].Pos,
- v[idx[i+1]].TCoords,
- v[idx[i+2]].TCoords,
- v[idx[i+0]].TCoords);
- calculateTangents(
- local_normal,
- v[idx[i+2]].Tangent,
- v[idx[i+2]].Binormal,
- v[idx[i+2]].Pos,
- v[idx[i+0]].Pos,
- v[idx[i+1]].Pos,
- v[idx[i+2]].TCoords,
- v[idx[i+0]].TCoords,
- v[idx[i+1]].TCoords);
- }
- ssmb->Indices = tmp_indices;
- ssmb->Vertices_Standard.clear();
- ssmb->VertexType = video::EVT_TANGENTS;
- }
- if (recalculate_joints)
- {
- Vertices_Moved[b].set_used(ssmb->getVertexCount());
- for (u32 i = 0; i < AllJoints.size(); i++)
- {
- SJoint *joint = AllJoints[i];
- for (u32 j = 0; j <joint->Weights.size(); j++)
- {
- if (joint->Weights[j].buffer_id == b)
- {
- core::map<u32, u32>::Node *n =
- vert_loc_map.find(joint->Weights[j].vertex_id);
- if (n)
- {
- joint->Weights[j].vertex_id = n->getValue();
- }
- }
- }
- }
- }
- }
- if (recalculate_animation)
- {
- PreparedForSkinning = false;
- checkForAnimation();
- }
- }
- void CSkinnedMesh::calculateTangents(
- core::vector3df& normal,
- core::vector3df& tangent,
- core::vector3df& binormal,
- core::vector3df& vt1, core::vector3df& vt2, core::vector3df& vt3, // vertices
- core::vector2df& tc1, core::vector2df& tc2, core::vector2df& tc3) // texture coords
- {
- core::vector3df v1 = vt1 - vt2;
- core::vector3df v2 = vt3 - vt1;
- normal = v2.crossProduct(v1);
- normal.normalize();
- // binormal
- f32 deltaX1 = tc1.X - tc2.X;
- f32 deltaX2 = tc3.X - tc1.X;
- binormal = (v1 * deltaX2) - (v2 * deltaX1);
- binormal.normalize();
- // tangent
- f32 deltaY1 = tc1.Y - tc2.Y;
- f32 deltaY2 = tc3.Y - tc1.Y;
- tangent = (v1 * deltaY2) - (v2 * deltaY1);
- tangent.normalize();
- // adjust
- core::vector3df txb = tangent.crossProduct(binormal);
- if (txb.dotProduct(normal) < 0.0f)
- {
- tangent *= -1.0f;
- binormal *= -1.0f;
- }
- }
- } // end namespace scene
- } // end namespace irr
- #endif // _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_
|