mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-20 15:40:32 +00:00
Reimplement NiGeomMorpherController using Ogre's pose animation system
This commit is contained in:
parent
596c9b80a9
commit
6d47d710a0
@ -116,21 +116,6 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape
|
|||||||
Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC;
|
Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC;
|
||||||
bool vertShadowBuffer = false;
|
bool vertShadowBuffer = false;
|
||||||
|
|
||||||
bool geomMorpherController = false;
|
|
||||||
if(!shape->controller.empty())
|
|
||||||
{
|
|
||||||
Nif::ControllerPtr ctrl = shape->controller;
|
|
||||||
do {
|
|
||||||
if(ctrl->recType == Nif::RC_NiGeomMorpherController)
|
|
||||||
{
|
|
||||||
vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
|
|
||||||
vertShadowBuffer = true;
|
|
||||||
geomMorpherController = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while(!(ctrl=ctrl->next).empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(skin != NULL)
|
if(skin != NULL)
|
||||||
{
|
{
|
||||||
vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
|
vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY;
|
||||||
@ -350,10 +335,39 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape
|
|||||||
mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest);
|
mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a dummy vertex animation track if there's a geom morpher controller
|
|
||||||
// This is required to make Ogre create the buffers we will use for software vertex animation
|
if(!shape->controller.empty())
|
||||||
if (srcVerts.size() && geomMorpherController)
|
{
|
||||||
mesh->createAnimation("dummy", 0)->createVertexTrack(1, sub->vertexData, Ogre::VAT_MORPH);
|
Nif::ControllerPtr ctrl = shape->controller;
|
||||||
|
do {
|
||||||
|
// Load GeomMorpherController into an Ogre::Pose and Animation
|
||||||
|
if(ctrl->recType == Nif::RC_NiGeomMorpherController)
|
||||||
|
{
|
||||||
|
const Nif::NiGeomMorpherController *geom =
|
||||||
|
static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr());
|
||||||
|
|
||||||
|
const std::vector<Nif::NiMorphData::MorphData>& morphs = geom->data.getPtr()->mMorphs;
|
||||||
|
// Note we are not interested in morph 0, which just contains the original vertices
|
||||||
|
for (unsigned int i = 1; i < morphs.size(); ++i)
|
||||||
|
{
|
||||||
|
Ogre::Pose* pose = mesh->createPose(i);
|
||||||
|
const Nif::NiMorphData::MorphData& data = morphs[i];
|
||||||
|
for (unsigned int v = 0; v < data.mVertices.size(); ++v)
|
||||||
|
pose->addVertex(v, data.mVertices[v]);
|
||||||
|
|
||||||
|
Ogre::String animationID = Ogre::StringConverter::toString(ctrl->recIndex)
|
||||||
|
+ "_" + Ogre::StringConverter::toString(i);
|
||||||
|
Ogre::VertexAnimationTrack* track =
|
||||||
|
mesh->createAnimation(animationID, 0)
|
||||||
|
->createVertexTrack(1, Ogre::VAT_POSE);
|
||||||
|
Ogre::VertexPoseKeyFrame* keyframe = track->createVertexPoseKeyFrame(0);
|
||||||
|
keyframe->addPoseReference(i-1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(!(ctrl=ctrl->next).empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -534,18 +534,18 @@ public:
|
|||||||
class Value : public Ogre::ControllerValue<Ogre::Real>, public ValueInterpolator
|
class Value : public Ogre::ControllerValue<Ogre::Real>, public ValueInterpolator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Ogre::SubEntity *mSubEntity;
|
Ogre::Entity *mEntity;
|
||||||
std::vector<Nif::NiMorphData::MorphData> mMorphs;
|
std::vector<Nif::NiMorphData::MorphData> mMorphs;
|
||||||
std::vector<float> mValues;
|
size_t mControllerIndex;
|
||||||
|
|
||||||
std::vector<Ogre::Vector3> mVertices;
|
std::vector<Ogre::Vector3> mVertices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data)
|
Value(Ogre::Entity *ent, const Nif::NiMorphData *data, size_t controllerIndex)
|
||||||
: mSubEntity(subent)
|
: mEntity(ent)
|
||||||
, mMorphs(data->mMorphs)
|
, mMorphs(data->mMorphs)
|
||||||
|
, mControllerIndex(controllerIndex)
|
||||||
{
|
{
|
||||||
mValues.resize(mMorphs.size()-1, 0.f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Ogre::Real getValue() const
|
virtual Ogre::Real getValue() const
|
||||||
@ -558,21 +558,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (mMorphs.size() <= 1)
|
if (mMorphs.size() <= 1)
|
||||||
return;
|
return;
|
||||||
|
int i = 1;
|
||||||
#if OGRE_DOUBLE_PRECISION
|
|
||||||
#error "This code needs to be rewritten for double precision mode"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Ogre::VertexData* data = mSubEntity->_getSoftwareVertexAnimVertexData();
|
|
||||||
|
|
||||||
const Ogre::VertexElement* posElem =
|
|
||||||
data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
|
|
||||||
|
|
||||||
Ogre::HardwareVertexBufferSharedPtr vbuf =
|
|
||||||
data->vertexBufferBinding->getBuffer(posElem->getSource());
|
|
||||||
|
|
||||||
bool needToUpdate = false;
|
|
||||||
int i=0;
|
|
||||||
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
|
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
|
||||||
{
|
{
|
||||||
float val = 0;
|
float val = 0;
|
||||||
@ -580,37 +566,13 @@ public:
|
|||||||
val = interpKey(it->mData.mKeys, time);
|
val = interpKey(it->mData.mKeys, time);
|
||||||
val = std::max(0.f, std::min(1.f, val));
|
val = std::max(0.f, std::min(1.f, val));
|
||||||
|
|
||||||
if (val != mValues[i])
|
Ogre::String animationID = Ogre::StringConverter::toString(mControllerIndex)
|
||||||
needToUpdate = true;
|
+ "_" + Ogre::StringConverter::toString(i);
|
||||||
mValues[i] = val;
|
|
||||||
|
Ogre::AnimationState* state = mEntity->getAnimationState(animationID);
|
||||||
|
state->setEnabled(val > 0);
|
||||||
|
state->setWeight(val);
|
||||||
}
|
}
|
||||||
if (!needToUpdate)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// The first morph key always contains the original positions
|
|
||||||
mVertices = mMorphs[0].mVertices;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for (std::vector<Nif::NiMorphData::MorphData>::iterator it = mMorphs.begin()+1; it != mMorphs.end(); ++it,++i)
|
|
||||||
{
|
|
||||||
float val = mValues[i];
|
|
||||||
|
|
||||||
if (it->mVertices.size() != mMorphs[0].mVertices.size())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (val != 0)
|
|
||||||
{
|
|
||||||
for (unsigned int v=0; v<mVertices.size(); ++v)
|
|
||||||
mVertices[v] += it->mVertices[v] * val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mVertices.size() * sizeof(float)*3 != vbuf->getSizeInBytes())
|
|
||||||
return;
|
|
||||||
|
|
||||||
vbuf->writeData(0, vbuf->getSizeInBytes(), &mVertices[0]);
|
|
||||||
|
|
||||||
mSubEntity->_markBuffersUsedForAnimation();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -629,13 +591,6 @@ class NIFObjectLoader
|
|||||||
std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl;
|
std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fail(const std::string &msg)
|
|
||||||
{
|
|
||||||
std::cerr << "NIFObjectLoader: Fail: "<< msg << std::endl;
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void createEntity(const std::string &name, const std::string &group,
|
static void createEntity(const std::string &name, const std::string &group,
|
||||||
Ogre::SceneManager *sceneMgr, ObjectScenePtr scene,
|
Ogre::SceneManager *sceneMgr, ObjectScenePtr scene,
|
||||||
const Nif::Node *node, int flags, int animflags)
|
const Nif::Node *node, int flags, int animflags)
|
||||||
@ -693,7 +648,8 @@ class NIFObjectLoader
|
|||||||
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ?
|
||||||
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
Ogre::ControllerManager::getSingleton().getFrameTimeSource() :
|
||||||
Ogre::ControllerValueRealPtr());
|
Ogre::ControllerValueRealPtr());
|
||||||
Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(entity->getSubEntity(0), geom->data.getPtr()));
|
Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(
|
||||||
|
entity, geom->data.getPtr(), geom->recIndex));
|
||||||
|
|
||||||
GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
GeomMorpherController::Function* function = OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay));
|
||||||
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
|
scene->mMaxControllerLength = std::max(function->mStopTime, scene->mMaxControllerLength);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user