關於獲取3DS MAX中的蒙皮數據 3DSMAX C++API的應用

目的是爲OSG作自定義的導出插件. 記錄取得數據的方法.node

Max在代碼中會提供一個INode對象. 從這個對象裏取出各類數據. getSkin這個函數取出了ISkin修改器 下面這個函數同樣是用於學習, 把數據輸出到文本文件數組

`函數

ISkin* OSGExp::getSkin(INode *pINode)
{
	// get the object reference of the node
	Object *pObject;
	pObject = pINode->GetObjectRef();
	if (pObject == 0) return 0;

	// loop through all derived objects
	ObjectState _objectState = pINode->EvalWorldState(_ip->GetTime());// Arcadia 2018-09-10
	if (_objectState.obj->SuperClassID() == GEOMOBJECT_CLASS_ID)// Arcadia 2018-09-10 有頂點數據,纔會有蒙皮
	{
		IDerivedObject *pDerivedObject;
		pDerivedObject = static_cast<IDerivedObject *>(pObject);

		// loop through all modifiers 遍歷全部的修改器
		int stackId;
		Modifier *pModifier;// 這裏用於存放當前修改器, 用於試着轉成蒙皮
		ISkin* _skin = NULL;
		for (stackId = 0; stackId < pDerivedObject->NumModifiers(); stackId++)
		{
			_skin = NULL;
			// get the modifier
			if (NULL == pDerivedObject->GetModifier(stackId))
			{
				continue;
			}
			// 蒙皮在Max中是個修改器, 取得這個修改器,再轉成_skin
			pModifier = pDerivedObject->GetModifier(stackId);

			// Arcadia 2018-09-10
			if (pModifier)
			{
				char _sTemp[255];
				// 蒙皮數據的上下文:
				_skin = dynamic_cast<ISkin*>(pModifier);
				if (_skin)
				{
				}// END if(_skin)
			}
		}
		return _skin;
	}

	return 0;
}

`oop

函數readSkinData解析蒙皮數據 在Max導出插件製做過程當中, 用寫文件的方式調試比較方便 每一個頂點對應幾個有做用的骨骼, GetNumAssignedBones 取得有做用的骨骼 而後再遍歷取得這個頂點的各個權重值. 並遍歷取得相關骨骼的序號.學習

這裏要注意的一點是, 全部骨骼是一個數組, 單個頂點的做用骨骼又是另外一數組, 用單個頂點做用骨骼的下標能夠取得骨骼於[全部骨骼數組]的下標.插件

