mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-19 13:11:32 +00:00
Nth revision of NifLoader geometry handling
Handle BSSegmentedTriShape
This commit is contained in:
parent
8fb900da85
commit
af24d3fd3c
2 changed files with 146 additions and 130 deletions
|
@ -32,6 +32,32 @@ namespace
|
||||||
return letterPos < path.size() && (path[letterPos] == 'x' || path[letterPos] == 'X');
|
return letterPos < path.size() && (path[letterPos] == 'x' || path[letterPos] == 'X');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isTypeNiGeometry(int type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Nif::RC_NiTriShape:
|
||||||
|
case Nif::RC_NiTriStrips:
|
||||||
|
case Nif::RC_BSLODTriShape:
|
||||||
|
case Nif::RC_BSSegmentedTriShape:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTypeTriShape(int type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Nif::RC_NiTriShape:
|
||||||
|
case Nif::RC_BSLODTriShape:
|
||||||
|
case Nif::RC_BSSegmentedTriShape:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void prepareTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriBasedGeomData& data)
|
void prepareTriangleMesh(btTriangleMesh& mesh, const Nif::NiTriBasedGeomData& data)
|
||||||
{
|
{
|
||||||
// FIXME: copying vertices/indices individually is unreasonable
|
// FIXME: copying vertices/indices individually is unreasonable
|
||||||
|
@ -81,7 +107,7 @@ namespace
|
||||||
auto handleNiGeometry(const Nif::NiGeometry& geometry, Function&& function)
|
auto handleNiGeometry(const Nif::NiGeometry& geometry, Function&& function)
|
||||||
-> decltype(function(static_cast<const Nif::NiTriShapeData&>(geometry.mData.get())))
|
-> decltype(function(static_cast<const Nif::NiTriShapeData&>(geometry.mData.get())))
|
||||||
{
|
{
|
||||||
if (geometry.recType == Nif::RC_NiTriShape || geometry.recType == Nif::RC_BSLODTriShape)
|
if (isTypeTriShape(geometry.recType))
|
||||||
{
|
{
|
||||||
auto data = static_cast<const Nif::NiTriShapeData*>(geometry.mData.getPtr());
|
auto data = static_cast<const Nif::NiTriShapeData*>(geometry.mData.getPtr());
|
||||||
if (data->mTriangles.empty())
|
if (data->mTriangles.empty())
|
||||||
|
@ -329,13 +355,9 @@ namespace NifBullet
|
||||||
// NOTE: a trishape with bounds, but no BBoxCollision flag should NOT go through handleNiTriShape!
|
// NOTE: a trishape with bounds, but no BBoxCollision flag should NOT go through handleNiTriShape!
|
||||||
// It must be ignored completely.
|
// It must be ignored completely.
|
||||||
// (occurs in tr_ex_imp_wall_arch_04.nif)
|
// (occurs in tr_ex_imp_wall_arch_04.nif)
|
||||||
if (node.mBounds.mType == Nif::BoundingVolume::Type::BASE_BV
|
if (node.mBounds.mType == Nif::BoundingVolume::Type::BASE_BV && isTypeNiGeometry(node.recType))
|
||||||
&& (node.recType == Nif::RC_NiTriShape || node.recType == Nif::RC_NiTriStrips
|
|
||||||
|| node.recType == Nif::RC_BSLODTriShape))
|
|
||||||
{
|
|
||||||
handleNiTriShape(static_cast<const Nif::NiGeometry&>(node), parent, args);
|
handleNiTriShape(static_cast<const Nif::NiGeometry&>(node), parent, args);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// For NiNodes, loop through children
|
// For NiNodes, loop through children
|
||||||
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(&node))
|
if (const Nif::NiNode* ninode = dynamic_cast<const Nif::NiNode*>(&node))
|
||||||
|
|
|
@ -88,7 +88,7 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isTypeGeometry(int type)
|
bool isTypeNiGeometry(int type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -96,6 +96,19 @@ namespace
|
||||||
case Nif::RC_NiTriStrips:
|
case Nif::RC_NiTriStrips:
|
||||||
case Nif::RC_NiLines:
|
case Nif::RC_NiLines:
|
||||||
case Nif::RC_BSLODTriShape:
|
case Nif::RC_BSLODTriShape:
|
||||||
|
case Nif::RC_BSSegmentedTriShape:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTypeBSGeometry(int type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Nif::RC_BSTriShape:
|
||||||
|
case Nif::RC_BSDynamicTriShape:
|
||||||
|
case Nif::RC_BSMeshLODTriShape:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -125,15 +138,6 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto geometry = dynamic_cast<const Nif::NiGeometry*>(nifNode);
|
|
||||||
if (geometry)
|
|
||||||
{
|
|
||||||
if (!geometry->mShaderProperty.empty())
|
|
||||||
out.emplace_back(geometry->mShaderProperty.getPtr());
|
|
||||||
if (!geometry->mAlphaProperty.empty())
|
|
||||||
out.emplace_back(geometry->mAlphaProperty.getPtr());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeCallback used to have a node always oriented towards the camera. The node can have translation and scale
|
// NodeCallback used to have a node always oriented towards the camera. The node can have translation and scale
|
||||||
|
@ -443,11 +447,16 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto geometry = dynamic_cast<const Nif::NiGeometry*>(nifNode);
|
// NiAlphaProperty is handled as a drawable property
|
||||||
// NiGeometry's NiAlphaProperty doesn't get handled here because it's a drawable property
|
Nif::BSShaderPropertyPtr shaderprop = nullptr;
|
||||||
if (geometry && !geometry->mShaderProperty.empty())
|
if (isTypeNiGeometry(nifNode->recType))
|
||||||
handleProperty(geometry->mShaderProperty.getPtr(), applyTo, composite, imageManager, boundTextures,
|
shaderprop = static_cast<const Nif::NiGeometry*>(nifNode)->mShaderProperty;
|
||||||
animflags, hasStencilProperty);
|
else if (isTypeBSGeometry(nifNode->recType))
|
||||||
|
shaderprop = static_cast<const Nif::BSTriShape*>(nifNode)->mShaderProperty;
|
||||||
|
|
||||||
|
if (!shaderprop.empty())
|
||||||
|
handleProperty(shaderprop.getPtr(), applyTo, composite, imageManager, boundTextures, animflags,
|
||||||
|
hasStencilProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setupController(const Nif::NiTimeController* ctrl, SceneUtil::Controller* toSetup, int animflags)
|
static void setupController(const Nif::NiTimeController* ctrl, SceneUtil::Controller* toSetup, int animflags)
|
||||||
|
@ -747,7 +756,9 @@ namespace NifOsg
|
||||||
|
|
||||||
applyNodeProperties(nifNode, node, composite, args.mImageManager, args.mBoundTextures, args.mAnimFlags);
|
applyNodeProperties(nifNode, node, composite, args.mImageManager, args.mBoundTextures, args.mAnimFlags);
|
||||||
|
|
||||||
const bool isGeometry = isTypeGeometry(nifNode->recType);
|
const bool isNiGeometry = isTypeNiGeometry(nifNode->recType);
|
||||||
|
const bool isBSGeometry = isTypeBSGeometry(nifNode->recType);
|
||||||
|
const bool isGeometry = isNiGeometry || isBSGeometry;
|
||||||
|
|
||||||
if (isGeometry && !args.mSkipMeshes)
|
if (isGeometry && !args.mSkipMeshes)
|
||||||
{
|
{
|
||||||
|
@ -762,12 +773,8 @@ namespace NifOsg
|
||||||
skip = args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->mName, "EditorMarker");
|
skip = args.mHasMarkers && Misc::StringUtils::ciStartsWith(nifNode->mName, "EditorMarker");
|
||||||
if (!skip)
|
if (!skip)
|
||||||
{
|
{
|
||||||
Nif::NiSkinInstancePtr skin = static_cast<const Nif::NiGeometry*>(nifNode)->mSkin;
|
if (isNiGeometry)
|
||||||
|
handleNiGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||||
if (skin.empty())
|
|
||||||
handleGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
|
|
||||||
else
|
|
||||||
handleSkinnedGeometry(nifNode, parent, node, composite, args.mBoundTextures, args.mAnimFlags);
|
|
||||||
|
|
||||||
if (!nifNode->mController.empty())
|
if (!nifNode->mController.empty())
|
||||||
handleMeshControllers(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
|
handleMeshControllers(nifNode, node, composite, args.mBoundTextures, args.mAnimFlags);
|
||||||
|
@ -1342,41 +1349,7 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNiGeometryData(osg::Geometry* geometry, const Nif::NiGeometryData* data,
|
void handleNiGeometryData(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Geometry* geometry,
|
||||||
const std::vector<unsigned int>& boundTextures, const std::string& name)
|
|
||||||
{
|
|
||||||
const auto& vertices = data->mVertices;
|
|
||||||
const auto& normals = data->mNormals;
|
|
||||||
const auto& colors = data->mColors;
|
|
||||||
if (!vertices.empty())
|
|
||||||
geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data()));
|
|
||||||
if (!normals.empty())
|
|
||||||
geometry->setNormalArray(
|
|
||||||
new osg::Vec3Array(normals.size(), normals.data()), osg::Array::BIND_PER_VERTEX);
|
|
||||||
if (!colors.empty())
|
|
||||||
geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX);
|
|
||||||
|
|
||||||
const auto& uvlist = data->mUVList;
|
|
||||||
int textureStage = 0;
|
|
||||||
for (std::vector<unsigned int>::const_iterator it = boundTextures.begin(); it != boundTextures.end();
|
|
||||||
++it, ++textureStage)
|
|
||||||
{
|
|
||||||
unsigned int uvSet = *it;
|
|
||||||
if (uvSet >= uvlist.size())
|
|
||||||
{
|
|
||||||
Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in "
|
|
||||||
<< mFilename;
|
|
||||||
if (uvlist.empty())
|
|
||||||
continue;
|
|
||||||
uvSet = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[uvSet].size(), uvlist[uvSet].data()),
|
|
||||||
osg::Array::BIND_PER_VERTEX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleNiGeometry(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Geometry* geometry,
|
|
||||||
osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite,
|
osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite,
|
||||||
const std::vector<unsigned int>& boundTextures, int animflags)
|
const std::vector<unsigned int>& boundTextures, int animflags)
|
||||||
{
|
{
|
||||||
|
@ -1458,7 +1431,36 @@ namespace NifOsg
|
||||||
new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, line.size(), line.data()));
|
new osg::DrawElementsUShort(osg::PrimitiveSet::LINES, line.size(), line.data()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleNiGeometryData(geometry, niGeometryData, boundTextures, nifNode->mName);
|
|
||||||
|
const auto& vertices = niGeometryData->mVertices;
|
||||||
|
const auto& normals = niGeometryData->mNormals;
|
||||||
|
const auto& colors = niGeometryData->mColors;
|
||||||
|
if (!vertices.empty())
|
||||||
|
geometry->setVertexArray(new osg::Vec3Array(vertices.size(), vertices.data()));
|
||||||
|
if (!normals.empty())
|
||||||
|
geometry->setNormalArray(
|
||||||
|
new osg::Vec3Array(normals.size(), normals.data()), osg::Array::BIND_PER_VERTEX);
|
||||||
|
if (!colors.empty())
|
||||||
|
geometry->setColorArray(new osg::Vec4Array(colors.size(), colors.data()), osg::Array::BIND_PER_VERTEX);
|
||||||
|
|
||||||
|
const auto& uvlist = niGeometryData->mUVList;
|
||||||
|
int textureStage = 0;
|
||||||
|
for (std::vector<unsigned int>::const_iterator it = boundTextures.begin(); it != boundTextures.end();
|
||||||
|
++it, ++textureStage)
|
||||||
|
{
|
||||||
|
unsigned int uvSet = *it;
|
||||||
|
if (uvSet >= uvlist.size())
|
||||||
|
{
|
||||||
|
Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << nifNode->mName
|
||||||
|
<< "\" in " << mFilename;
|
||||||
|
if (uvlist.empty())
|
||||||
|
continue;
|
||||||
|
uvSet = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry->setTexCoordArray(textureStage, new osg::Vec2Array(uvlist[uvSet].size(), uvlist[uvSet].data()),
|
||||||
|
osg::Array::BIND_PER_VERTEX);
|
||||||
|
}
|
||||||
|
|
||||||
// osg::Material properties are handled here for two reasons:
|
// osg::Material properties are handled here for two reasons:
|
||||||
// - if there are no vertex colors, we need to disable colorMode.
|
// - if there are no vertex colors, we need to disable colorMode.
|
||||||
|
@ -1466,82 +1468,37 @@ namespace NifOsg
|
||||||
// above the actual renderable would be tedious.
|
// above the actual renderable would be tedious.
|
||||||
std::vector<const Nif::NiProperty*> drawableProps;
|
std::vector<const Nif::NiProperty*> drawableProps;
|
||||||
collectDrawableProperties(nifNode, parent, drawableProps);
|
collectDrawableProperties(nifNode, parent, drawableProps);
|
||||||
|
if (!niGeometry->mShaderProperty.empty())
|
||||||
|
drawableProps.emplace_back(niGeometry->mShaderProperty.getPtr());
|
||||||
|
if (!niGeometry->mAlphaProperty.empty())
|
||||||
|
drawableProps.emplace_back(niGeometry->mAlphaProperty.getPtr());
|
||||||
applyDrawableProperties(parentNode, drawableProps, composite, !niGeometryData->mColors.empty(), animflags);
|
applyDrawableProperties(parentNode, drawableProps, composite, !niGeometryData->mColors.empty(), animflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleGeometry(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
|
void handleNiGeometry(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
|
||||||
SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures,
|
SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures,
|
||||||
int animflags)
|
int animflags)
|
||||||
{
|
{
|
||||||
assert(isTypeGeometry(nifNode->recType));
|
assert(isTypeNiGeometry(nifNode->recType));
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geometry> geom(new osg::Geometry);
|
osg::ref_ptr<osg::Geometry> geom(new osg::Geometry);
|
||||||
handleNiGeometry(nifNode, parent, geom, parentNode, composite, boundTextures, animflags);
|
handleNiGeometryData(nifNode, parent, geom, parentNode, composite, boundTextures, animflags);
|
||||||
// If the record had no valid geometry data in it, early-out
|
// If the record had no valid geometry data in it, early-out
|
||||||
if (geom->empty())
|
if (geom->empty())
|
||||||
return;
|
return;
|
||||||
osg::ref_ptr<osg::Drawable> drawable;
|
|
||||||
for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext)
|
osg::ref_ptr<osg::Drawable> drawable = geom;
|
||||||
|
|
||||||
|
auto niGeometry = static_cast<const Nif::NiGeometry*>(nifNode);
|
||||||
|
if (!niGeometry->mSkin.empty())
|
||||||
{
|
{
|
||||||
if (!ctrl->isActive())
|
|
||||||
continue;
|
|
||||||
if (ctrl->recType == Nif::RC_NiGeomMorpherController)
|
|
||||||
{
|
|
||||||
const Nif::NiGeomMorpherController* nimorphctrl
|
|
||||||
= static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr());
|
|
||||||
if (nimorphctrl->mData.empty())
|
|
||||||
continue;
|
|
||||||
drawable = handleMorphGeometry(nimorphctrl, geom, parentNode, composite, boundTextures, animflags);
|
|
||||||
|
|
||||||
osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController(nimorphctrl);
|
|
||||||
setupController(ctrl.getPtr(), morphctrl, animflags);
|
|
||||||
drawable->setUpdateCallback(morphctrl);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!drawable.get())
|
|
||||||
drawable = geom;
|
|
||||||
drawable->setName(nifNode->mName);
|
|
||||||
parentNode->addChild(drawable);
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Drawable> handleMorphGeometry(const Nif::NiGeomMorpherController* morpher,
|
|
||||||
osg::ref_ptr<osg::Geometry> sourceGeometry, osg::Node* parentNode,
|
|
||||||
SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures,
|
|
||||||
int animflags)
|
|
||||||
{
|
|
||||||
osg::ref_ptr<SceneUtil::MorphGeometry> morphGeom = new SceneUtil::MorphGeometry;
|
|
||||||
morphGeom->setSourceGeometry(sourceGeometry);
|
|
||||||
|
|
||||||
const std::vector<Nif::NiMorphData::MorphData>& morphs = morpher->mData.getPtr()->mMorphs;
|
|
||||||
if (morphs.empty())
|
|
||||||
return morphGeom;
|
|
||||||
if (morphs[0].mVertices.size()
|
|
||||||
!= static_cast<const osg::Vec3Array*>(sourceGeometry->getVertexArray())->size())
|
|
||||||
return morphGeom;
|
|
||||||
for (unsigned int i = 0; i < morphs.size(); ++i)
|
|
||||||
morphGeom->addMorphTarget(
|
|
||||||
new osg::Vec3Array(morphs[i].mVertices.size(), morphs[i].mVertices.data()), 0.f);
|
|
||||||
|
|
||||||
return morphGeom;
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleSkinnedGeometry(const Nif::NiAVObject* nifNode, const Nif::Parent* parent, osg::Group* parentNode,
|
|
||||||
SceneUtil::CompositeStateSetUpdater* composite, const std::vector<unsigned int>& boundTextures,
|
|
||||||
int animflags)
|
|
||||||
{
|
|
||||||
assert(isTypeGeometry(nifNode->recType));
|
|
||||||
osg::ref_ptr<osg::Geometry> geometry(new osg::Geometry);
|
|
||||||
handleNiGeometry(nifNode, parent, geometry, parentNode, composite, boundTextures, animflags);
|
|
||||||
if (geometry->empty())
|
|
||||||
return;
|
|
||||||
osg::ref_ptr<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry);
|
osg::ref_ptr<SceneUtil::RigGeometry> rig(new SceneUtil::RigGeometry);
|
||||||
rig->setSourceGeometry(geometry);
|
rig->setSourceGeometry(geom);
|
||||||
rig->setName(nifNode->mName);
|
|
||||||
|
|
||||||
// Assign bone weights
|
// Assign bone weights
|
||||||
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map(new SceneUtil::RigGeometry::InfluenceMap);
|
osg::ref_ptr<SceneUtil::RigGeometry::InfluenceMap> map(new SceneUtil::RigGeometry::InfluenceMap);
|
||||||
|
|
||||||
const Nif::NiSkinInstance* skin = static_cast<const Nif::NiGeometry*>(nifNode)->mSkin.getPtr();
|
const Nif::NiSkinInstance* skin = niGeometry->mSkin.getPtr();
|
||||||
const Nif::NiSkinData* data = skin->mData.getPtr();
|
const Nif::NiSkinData* data = skin->mData.getPtr();
|
||||||
const Nif::NiAVObjectList& bones = skin->mBones;
|
const Nif::NiAVObjectList& bones = skin->mBones;
|
||||||
for (std::size_t i = 0; i < bones.size(); ++i)
|
for (std::size_t i = 0; i < bones.size(); ++i)
|
||||||
|
@ -1557,7 +1514,44 @@ namespace NifOsg
|
||||||
}
|
}
|
||||||
rig->setInfluenceMap(map);
|
rig->setInfluenceMap(map);
|
||||||
|
|
||||||
parentNode->addChild(rig);
|
drawable = rig;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Nif::NiTimeControllerPtr ctrl = nifNode->mController; !ctrl.empty(); ctrl = ctrl->mNext)
|
||||||
|
{
|
||||||
|
if (!ctrl->isActive())
|
||||||
|
continue;
|
||||||
|
if (ctrl->recType == Nif::RC_NiGeomMorpherController)
|
||||||
|
{
|
||||||
|
if (!niGeometry->mSkin.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto nimorphctrl = static_cast<const Nif::NiGeomMorpherController*>(ctrl.getPtr());
|
||||||
|
if (nimorphctrl->mData.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::vector<Nif::NiMorphData::MorphData>& morphs = nimorphctrl->mData.getPtr()->mMorphs;
|
||||||
|
if (morphs.empty() || morphs[0].mVertices.size()
|
||||||
|
!= static_cast<const osg::Vec3Array*>(geom->getVertexArray())->size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
osg::ref_ptr<SceneUtil::MorphGeometry> morphGeom = new SceneUtil::MorphGeometry;
|
||||||
|
morphGeom->setSourceGeometry(geom);
|
||||||
|
for (unsigned int i = 0; i < morphs.size(); ++i)
|
||||||
|
morphGeom->addMorphTarget(
|
||||||
|
new osg::Vec3Array(morphs[i].mVertices.size(), morphs[i].mVertices.data()), 0.f);
|
||||||
|
|
||||||
|
osg::ref_ptr<GeomMorpherController> morphctrl = new GeomMorpherController(nimorphctrl);
|
||||||
|
setupController(ctrl.getPtr(), morphctrl, animflags);
|
||||||
|
morphGeom->setUpdateCallback(morphctrl);
|
||||||
|
|
||||||
|
drawable = morphGeom;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawable->setName(nifNode->mName);
|
||||||
|
parentNode->addChild(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::BlendFunc::BlendFuncMode getBlendMode(int mode)
|
osg::BlendFunc::BlendFuncMode getBlendMode(int mode)
|
||||||
|
|
Loading…
Reference in a new issue