mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 16:15:33 +00:00
custom class for osgAnimation::RigGeometry, Collada animated deforming body parts
This commit is contained in:
parent
e5e6645575
commit
334c6dde0b
9 changed files with 473 additions and 10 deletions
|
@ -140,6 +140,7 @@
|
||||||
Feature #5198: Implement "Magic effect expired" event
|
Feature #5198: Implement "Magic effect expired" event
|
||||||
Feature #5454: Clear active spells from actor when he disappears from scene
|
Feature #5454: Clear active spells from actor when he disappears from scene
|
||||||
Feature #5489: MCP: Telekinesis fix for activators
|
Feature #5489: MCP: Telekinesis fix for activators
|
||||||
|
Feature #5701: Convert osgAnimation::RigGeometry to double-buffered custom version
|
||||||
Feature #5737: Handle instance move from one cell to another
|
Feature #5737: Handle instance move from one cell to another
|
||||||
Feature #5996: Support Lua scripts in OpenMW
|
Feature #5996: Support Lua scripts in OpenMW
|
||||||
Feature #6017: Separate persistent and temporary cell references when saving
|
Feature #6017: Separate persistent and temporary cell references when saving
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <components/sceneutil/lightmanager.hpp>
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
#include <components/sceneutil/morphgeometry.hpp>
|
#include <components/sceneutil/morphgeometry.hpp>
|
||||||
|
#include <components/sceneutil/riggeometryosgaextension.hpp>
|
||||||
#include <components/sceneutil/riggeometry.hpp>
|
#include <components/sceneutil/riggeometry.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
@ -244,6 +245,8 @@ namespace MWRender
|
||||||
if (dynamic_cast<const osgParticle::ParticleSystem*>(drawable))
|
if (dynamic_cast<const osgParticle::ParticleSystem*>(drawable))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
if (dynamic_cast<const SceneUtil::OsgaRigGeometry*>(drawable))
|
||||||
|
return nullptr;
|
||||||
if (const SceneUtil::RigGeometry* rig = dynamic_cast<const SceneUtil::RigGeometry*>(drawable))
|
if (const SceneUtil::RigGeometry* rig = dynamic_cast<const SceneUtil::RigGeometry*>(drawable))
|
||||||
return operator()(rig->getSourceGeometry());
|
return operator()(rig->getSourceGeometry());
|
||||||
if (const SceneUtil::MorphGeometry* morph = dynamic_cast<const SceneUtil::MorphGeometry*>(drawable))
|
if (const SceneUtil::MorphGeometry* morph = dynamic_cast<const SceneUtil::MorphGeometry*>(drawable))
|
||||||
|
|
|
@ -61,7 +61,7 @@ add_component_dir (sceneutil
|
||||||
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
|
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
|
||||||
lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer
|
lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer
|
||||||
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt
|
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt
|
||||||
screencapture depth color
|
screencapture depth color riggeometryosgaextension
|
||||||
)
|
)
|
||||||
|
|
||||||
add_component_dir (nif
|
add_component_dir (nif
|
||||||
|
|
|
@ -4,9 +4,12 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include <osg/AlphaFunc>
|
#include <osg/AlphaFunc>
|
||||||
|
#include <osg/Group>
|
||||||
#include <osg/Node>
|
#include <osg/Node>
|
||||||
#include <osg/UserDataContainer>
|
#include <osg/UserDataContainer>
|
||||||
|
|
||||||
|
#include <osgAnimation/RigGeometry>
|
||||||
|
|
||||||
#include <osgParticle/ParticleSystem>
|
#include <osgParticle/ParticleSystem>
|
||||||
|
|
||||||
#include <osgUtil/IncrementalCompileOperation>
|
#include <osgUtil/IncrementalCompileOperation>
|
||||||
|
@ -35,6 +38,7 @@
|
||||||
#include <components/sceneutil/visitor.hpp>
|
#include <components/sceneutil/visitor.hpp>
|
||||||
#include <components/sceneutil/lightmanager.hpp>
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
#include <components/sceneutil/depth.hpp>
|
#include <components/sceneutil/depth.hpp>
|
||||||
|
#include <components/sceneutil/riggeometryosgaextension.hpp>
|
||||||
|
|
||||||
#include <components/shader/shadervisitor.hpp>
|
#include <components/shader/shadervisitor.hpp>
|
||||||
#include <components/shader/shadermanager.hpp>
|
#include <components/shader/shadermanager.hpp>
|
||||||
|
@ -226,11 +230,12 @@ namespace Resource
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check Collada extra descriptions
|
// Check Collada extra descriptions
|
||||||
class ColladaAlphaTrickVisitor : public osg::NodeVisitor
|
class ColladaDescriptionVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ColladaAlphaTrickVisitor()
|
ColladaDescriptionVisitor()
|
||||||
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN),
|
||||||
|
mSkeleton(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +273,6 @@ namespace Resource
|
||||||
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the <node> has <extra type="Node"> <technique profile="OpenSceneGraph"> <Descriptions> <Description>
|
/* Check if the <node> has <extra type="Node"> <technique profile="OpenSceneGraph"> <Descriptions> <Description>
|
||||||
correct format for OpenMW: <Description>alphatest mode value MaterialName</Description>
|
correct format for OpenMW: <Description>alphatest mode value MaterialName</Description>
|
||||||
e.g <Description>alphatest GEQUAL 0.8 MyAlphaTestedMaterial</Description> */
|
e.g <Description>alphatest GEQUAL 0.8 MyAlphaTestedMaterial</Description> */
|
||||||
|
@ -299,6 +303,25 @@ namespace Resource
|
||||||
node.getStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON);
|
node.getStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (descriptionParts.size() > (0) && descriptionParts.at(0) == "bodypart")
|
||||||
|
{
|
||||||
|
SceneUtil::FindByClassVisitor osgaRigFinder("RigGeometryHolder");
|
||||||
|
node.accept(osgaRigFinder);
|
||||||
|
for(osg::Node* foundRigNode : osgaRigFinder.mFoundNodes)
|
||||||
|
{
|
||||||
|
if (SceneUtil::RigGeometryHolder* rigGeometryHolder = dynamic_cast<SceneUtil::RigGeometryHolder*> (foundRigNode))
|
||||||
|
mRigGeometryHolders.emplace_back(osg::ref_ptr<SceneUtil::RigGeometryHolder> (rigGeometryHolder));
|
||||||
|
else Log(Debug::Error) << "Converted RigGeometryHolder is of a wrong type.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mRigGeometryHolders.empty())
|
||||||
|
{
|
||||||
|
osgAnimation::RigGeometry::FindNearestParentSkeleton skeletonFinder;
|
||||||
|
mRigGeometryHolders[0]->accept(skeletonFinder);
|
||||||
|
if (skeletonFinder._root.valid()) mSkeleton = skeletonFinder._root;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +329,9 @@ namespace Resource
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> mDescriptions;
|
std::vector<std::string> mDescriptions;
|
||||||
|
public:
|
||||||
|
osgAnimation::Skeleton* mSkeleton; //pointer is valid only if the model is a bodypart, osg::ref_ptr<Skeleton>
|
||||||
|
std::vector<osg::ref_ptr<SceneUtil::RigGeometryHolder>> mRigGeometryHolders;
|
||||||
};
|
};
|
||||||
|
|
||||||
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
|
SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager)
|
||||||
|
@ -424,7 +450,7 @@ namespace Resource
|
||||||
{
|
{
|
||||||
return mLightingMethod;
|
return mLightingMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneManager::setConvertAlphaTestToAlphaToCoverage(bool convert)
|
void SceneManager::setConvertAlphaTestToAlphaToCoverage(bool convert)
|
||||||
{
|
{
|
||||||
mConvertAlphaTestToAlphaToCoverage = convert;
|
mConvertAlphaTestToAlphaToCoverage = convert;
|
||||||
|
@ -525,11 +551,55 @@ namespace Resource
|
||||||
if (nameFinder.mFoundNode)
|
if (nameFinder.mFoundNode)
|
||||||
nameFinder.mFoundNode->setNodeMask(hiddenNodeMask);
|
nameFinder.mFoundNode->setNodeMask(hiddenNodeMask);
|
||||||
|
|
||||||
|
// Recognize and convert osgAnimation::RigGeometry to OpenMW-optimized type
|
||||||
|
SceneUtil::FindByClassVisitor rigFinder("RigGeometry");
|
||||||
|
node->accept(rigFinder);
|
||||||
|
for(osg::Node* foundRigNode : rigFinder.mFoundNodes)
|
||||||
|
{
|
||||||
|
if (foundRigNode->libraryName() == std::string("osgAnimation"))
|
||||||
|
{
|
||||||
|
osgAnimation::RigGeometry* foundRigGeometry = static_cast<osgAnimation::RigGeometry*> (foundRigNode);
|
||||||
|
osg::ref_ptr<SceneUtil::RigGeometryHolder> newRig = new SceneUtil::RigGeometryHolder(*foundRigGeometry, osg::CopyOp::DEEP_COPY_ALL);
|
||||||
|
|
||||||
|
if (foundRigGeometry->getStateSet()) newRig->setStateSet(foundRigGeometry->getStateSet());
|
||||||
|
|
||||||
|
if (osg::Group* parent = dynamic_cast<osg::Group*> (foundRigGeometry->getParent(0)))
|
||||||
|
{
|
||||||
|
parent->removeChild(foundRigGeometry);
|
||||||
|
parent->addChild(newRig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ext == "dae")
|
if (ext == "dae")
|
||||||
{
|
{
|
||||||
// Collada alpha testing
|
Resource::ColladaDescriptionVisitor colladaDescriptionVisitor;
|
||||||
Resource::ColladaAlphaTrickVisitor colladaAlphaTrickVisitor;
|
node->accept(colladaDescriptionVisitor);
|
||||||
node->accept(colladaAlphaTrickVisitor);
|
|
||||||
|
if (colladaDescriptionVisitor.mSkeleton)
|
||||||
|
{
|
||||||
|
if ( osg::Group* group = dynamic_cast<osg::Group*> (node) )
|
||||||
|
{
|
||||||
|
group->removeChildren(0, group->getNumChildren());
|
||||||
|
for (osg::ref_ptr<SceneUtil::RigGeometryHolder> newRiggeometryHolder : colladaDescriptionVisitor.mRigGeometryHolders)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::MatrixTransform> backToOriginTrans = new osg::MatrixTransform();
|
||||||
|
|
||||||
|
newRiggeometryHolder->getOrCreateUserDataContainer()->addUserObject(new TemplateRef(newRiggeometryHolder->getGeometry(0)));
|
||||||
|
backToOriginTrans->getOrCreateUserDataContainer()->addUserObject(new TemplateRef(newRiggeometryHolder->getGeometry(0)));
|
||||||
|
|
||||||
|
newRiggeometryHolder->setBodyPart(true);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
if (newRiggeometryHolder->getGeometry(i)) newRiggeometryHolder->getGeometry(i)->setSkeleton(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
backToOriginTrans->addChild(newRiggeometryHolder);
|
||||||
|
group->addChild(backToOriginTrans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node->getOrCreateStateSet()->addUniform(new osg::Uniform("emissiveMult", 1.f));
|
node->getOrCreateStateSet()->addUniform(new osg::Uniform("emissiveMult", 1.f));
|
||||||
node->getOrCreateStateSet()->addUniform(new osg::Uniform("specStrength", 1.f));
|
node->getOrCreateStateSet()->addUniform(new osg::Uniform("specStrength", 1.f));
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <components/sceneutil/morphgeometry.hpp>
|
#include <components/sceneutil/morphgeometry.hpp>
|
||||||
#include <components/sceneutil/riggeometry.hpp>
|
#include <components/sceneutil/riggeometry.hpp>
|
||||||
|
#include <components/sceneutil/riggeometryosgaextension.hpp>
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
|
@ -41,7 +42,9 @@ namespace SceneUtil
|
||||||
if (const osgParticle::ParticleSystem* partsys = dynamic_cast<const osgParticle::ParticleSystem*>(drawable))
|
if (const osgParticle::ParticleSystem* partsys = dynamic_cast<const osgParticle::ParticleSystem*>(drawable))
|
||||||
return operator()(partsys);
|
return operator()(partsys);
|
||||||
|
|
||||||
if (dynamic_cast<const SceneUtil::RigGeometry*>(drawable) || dynamic_cast<const SceneUtil::MorphGeometry*>(drawable) || dynamic_cast<const osgAnimation::RigGeometry*>(drawable) || dynamic_cast<const osgAnimation::MorphGeometry*>(drawable))
|
if (dynamic_cast<const SceneUtil::RigGeometry*>(drawable) || dynamic_cast<const SceneUtil::MorphGeometry*>(drawable) ||
|
||||||
|
dynamic_cast<const osgAnimation::RigGeometry*>(drawable) || dynamic_cast<const osgAnimation::MorphGeometry*>(drawable) ||
|
||||||
|
dynamic_cast<const SceneUtil::RigGeometryHolder*>(drawable))
|
||||||
{
|
{
|
||||||
return static_cast<osg::Drawable*>(drawable->clone(*this));
|
return static_cast<osg::Drawable*>(drawable->clone(*this));
|
||||||
}
|
}
|
||||||
|
|
281
components/sceneutil/riggeometryosgaextension.cpp
Normal file
281
components/sceneutil/riggeometryosgaextension.cpp
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
#include "riggeometryosgaextension.hpp"
|
||||||
|
|
||||||
|
#include <osgAnimation/RigGeometry>
|
||||||
|
|
||||||
|
#include <osg/Drawable>
|
||||||
|
#include <osg/NodeVisitor>
|
||||||
|
#include <osg/Version>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/resource/scenemanager.hpp>
|
||||||
|
|
||||||
|
namespace SceneUtil
|
||||||
|
{
|
||||||
|
|
||||||
|
OsgaRigGeometry::OsgaRigGeometry() : osgAnimation::RigGeometry()
|
||||||
|
{
|
||||||
|
setDataVariance(osg::Object::STATIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
OsgaRigGeometry::OsgaRigGeometry(const osgAnimation::RigGeometry& copy, const osg::CopyOp& copyop) : osgAnimation::RigGeometry(copy, copyop)
|
||||||
|
{
|
||||||
|
setDataVariance(osg::Object::STATIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
OsgaRigGeometry::OsgaRigGeometry(const OsgaRigGeometry& copy, const osg::CopyOp& copyop) :
|
||||||
|
osgAnimation::RigGeometry(copy, copyop)
|
||||||
|
{
|
||||||
|
setDataVariance(osg::Object::STATIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OsgaRigGeometry::computeMatrixFromRootSkeleton(osg::MatrixList mtxList)
|
||||||
|
{
|
||||||
|
if (!_root.valid())
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Warning " << className() <<"::computeMatrixFromRootSkeleton if you have this message it means you miss to call buildTransformer(Skeleton* root), or your RigGeometry (" << getName() <<") is not attached to a Skeleton subgraph";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osg::Matrix notRoot = _root->getMatrix();
|
||||||
|
_matrixFromSkeletonToGeometry = mtxList[0] * osg::Matrix::inverse(notRoot);
|
||||||
|
_invMatrixFromSkeletonToGeometry = osg::Matrix::inverse(_matrixFromSkeletonToGeometry);
|
||||||
|
_needToComputeMatrix = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RigGeometryHolder::RigGeometryHolder() :
|
||||||
|
mBackToOrigin(nullptr),
|
||||||
|
mLastFrameNumber(0),
|
||||||
|
mIsBodyPart(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RigGeometryHolder::RigGeometryHolder(const RigGeometryHolder& copy, const osg::CopyOp& copyop) :
|
||||||
|
Drawable(copy, copyop),
|
||||||
|
mBackToOrigin(copy.mBackToOrigin),
|
||||||
|
mLastFrameNumber(0),
|
||||||
|
mIsBodyPart(copy.mIsBodyPart)
|
||||||
|
{
|
||||||
|
setUseVertexBufferObjects(true);
|
||||||
|
|
||||||
|
if (!copy.getSourceRigGeometry())
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "copy constructor of RigGeometryHolder partially failed (no source RigGeometry)";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<OsgaRigGeometry> rigGeometry = new OsgaRigGeometry(*copy.getSourceRigGeometry(), copyop);
|
||||||
|
setSourceRigGeometry(rigGeometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
RigGeometryHolder::RigGeometryHolder(const osgAnimation::RigGeometry& copy, const osg::CopyOp& copyop) :
|
||||||
|
mBackToOrigin(nullptr),
|
||||||
|
mLastFrameNumber(0),
|
||||||
|
mIsBodyPart(false)
|
||||||
|
{
|
||||||
|
setUseVertexBufferObjects(true);
|
||||||
|
|
||||||
|
osg::ref_ptr<OsgaRigGeometry> rigGeometry = new OsgaRigGeometry(copy, copyop);
|
||||||
|
setSourceRigGeometry(rigGeometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RigGeometryHolder::setSourceRigGeometry(osg::ref_ptr<OsgaRigGeometry> sourceRigGeometry)
|
||||||
|
{
|
||||||
|
for (unsigned int i=0; i<2; ++i)
|
||||||
|
mGeometry.at(i) = nullptr;
|
||||||
|
|
||||||
|
mSourceRigGeometry = sourceRigGeometry;
|
||||||
|
|
||||||
|
_boundingBox = mSourceRigGeometry->getComputeBoundingBoxCallback()->computeBound(*mSourceRigGeometry);
|
||||||
|
_boundingSphere = osg::BoundingSphere(_boundingBox);
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<2; ++i)
|
||||||
|
{
|
||||||
|
const OsgaRigGeometry& from = *sourceRigGeometry;
|
||||||
|
|
||||||
|
// DO NOT COPY AND PASTE THIS CODE. Cloning osg::Geometry without also cloning its contained Arrays is generally unsafe.
|
||||||
|
// In this specific case the operation is safe under the following two assumptions:
|
||||||
|
// - When Arrays are removed or replaced in the cloned geometry, the original Arrays in their place must outlive the cloned geometry regardless. (ensured by mSourceRigGeometry, possibly also RigGeometry._geometry)
|
||||||
|
// - Arrays that we add or replace in the cloned geometry must be explicitely forbidden from reusing BufferObjects of the original geometry.
|
||||||
|
mGeometry.at(i) = new OsgaRigGeometry(from, osg::CopyOp::SHALLOW_COPY);
|
||||||
|
mGeometry.at(i)->getOrCreateUserDataContainer()->addUserObject(new Resource::TemplateRef(mSourceRigGeometry));
|
||||||
|
|
||||||
|
OsgaRigGeometry& to = *mGeometry.at(i);
|
||||||
|
to.setSupportsDisplayList(false);
|
||||||
|
to.setUseVertexBufferObjects(true);
|
||||||
|
to.setCullingActive(false); // make sure to disable culling since that's handled by this class
|
||||||
|
|
||||||
|
to.setDataVariance(osg::Object::STATIC);
|
||||||
|
to.setNeedToComputeMatrix(true);
|
||||||
|
|
||||||
|
// vertices and normals are modified every frame, so we need to deep copy them.
|
||||||
|
// assign a dedicated VBO to make sure that modifications don't interfere with source geometry's VBO.
|
||||||
|
osg::ref_ptr<osg::VertexBufferObject> vbo (new osg::VertexBufferObject);
|
||||||
|
vbo->setUsage(GL_DYNAMIC_DRAW_ARB);
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Array> vertexArray = static_cast<osg::Array*>(from.getVertexArray()->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||||
|
if (vertexArray)
|
||||||
|
{
|
||||||
|
vertexArray->setVertexBufferObject(vbo);
|
||||||
|
to.setVertexArray(vertexArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const osg::Array* normals = from.getNormalArray())
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Array> normalArray = static_cast<osg::Array*>(normals->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||||
|
if (normalArray)
|
||||||
|
{
|
||||||
|
normalArray->setVertexBufferObject(vbo);
|
||||||
|
to.setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const osg::Vec4Array* tangents = dynamic_cast<const osg::Vec4Array*>(from.getTexCoordArray(7)))
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Array> tangentArray = static_cast<osg::Array*>(tangents->clone(osg::CopyOp::DEEP_COPY_ALL));
|
||||||
|
tangentArray->setVertexBufferObject(vbo);
|
||||||
|
to.setTexCoordArray(7, tangentArray, osg::Array::BIND_PER_VERTEX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<OsgaRigGeometry> RigGeometryHolder::getSourceRigGeometry() const
|
||||||
|
{
|
||||||
|
return mSourceRigGeometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RigGeometryHolder::updateRigGeometry(OsgaRigGeometry* geom, osg::NodeVisitor *nv)
|
||||||
|
{
|
||||||
|
if(!geom)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!geom->getSkeleton() && !this->getParents().empty())
|
||||||
|
{
|
||||||
|
osgAnimation::RigGeometry::FindNearestParentSkeleton finder;
|
||||||
|
if(this->getParents().size() > 1)
|
||||||
|
Log(Debug::Warning) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )";
|
||||||
|
this->getParents()[0]->accept(finder);
|
||||||
|
|
||||||
|
if(!finder._root.valid())
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "A RigGeometry did not find a parent skeleton for RigGeometry ( " << geom->getName() << " )";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
geom->getRigTransformImplementation()->prepareData(*geom);
|
||||||
|
geom->setSkeleton(finder._root.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!geom->getSkeleton())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(geom->getNeedToComputeMatrix())
|
||||||
|
{
|
||||||
|
osgAnimation::Skeleton* root = geom->getSkeleton();
|
||||||
|
if (!root)
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Warning: if you have this message it means you miss to call buildTransformer(Skeleton* root), or your RigGeometry is not attached to a Skeleton subgraph";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
osg::MatrixList mtxList = root->getWorldMatrices(root); //We always assume that RigGeometries have origin at their root
|
||||||
|
geom->computeMatrixFromRootSkeleton(mtxList);
|
||||||
|
|
||||||
|
if (mIsBodyPart && mBackToOrigin) updateBackToOriginTransform(geom);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(geom->getSourceGeometry())
|
||||||
|
{
|
||||||
|
osg::Drawable::UpdateCallback * up = dynamic_cast<osg::Drawable::UpdateCallback*>(geom->getSourceGeometry()->getUpdateCallback());
|
||||||
|
if(up)
|
||||||
|
{
|
||||||
|
up->update(nv, geom->getSourceGeometry());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
geom->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
OsgaRigGeometry* RigGeometryHolder::getGeometry(int geometry)
|
||||||
|
{
|
||||||
|
return mGeometry.at(geometry).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RigGeometryHolder::updateBackToOriginTransform(OsgaRigGeometry* geometry)
|
||||||
|
{
|
||||||
|
osgAnimation::Skeleton* skeleton = geometry->getSkeleton();
|
||||||
|
if (skeleton)
|
||||||
|
{
|
||||||
|
osg::MatrixList mtxList = mBackToOrigin->getParents()[0]->getWorldMatrices(skeleton);
|
||||||
|
osg::Matrix skeletonMatrix = skeleton->getMatrix();
|
||||||
|
osg::Matrixf matrixFromSkeletonToGeometry = mtxList[0] * osg::Matrix::inverse(skeletonMatrix);
|
||||||
|
osg::Matrixf invMatrixFromSkeletonToGeometry = osg::Matrix::inverse(matrixFromSkeletonToGeometry);
|
||||||
|
mBackToOrigin->setMatrix(invMatrixFromSkeletonToGeometry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RigGeometryHolder::accept(osg::NodeVisitor &nv)
|
||||||
|
{
|
||||||
|
if (!nv.validNodeMask(*this))
|
||||||
|
return;
|
||||||
|
|
||||||
|
nv.pushOntoNodePath(this);
|
||||||
|
|
||||||
|
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR && mSourceRigGeometry.get())
|
||||||
|
{
|
||||||
|
unsigned int traversalNumber = nv.getTraversalNumber();
|
||||||
|
if (mLastFrameNumber == traversalNumber)
|
||||||
|
{
|
||||||
|
OsgaRigGeometry& geom = *getRigGeometryPerFrame(mLastFrameNumber);
|
||||||
|
|
||||||
|
nv.pushOntoNodePath(&geom);
|
||||||
|
nv.apply(geom);
|
||||||
|
nv.popFromNodePath();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mLastFrameNumber = traversalNumber;
|
||||||
|
|
||||||
|
OsgaRigGeometry& geom = *getRigGeometryPerFrame(mLastFrameNumber);
|
||||||
|
|
||||||
|
if (mIsBodyPart)
|
||||||
|
{
|
||||||
|
if (mBackToOrigin) updateBackToOriginTransform(&geom);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::MatrixTransform* matrixTransform = dynamic_cast<osg::MatrixTransform*> (this->getParents()[0]);
|
||||||
|
if (matrixTransform)
|
||||||
|
{
|
||||||
|
mBackToOrigin = matrixTransform;
|
||||||
|
updateBackToOriginTransform(&geom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRigGeometry(&geom, &nv);
|
||||||
|
|
||||||
|
nv.pushOntoNodePath(&geom);
|
||||||
|
nv.apply(geom);
|
||||||
|
nv.popFromNodePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nv.apply(*this);
|
||||||
|
|
||||||
|
nv.popFromNodePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RigGeometryHolder::accept(osg::PrimitiveFunctor& func) const
|
||||||
|
{
|
||||||
|
getRigGeometryPerFrame(mLastFrameNumber)->accept(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
OsgaRigGeometry* RigGeometryHolder::getRigGeometryPerFrame(unsigned int frame) const
|
||||||
|
{
|
||||||
|
return mGeometry.at(frame%2).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
72
components/sceneutil/riggeometryosgaextension.hpp
Normal file
72
components/sceneutil/riggeometryosgaextension.hpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_OSGAEXTENSION_RIGGEOMETRY_H
|
||||||
|
#define OPENMW_COMPONENTS_OSGAEXTENSION_RIGGEOMETRY_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include <osg/Drawable>
|
||||||
|
#include <osgAnimation/RigGeometry>
|
||||||
|
|
||||||
|
#include <osg/NodeVisitor>
|
||||||
|
|
||||||
|
namespace SceneUtil
|
||||||
|
{
|
||||||
|
/// @brief Custom RigGeometry-class for osgAnimation-formats (collada)
|
||||||
|
class OsgaRigGeometry : public osgAnimation::RigGeometry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
OsgaRigGeometry();
|
||||||
|
|
||||||
|
OsgaRigGeometry(const osgAnimation::RigGeometry& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
|
OsgaRigGeometry(const OsgaRigGeometry& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
|
META_Object(SceneUtil, OsgaRigGeometry);
|
||||||
|
|
||||||
|
void computeMatrixFromRootSkeleton(osg::MatrixList mtxList);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief OpenMW-compatible double buffered static datavariance version of osgAnimation::RigGeometry
|
||||||
|
/// This class is based on osgAnimation::RigGeometry and SceneUtil::RigGeometry
|
||||||
|
class RigGeometryHolder : public osg::Drawable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RigGeometryHolder();
|
||||||
|
|
||||||
|
RigGeometryHolder(const RigGeometryHolder& copy, const osg::CopyOp& copyop);
|
||||||
|
|
||||||
|
RigGeometryHolder(const osgAnimation::RigGeometry& copy, const osg::CopyOp& copyop);
|
||||||
|
|
||||||
|
META_Object(SceneUtil, RigGeometryHolder);
|
||||||
|
|
||||||
|
void setSourceRigGeometry(osg::ref_ptr<OsgaRigGeometry> sourceRigGeometry);
|
||||||
|
osg::ref_ptr<OsgaRigGeometry> getSourceRigGeometry() const;
|
||||||
|
|
||||||
|
/// @brief Modified rig update, code based on osgAnimation::UpdateRigGeometry : public osg::Drawable::UpdateCallback
|
||||||
|
void updateRigGeometry(OsgaRigGeometry* geom, osg::NodeVisitor *nv);
|
||||||
|
|
||||||
|
OsgaRigGeometry* getGeometry(int geometry);
|
||||||
|
|
||||||
|
void accept(osg::NodeVisitor &nv) override;
|
||||||
|
void accept(osg::PrimitiveFunctor&) const override;
|
||||||
|
bool supports(const osg::PrimitiveFunctor&) const override{ return true; }
|
||||||
|
|
||||||
|
void setBackToOrigin(osg::MatrixTransform* backToOrigin) {mBackToOrigin = backToOrigin;}
|
||||||
|
void setBodyPart(bool isBodyPart) {mIsBodyPart = isBodyPart;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<osg::ref_ptr<OsgaRigGeometry>, 2> mGeometry;
|
||||||
|
osg::ref_ptr<OsgaRigGeometry> mSourceRigGeometry;
|
||||||
|
osg::MatrixTransform* mBackToOrigin; //This is used to move riggeometries from their slot locations to skeleton origin in order to get correct deformations for bodyparts
|
||||||
|
|
||||||
|
unsigned int mLastFrameNumber;
|
||||||
|
bool mIsBodyPart;
|
||||||
|
|
||||||
|
void updateBackToOriginTransform(OsgaRigGeometry* geometry);
|
||||||
|
|
||||||
|
OsgaRigGeometry* getRigGeometryPerFrame(unsigned int frame) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -8,6 +8,7 @@
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
#include <components/sceneutil/skeleton.hpp>
|
#include <components/sceneutil/skeleton.hpp>
|
||||||
#include <components/sceneutil/riggeometry.hpp>
|
#include <components/sceneutil/riggeometry.hpp>
|
||||||
|
#include <components/sceneutil/riggeometryosgaextension.hpp>
|
||||||
#include <components/sceneutil/morphgeometry.hpp>
|
#include <components/sceneutil/morphgeometry.hpp>
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
|
@ -49,6 +50,24 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RigGeometryHolderSerializer : public osgDB::ObjectWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RigGeometryHolderSerializer()
|
||||||
|
: osgDB::ObjectWrapper(createInstanceFunc<SceneUtil::RigGeometryHolder>, "SceneUtil::RigGeometryHolder", "osg::Object osg::Node osg::Drawable SceneUtil::RigGeometryHolder")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OsgaRigGeometrySerializer : public osgDB::ObjectWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OsgaRigGeometrySerializer()
|
||||||
|
: osgDB::ObjectWrapper(createInstanceFunc<SceneUtil::OsgaRigGeometry>, "SceneUtil::OsgaRigGeometry", "osg::Object osg::Node osg::Geometry osgAnimation::RigGeometry SceneUtil::OsgaRigGeometry")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class MorphGeometrySerializer : public osgDB::ObjectWrapper
|
class MorphGeometrySerializer : public osgDB::ObjectWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -108,6 +127,8 @@ void registerSerializers()
|
||||||
mgr->addWrapper(new PositionAttitudeTransformSerializer);
|
mgr->addWrapper(new PositionAttitudeTransformSerializer);
|
||||||
mgr->addWrapper(new SkeletonSerializer);
|
mgr->addWrapper(new SkeletonSerializer);
|
||||||
mgr->addWrapper(new RigGeometrySerializer);
|
mgr->addWrapper(new RigGeometrySerializer);
|
||||||
|
mgr->addWrapper(new RigGeometryHolderSerializer);
|
||||||
|
mgr->addWrapper(new OsgaRigGeometrySerializer);
|
||||||
mgr->addWrapper(new MorphGeometrySerializer);
|
mgr->addWrapper(new MorphGeometrySerializer);
|
||||||
mgr->addWrapper(new LightManagerSerializer);
|
mgr->addWrapper(new LightManagerSerializer);
|
||||||
mgr->addWrapper(new CameraRelativeTransformSerializer);
|
mgr->addWrapper(new CameraRelativeTransformSerializer);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <components/sceneutil/riggeometry.hpp>
|
#include <components/sceneutil/riggeometry.hpp>
|
||||||
#include <components/sceneutil/morphgeometry.hpp>
|
#include <components/sceneutil/morphgeometry.hpp>
|
||||||
#include <components/sceneutil/depth.hpp>
|
#include <components/sceneutil/depth.hpp>
|
||||||
|
#include <components/sceneutil/riggeometryosgaextension.hpp>
|
||||||
|
|
||||||
#include "removedalphafunc.hpp"
|
#include "removedalphafunc.hpp"
|
||||||
#include "shadermanager.hpp"
|
#include "shadermanager.hpp"
|
||||||
|
@ -922,6 +923,17 @@ namespace Shader
|
||||||
if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs))
|
if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs))
|
||||||
morph->setSourceGeometry(sourceGeometry);
|
morph->setSourceGeometry(sourceGeometry);
|
||||||
}
|
}
|
||||||
|
else if (auto osgaRig = dynamic_cast<SceneUtil::RigGeometryHolder*>(&drawable))
|
||||||
|
{
|
||||||
|
osg::ref_ptr<SceneUtil::OsgaRigGeometry> sourceOsgaRigGeometry = osgaRig->getSourceRigGeometry();
|
||||||
|
osg::ref_ptr<osg::Geometry> sourceGeometry = sourceOsgaRigGeometry->getSourceGeometry();
|
||||||
|
if (sourceGeometry && adjustGeometry(*sourceGeometry, reqs))
|
||||||
|
{
|
||||||
|
sourceOsgaRigGeometry->setSourceGeometry(sourceGeometry);
|
||||||
|
osgaRig->setSourceRigGeometry(sourceOsgaRigGeometry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ensureFFP(drawable);
|
ensureFFP(drawable);
|
||||||
|
|
Loading…
Reference in a new issue