` /** * 讀取蒙皮數據, 輸出到文件, 用於調試與學習 */ void OSGExp::readSkinData(ISkin skin,INode node) { using std::sprintf; string labelStart("\n S S S S S S S S S S S S\n"); m_FileObj.write(labelStart.c_str(), labelStart.size());調試

char _sTemp[255];

	{
		m_FileObj.write("有轉成ISkin\n", string("有轉成ISkin\n").size());
		ISkinContextData *_data = skin->GetContextInterface(node);

		sprintf(_sTemp, "點數:\t%d\n", _data->GetNumPoints());
		m_FileObj.write(_sTemp, string(_sTemp).size());

		sprintf(_sTemp, "骨骼數:\t%d\n", skin->GetNumBones());
		m_FileObj.write(_sTemp, string(_sTemp).size());

		Matrix3 _mt3;
		sprintf(_sTemp, "SKIN_OK?\t%d\n",SKIN_OK == skin->GetSkinInitTM(node,_mt3) ); // 2018-09-12 返回是 SKIN_INVALID_NODE_PTR 不知會不會有問題 GetSkinInitTM是OK的, 但GetBoneInitTM不OK
		m_FileObj.write(_sTemp, string(_sTemp).size());

		// 取骨骼:
		for (int i = 0; i < skin->GetNumBones(); ++i)
		{
			INode* nodeBone = skin->GetBone(i);
			const wchar_t* wc_strName = nodeBone->GetName();
			string s_strName = Util::TDuW2A(wc_strName);
			sprintf(_sTemp, "骨骼名:\t%d\t%s", i, s_strName.c_str() );
			m_FileObj.write(_sTemp, string(_sTemp).size());


			switch ( skin->GetBoneProperty(i) )
			{
			case BONE_LOCK_FLAG:
				sprintf(_sTemp, "\t%s", "BONE_LOCK_FLAG");
				break;
			case BONE_ABSOLUTE_FLAG:
				sprintf(_sTemp, "\t%s", "BONE_ABSOLUTE_FLAG");
				break;
			case BONE_SPLINE_FLAG:
				sprintf(_sTemp, "\t%s", "BONE_SPLINE_FLAG");
				break;
			case BONE_SPLINECLOSED_FLAG:
				sprintf(_sTemp, "\t%s", "BONE_SPLINECLOSED_FLAG");
				break;
			case BONE_DRAW_ENVELOPE_FLAG:
				sprintf(_sTemp, "\t%s", "BONE_DRAW_ENVELOPE_FLAG");
				break;
			case BONE_BONE_FLAG:
				sprintf(_sTemp, "\t%s", "BONE_BONE_FLAG");
				break;
			case BONE_DEAD_FLAG:
				sprintf(_sTemp, "\t%s", "BONE_DEAD_FLAG");
				break;
			}
			m_FileObj.write(_sTemp, string(_sTemp).size());



			// Bone TM:
			union xxx {
				xxx() {}
				Matrix3 mt3_3;// = skin->GetBoneTm(i);
				float m[4][3];// = (float*)mt3_3;
			} _getDataU;
			_getDataU.mt3_3 = skin->GetBoneTm(i);
			sprintf(_sTemp, "\t座標Z:\t%f", _getDataU.m[3][2]);
			m_FileObj.write(_sTemp, string(_sTemp).size());


			sprintf(_sTemp, "\n");
			m_FileObj.write(_sTemp, string(_sTemp).size());


		}
	}// END if(_skin)

	// GetNumBonesFlat:
	sprintf(_sTemp, "GetNumBonesFlat:\t%d\n", skin->GetNumBonesFlat());
	m_FileObj.write(_sTemp, string(_sTemp).size());

	// GetRefFrame:
	sprintf(_sTemp, "GetRefFrame:\t%d\n", skin->GetRefFrame());
	m_FileObj.write(_sTemp, string(_sTemp).size());

	// 輸出各頂點座標:


	// ISkinContextData:
	{
		sprintf(_sTemp, "ISkinContextData:\n");
		m_FileObj.write(_sTemp, string(_sTemp).size());

		ISkinContextData *skinData = skin->GetContextInterface(node);

		sprintf(_sTemp, "\tGetNumPoints:\t%d\n", skinData->GetNumPoints());
		m_FileObj.write(_sTemp, string(_sTemp).size());

		sprintf(_sTemp, "\tGetNumAssignedBones:\t%d\n", skinData->GetNumAssignedBones(0));// 骨骼數
		m_FileObj.write(_sTemp, string(_sTemp).size());

		sprintf(_sTemp, "\tGetAssignedBone:\t%d\n", skinData->GetAssignedBone(0,0));// 有分配的骨骼
		m_FileObj.write(_sTemp, string(_sTemp).size());

		// 各頂點權重:
		for (int i = 0; i < skinData->GetNumPoints(); ++i)
		{
			int numOfBones = skinData->GetNumAssignedBones(i);
			// 本頂點於各骨骼的權重
			for (int boneAffectedId = 0; boneAffectedId < numOfBones;++boneAffectedId)
			{
				// 這裏取到了權重__weight
				float __weight = skinData->GetBoneWeight(i, boneAffectedId);
				int boneIndex = skinData->GetAssignedBone( i , boneAffectedId);
				//string strName = Util::TDuW2A( skin->GetBoneName(boneAffectedId) );
				string strNameFromBoneIndex = Util::TDuW2A(skin->GetBoneName(boneIndex));

				if(-1 != boneIndex)
				{
					sprintf(_sTemp, "\t\tBoneWeight:\t%d,%d:\t%f \t boneIndex:%d(%s)\n  ", i, boneAffectedId, __weight,boneIndex , strNameFromBoneIndex);
					m_FileObj.write(_sTemp, string(_sTemp).size());
				}
			}

			/*float weight = skinData->GetBoneWeight(i, skinData->GetAssignedBone(0, 0));
			sprintf(_sTemp, "\t\tBoneWeight:\t%d:%f\n", i , weight);
			m_FileObj.write(_sTemp, string(_sTemp).size());*/
		}

		//sprintf(_sTemp, "\tGetBoneWeight:\t%f\n", skinData->GetBoneWeight(0, skinData->GetAssignedBone(0, 0)));
		//m_FileObj.write(_sTemp, string(_sTemp).size());

	}

	#pragma region 頂點數據輸出
	string labelVData("\n頂點數據輸出:\n");
	m_FileObj.write(labelVData.c_str(), labelVData.size());
	// 輸出頂點數據 , 以能進一步研究頂點蒙皮數據的正確性.
	// 1. 頂點的次序
	// Order of the vertices. Get them counter clockwise if the objects is
	// negatively scaled. This is important if an object has been mirrored.
	Matrix3 tm = node->GetObjTMAfterWSM(0/*TimeValue*/);
	BOOL negScale = getTMNegParity(tm);
	int vx1, vx2, vx3;
	if (negScale) {
		vx1 = 2;
		vx2 = 1;
		vx3 = 0;
	}
	else {
		vx1 = 0;
		vx2 = 1;
		vx3 = 2;
	}

	// Get mesh object
	BOOL needDel;
	ObjectState os = node->EvalWorldState(0);
	TriObject* tri = getTriObjectFromObject(os.obj, 0/*TimeValue*/, needDel);

	// Extract coords, normals, texture coords, vertex colors, and vertex normals
	// from MAX mesh.

	Mesh* mesh = &tri->GetMesh();
	for (int _iv = 0; _iv < mesh->numVerts; ++_iv)
	{
		Point3 v1 = mesh->verts[_iv];
		std::sprintf(_sTemp, "\tv1:%.4f\t%.4f\t%.4f\n", v1.x, v1.y, v1.z);
		string strV1(_sTemp);
		m_FileObj.write(strV1.c_str(), strV1.size());
	}
	#pragma endregion 頂點數據輸出

	string labelEnd("\n ES ES ES ES ES ES ES ES\n");
	m_FileObj.write(labelEnd.c_str(), labelEnd.size());
}

`code

蒙皮導出的學習

相關文章
相關標籤/搜索