关于获取3DS MAX中的蒙皮数据 3DSMAX C++API的应用

in 编程
关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9

目的是为OSG做自定义的导出插件. 记录取得数据的方法.

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;
}

`

函数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());
}

`

蒙皮导出的学习

关注公众号【好便宜】( ID:haopianyi222 ),领红包啦~
阿里云,国内最大的云服务商,注册就送数千元优惠券:https://t.cn/AiQe5A0g
腾讯云,良心云,价格优惠: https://t.cn/AieHwwKl
搬瓦工,CN2 GIA 优质线路,搭梯子、海外建站推荐: https://t.cn/AieHwfX9
扫一扫关注公众号添加购物返利助手,领红包
Comments are closed.

推荐使用阿里云服务器

超多优惠券

服务器最低一折,一年不到100!

朕已阅去看看