diff --git a/NifImport/MaxNifImport.cpp b/NifImport/MaxNifImport.cpp index 5486090765e32ab8c95894984052e3ff5fbd9891..503f24a1a5bb6c7b31e893991ea53f8cef753268 100644 --- a/NifImport/MaxNifImport.cpp +++ b/NifImport/MaxNifImport.cpp @@ -107,6 +107,11 @@ public: bool hasSkeleton; bool isBiped; bool removeUnusedImportedBones; + bool forceRotation; + + float minBoneWidth; + float maxBoneWidth; + float boneWidthToLengthRatio; vector<NiObjectRef> blocks; vector<NiNodeRef> nodes; @@ -169,6 +174,8 @@ public: bool ImportSkin(ImpNode *node, NiTriBasedGeomRef triGeom); Texmap* CreateTexture(TexDesc& desc); + + INode *CreateBone(const string& name, Point3 startPos, Point3 endPos, Point3 zAxis); }; @@ -475,6 +482,11 @@ void NifImporter::LoadIniSettings() bipedAnkleAttach = GetIniValue<float>(BipedImportSection, "BipedAnkleAttach", 0.2f); bipedTrianglePelvis = GetIniValue<bool>(BipedImportSection, "BipedTrianglePelvis", false); removeUnusedImportedBones = GetIniValue<bool>(BipedImportSection, "RemoveUnusedImportedBones", false); + forceRotation = GetIniValue<bool>(BipedImportSection, "ForceRotation", false); + + minBoneWidth = GetIniValue<float>(BipedImportSection, "MinBoneWidth", 0.5f); + maxBoneWidth = GetIniValue<float>(BipedImportSection, "MaxBoneWidth", 3.0f); + boneWidthToLengthRatio = GetIniValue<float>(BipedImportSection, "BoneWidthToLengthRatio", 0.25f); importSkeleton = hasSkeleton = HasSkeleton(); isBiped = IsBiped(); @@ -738,7 +750,7 @@ void NifImporter::ScaleBiped(IBipMaster* master, NiNodeRef block, bool Recurse) } -INode *CreateBone(const string& name, Point3 startPos, Point3 endPos, Point3 zAxis) +INode *NifImporter::CreateBone(const string& name, Point3 startPos, Point3 endPos, Point3 zAxis) { if (FPInterface * fpBones = GetCOREInterface(Interface_ID(0x438aff72, 0xef9675ac))) { @@ -751,12 +763,8 @@ INode *CreateBone(const string& name, Point3 startPos, Point3 endPos, Point3 zAx if (INode *n = result.n) { n->SetName(const_cast<TCHAR*>(name.c_str())); - - const float wmin = 0.5f; - const float wmax = 3.0f; float len = fabs(Length(startPos)-Length(endPos)); - float width = max(wmin, min(wmax, len / 4.0f)); - + float width = max(minBoneWidth, min(maxBoneWidth, len * boneWidthToLengthRatio)); if (Object* o = n->GetObjectRef()) { setMAXScriptValue(o->GetReference(0), "width", 0, width); @@ -784,6 +792,7 @@ void NifImporter::ImportBones(NiNodeRef node) vector<NiNodeRef> children = DynamicCast<NiNode>(node->GetChildren()); NiNodeRef parent = node->GetParent(); + PosRotScale prs = prsDefault; Matrix3 im = TOMATRIX3(node->GetWorldTransform(), true); Point3 p = im.GetTrans(); Quat q(im); @@ -795,13 +804,14 @@ void NifImporter::ImportBones(NiNodeRef node) INode *pinode = bone->GetParentNode(); if (pinode) bone->Detach(0,1); - PositionAndRotateNode(bone, p, q); + PositionAndRotateNode(bone, p, q, prs); if (pinode) pinode->AttachChild(bone, 1); } else { Vector3 ppos; + Point3 zAxis(0,1,0); if (!children.empty()) { for (vector<NiNodeRef>::iterator itr=children.begin(), end = children.end(); itr != end; ++itr) { Matrix44 cwt = (*itr)->GetWorldTransform(); @@ -816,12 +826,18 @@ void NifImporter::ImportBones(NiNodeRef node) Matrix44 pwt = parent->GetWorldTransform(); Matrix33 prot; float pscale; pwt.Decompose(ppos, prot, pscale); + if (forceRotation) + prs = prsPos; + } + else + { + if (forceRotation) + prs = prsPos; } Point3 pp(ppos.x, ppos.y, ppos.z); - Point3 zAxis(0,1,0); if (bone = CreateBone(name, p, pp, zAxis)) { - PositionAndRotateNode(bone, p, q); + PositionAndRotateNode(bone, p, q, prs); if (parent) { if (INode *pn = gi->GetINodeByName(parent->GetName().c_str())) diff --git a/NifImport/MaxNifTools.ini b/NifImport/MaxNifTools.ini index f45238053250f6765da915d2ddb91f5282403f5f..fb8ea1b472061a89b3f4bc039640a4942543cc4a 100644 --- a/NifImport/MaxNifTools.ini +++ b/NifImport/MaxNifTools.ini @@ -44,6 +44,12 @@ BipedAnkleAttach=0.2 BipedTrianglePelvis=0 ; Remove unused bones from the biped on import of a mesh. Default: 1 RemoveUnusedImportedBones=1 +; Minimum Bone Width / Maximum Bone Width / Ratio of Width to Length +MinBoneWidth=0.5 +MaxBoneWidth=3 +BoneWidthToLengthRatio=0.25 +; Force nub to point back to parent at expense of loss of rotation. Default: 1 +ForceRotation=1 ;; [Applications] diff --git a/NifImport/niutils.cpp b/NifImport/niutils.cpp index f730127e44d7b23b98b68ce05a07800059866288..1a494b12c77d03aa4fb4a35abb70de2a63eb52ec 100644 --- a/NifImport/niutils.cpp +++ b/NifImport/niutils.cpp @@ -356,7 +356,7 @@ Modifier *GetSkin(INode *node) // Set Position and Rotation on a standard controller will need to handle bipeds // Always in World Transform coordinates -void PositionAndRotateNode(INode *n, Point3 p, Quat& q, TimeValue t) +void PositionAndRotateNode(INode *n, Point3 p, Quat& q, PosRotScale prs, TimeValue t) { if (Control *c = n->GetTMController()) { @@ -368,15 +368,19 @@ void PositionAndRotateNode(INode *n, Point3 p, Quat& q, TimeValue t) // Get the Biped Export Interface from the controller //IBipedExport *BipIface = (IBipedExport *) c->GetInterface(I_BIPINTERFACE); IOurBipExport *BipIface = (IOurBipExport *) c->GetInterface(I_OURINTERFACE); - BipIface->SetBipedRotation(q, t, n, 0/*???*/); - BipIface->SetBipedPosition(p, t, n); + if (prs & prsRot) + BipIface->SetBipedRotation(q, t, n, 0/*???*/); + if (prs & prsPos) + BipIface->SetBipedPosition(p, t, n); } else { - if (Control *rotCtrl = c->GetRotationController()) - rotCtrl->SetValue(t, &q, 1, CTRL_ABSOLUTE); - if (Control *posCtrl = c->GetPositionController()) - posCtrl->SetValue(t, &p, 1, CTRL_ABSOLUTE); + if (prs & prsRot) + if (Control *rotCtrl = c->GetRotationController()) + rotCtrl->SetValue(t, &q, 1, CTRL_ABSOLUTE); + if (prs & prsPos) + if (Control *posCtrl = c->GetPositionController()) + posCtrl->SetValue(t, &p, 1, CTRL_ABSOLUTE); } } } diff --git a/NifImport/niutils.h b/NifImport/niutils.h index 2408100e7f5b6af7d06891496592076282060c00..6e2f12bda5c59f560fdf1ee0b82e0caaf6532626 100644 --- a/NifImport/niutils.h +++ b/NifImport/niutils.h @@ -194,7 +194,15 @@ extern void FindImages(NameValueCollection& images, const string& rootPath, cons extern void RenameNode(Interface *gi, LPCTSTR SrcName, LPCTSTR DstName); extern TriObject* GetTriObject(Object *o); extern Modifier *GetSkin(INode *node); -extern void PositionAndRotateNode(INode *n, Point3 p, Quat& q, TimeValue t = 0); + +enum PosRotScale +{ + prsPos = 0x1, + prsRot = 0x2, + prsScale = 0x4, + prsDefault = prsPos | prsRot | prsScale, +}; +extern void PositionAndRotateNode(INode *n, Point3 p, Quat& q, PosRotScale prs = prsDefault, TimeValue t = 0); extern Niflib::NiNodeRef FindNodeByName( const vector<Niflib::NiNodeRef>& blocks, const string& name ); extern std::vector<Niflib::NiNodeRef> SelectNodesByName( const vector<Niflib::NiNodeRef>& blocks, LPCTSTR match); @@ -218,4 +226,8 @@ static inline Matrix3 TOMATRIX3(const Niflib::Matrix44 &tm, bool invert = true){ return m; } +static inline Quat TOQUAT(const Niflib::Quaternion& q){ + return Quat(q.x, q.y, q.z, q.w); +} + #endif // _NIUTILS_H_ \ No newline at end of file