游戏开发论坛

 找回密码
 立即注册
搜索
查看: 8388|回复: 7

我对OgreMaxExporter的修改

[复制链接]

4

主题

15

帖子

26

积分

注册会员

Rank: 2

积分
26
QQ
发表于 2010-3-15 09:34:00 | 显示全部楼层 |阅读模式
很久都想在Ogre下自己独立开发一些东西,Ogre虽然很强大,但是对数据接口方面很弱,虽然Ogre Team也做了一些事情,比如在用Ogre开发的Max插件,但是用起来却不怎么爽,今天把老外写的Ogre的Max插件Down下来看了一下,发现他们写的太粗糙,模型虽然导出来了,但是很多纹理都是错的,特别对多重纹理的导出根本就没处理。没办法,只好自己写了。

Ogre1.4.9  Max导出插件总结:

(1):打开OgreMaxExporter,把工程设置好,把Ogre的库和3DMax的库加入的工程中去。

(2):最好把输出目录放在Max的plugins文件夹下面,这样就不必拷来拷去了。

(3):编译通过,运行3DMax就可以看到在Export下面多了一个输出的文件类型。可以导出一个导出类型OGRE 3D Exporter.xml, .mesh, .material, .skeleton。

(4):导出后,你会发现很多xml文件,打开就会看到模型的顶点,纹理,材质等信息。

(5):用OgreXMLConverter.exe转成.mesh文件,如果xml文件很多,可以用批处理命令:

for %i in (F:\fujian\*.xml) do OgreXMLConverter %i .要确保OgreXMLConverter 已经注册到环境变量中,如果没有,那只能用全路径名代替。for %i in (F:\fujian\*.xml) do E:\ogre\OgreXMLConverter.exe %i;

(6):把转成的mesh和material 文件拷贝到Media文件中去,转成的mesh文件就可以直接被Ogre应用程序用了。

代码修改:

(1)必须明确如何划分submesh. 在max中,是没有submesh这个概念的,对于一个复合的物体,比如凳子由一个长方体和四个圆柱体,从ogre的角度我们可以认为这个凳子是由5个submesh组成。而max没有这样的区分,他把所有的长方体和四个圆柱体的顶点信息都放在一个数组中,所以我们必须从这些顶点中区分那些顶点属于长方体,那些顶点属于柱体。其实我们可以用Max的submaterial来区分,主观的认为具有相同材质的顶点在同一个submesh上。认识到这一点,我们代码的修改就变的容易了。

(2)修改bool MeshXMLExporter::export(OutputMap& output)函数:如下

bool MeshXMLExporter::export(OutputMap& output)
{
try
{
  std::stringstream of;
  while (!m_submeshNames.empty())
   m_submeshNames.pop();
  if (m_pGame)
  {
   m_pGame->ReleaseIGame();
   m_pGame = 0;
  }
  m_ei->theScene->EnumTree(this);
  m_pGame = GetIGameInterface();
  IGameConversionManager* cm = GetConversionManager();
  cm->SetCoordSystem(IGameConversionManager::IGAME_OGL);
  m_pGame->InitialiseIGame(m_nodeTab, false);
  m_pGame->SetStaticFrame(0);
  int nodeCount = m_pGame->GetTopLevelNodeCount();
  if (nodeCount == 0)
  {
   MessageBox(GetActiveWindow(),
    "No nodes available to export, aborting...",
     "Nothing To Export", MB_ICONINFORMATION);
   m_pGame->ReleaseIGame();
   return false;
  }
  std::string fileName;
  IGameNode* node = m_pGame->GetTopLevelNode(0);
  if (!m_config.getExportMultipleFiles())
   fileName = m_config.getExportFilename();
  else
  {
   fileName = m_config.getExportPath() + "\\";
   fileName += node->GetName();
   fileName += ".mesh.xml";
  }
  // write start of XML data
  streamFileHeader(of);
  int nodeIdx = 0;
  std::map<std::string, std::string> materialScripts;
  while (nodeIdx < nodeCount)
  {
   std::string mtlName;
   IGameNode* node = m_pGame->GetTopLevelNode(nodeIdx);
   IGameObject* obj = node->GetIGameObject();
// InitializeData() is important -- it performs all of the WSM/time eval for us; no data without it
   obj->InitializeData();
   IGameMaterial* mtl = node->GetNodeMaterial();
   /************************************************************************/
   /*           武汉大学遥感信息工程学院S091班赵龙      2010-3-14       */
   /************************************************************************/
   int numMeshes = 1;
   bool isMultiMesh = false;
   //如果该材质是烘焙出来的,之间用烘焙后的材质,将原来的材质丢掉
   if(mtl && mtl->GetMaxMaterial()->ClassID()==Class_ID(BAKE_SHELL_CLASS_ID, 0))
   {
    mtl=mtl->GetSubMaterial(1);
   }
   //如果是该材质是由多个材质混合而成,则记录有多少个材质混合
   if (mtl && mtl->GetMaxMaterial()->ClassID() == Class_ID(MULTI_CLASS_ID, 0))
   {
    isMultiMesh = TRUE;
    //根据numMeshes来确定有多少个submesh
    numMeshes   = mtl->GetSubMaterialCount();
   }
   /************************************************************************/
   /*           武汉大学遥感信息工程学院S091班赵龙      2010-3-14       */
   /************************************************************************/
   exportSubmeshByMtl(materialScripts,mtl,of,obj,numMeshes,isMultiMesh);
   //////////////////////////////////////////////////////////////////////////
   node->ReleaseIGameObject();
   nodeIdx++;
   //写下一个.xml文件
   if (m_config.getExportMultipleFiles() || nodeIdx == nodeCount)
   {
    // write end of this file's XML
    streamFileFooter(of);
    // insert new filename --> stream pair into output map
    output[fileName] = std::string(of.str());
    of.str("");
    if (nodeIdx != nodeCount)
    {
     fileName = m_config.getExportPath() + "\\";
     node = m_pGame->GetTopLevelNode(nodeIdx);
     fileName += node->GetName();
     fileName += ".mesh.xml";
     // start over again with new data
     streamFileHeader(of);
    }
   }
  }
  m_pGame->ReleaseIGame();
  // export materials if we are writing those
  if (m_config.getExportMaterial())
  {
   std:fstream materialFile;
   materialFile.open((m_config.getExportPath() + "\\" +
     m_config.getMaterialFilename()).c_str(), std::ios::out);
   if (materialFile.is_open())
   {
    for (std::map<std::string, std::string>::iterator it = materialScripts.begin();
     it != materialScripts.end(); ++it)
    {
     materialFile << it->second;
    }
    materialFile.close();
   }
  }
  return true;
}
catch (...)
{
  MessageBox(GetActiveWindow(),
   "An unexpected error has occurred while trying to export, aborting", "Error", MB_ICONEXCLAMATION);
  if (m_pGame)
   m_pGame->ReleaseIGame();
  return false;
}
}

(3)添加函数:

void MeshXMLExporter::exportSubmeshByMtl(std::map<std::string, std::string>& materialScripts,
  IGameMaterial* mtl,std::stringstream& of,IGameObject* obj,
  int numMeshes, bool isMultiMesh)

该函数是根据Material生成submesh



void MeshXMLExporter::exportSubmeshByMtl(std::map<std::string, std::string>& materialScripts,
  IGameMaterial* mtl,std::stringstream& of,IGameObject* obj,
  int numMeshes, bool isMultiMesh)
{
  if(isMultiMesh)  //对多重纹理的处理
  {
   long i;
   for(i = 0; i < numMeshes; i++)
   {
    IGameMaterial* subMtl = mtl->GetSubMaterial(i);

    std::string mtlName = subMtl->GetMaterialName();
    //去掉空格
    std::string::size_type pos;
    while ((pos = mtlName.find_first_of(' ')) != std::string::npos)
     mtlName.replace(pos, 1, _T("_"));
    long reName = 0;
    std::string tempName = mtlName;

 //因为ogre的材质名称是不能重复的,而Max的材质名可以重复

 //所以如果遇到有相同的材质名,就生成一个不同的材质名代替
    while (materialScripts.find(tempName) != materialScripts.end())
    {
     std::stringstream stream;
     stream.width(0);
     stream.fill(' ');
     stream << reName;
     tempName = mtlName + stream.str();
     reName++;
    }
    mtlName = tempName;

   //根据材质的ID来判断那些顶点属于那个submesh

    if (streamSubmeshID(of, obj, mtlName,mtl->GetMaterialID(i)))
    {
     m_submeshNames.push(std::string(mtlName));
     if (materialScripts.find(mtlName) == materialScripts.end())
     {
      // export new material script
      MaterialExporter mexp(m_config, m_materialMap);
      std::string script;
      mexp.buildMaterial(subMtl, mtlName, script);
      materialScripts[mtlName] = script;
     }
    }
   }
  }
  else//单个纹理   ,从原来的代码中拷贝过来的。原来的代码也有问题
  {
   std::string::size_type pos;
   if(mtl == NULL)//这个地方有问题,没有材质的物体导不出来
   {
    return;
   }
   std::string mtlName = mtl->GetMaterialName();
   //去掉空格
   while ((pos = mtlName.find_first_of(' ')) != std::string::npos)
    mtlName.replace(pos, 1, _T("_"));

   if (materialScripts.find(mtlName) == materialScripts.end())
   {
    // export new material script
    MaterialExporter mexp(m_config, m_materialMap);
    std::string script;
    mexp.buildMaterial(mtl, mtlName, script);
    materialScripts[mtlName] = script;
   }

   if (streamSubmesh(of, obj, mtlName))
    m_submeshNames.push(std::string(mtlName));

  }
}

(4) 仿照streamSubmesh写了一个streamSubmeshID()这个比较长但是改的代码不多,这里就不代码全贴出来了

改的第一处是:thisFaceCount来代替faceCount;faceCount是指整个Node节点face的个数

thisFaceCount是当前submesh拥有的face的个数。

for (i = 0; i < faceCount; i++)
  {
   if(mesh->GetFaceMaterialID(i) == ID)
   {
    thisFaceCount ++;
   }
  }

//如果face的个数为0就没有必要建立一个submesh
  if(thisFaceCount == 0)
  {
     return false;
  }

//顶点的个数
  int vertCount = thisFaceCount*3;

改的第二处是在for (i =0; i<faceCount; i++)处,紧跟括号下面:

 //不属于该submesh的face全部Pass掉
   if(mesh->GetFaceMaterialID(i) != ID)
   {
    continue;
   }

(5)修改Material的导出:由于一个模型不只是有一个纹理坐标,所以要为每一个texture指定纹理坐标

  在MaterialExporter::streamPass的函数中

    of << "\n\t\t\ttexture_unit " << std::endl;
     of << "\t\t\t{" << std::endl;
     std::string bmap(tmap->GetBitmapFileName());
     bmap = bmap.substr(bmap.find_last_of('\\') + 1);
     long k = tmap->GetMapChannel();//这里是我改的
     if(k > texMapIdx)//这里是我改的
      k = texMapIdx;//这里是我改的

     of << "\t\t\t\ttex_coord_set " << k << std::endl;//这里是我改的
     of << "\t\t\t\ttexture " << bmap << std::endl;
     of << "\t\t\t}" << std::endl;

好了看看效果吧

4

主题

15

帖子

26

积分

注册会员

Rank: 2

积分
26
QQ
 楼主| 发表于 2010-3-15 09:37:00 | 显示全部楼层

Re: 我对OgreMaxExporter的修改


4

主题

15

帖子

26

积分

注册会员

Rank: 2

积分
26
QQ
 楼主| 发表于 2010-3-15 09:38:00 | 显示全部楼层

Re: 我对OgreMaxExporter的修改


8

主题

716

帖子

716

积分

高级会员

Rank: 4

积分
716
发表于 2010-3-15 09:52:00 | 显示全部楼层

Re:我对OgreMaxExporter的修改

不错!
很少有人会意识到一个输出插件对游戏的重要性。
当然,你做到这种程度才是刚刚开始,max的材质很复杂,mesh优化也需要做很多工作。
请继续加油~

4

主题

15

帖子

26

积分

注册会员

Rank: 2

积分
26
QQ
 楼主| 发表于 2010-3-15 09:56:00 | 显示全部楼层

Re: 我对OgreMaxExporter的修改

在选择osg引擎和Ogre引擎的问题上徘徊了很久。最终还是选择了Ogre引擎,也许是因为一种特殊的感情吧!
Ogre引擎有些地方不是很完美。我只想通过我们的努力把它变得更好!

8

主题

34

帖子

34

积分

注册会员

Rank: 2

积分
34
发表于 2010-4-2 12:54:00 | 显示全部楼层

Re:我对OgreMaxExporter的修改

OgreMaxExporter和LEXIExporter相比哪个好些?
我想选择一个在上面修改

4

主题

15

帖子

26

积分

注册会员

Rank: 2

积分
26
QQ
 楼主| 发表于 2010-4-8 11:18:00 | 显示全部楼层

Re: 我对OgreMaxExporter的修改

我没有搞过LEXIExporter,不过OgreMaxExporter还有很多不尽人意的地方,要改的地方很多

5

主题

266

帖子

809

积分

高级会员

Rank: 4

积分
809
发表于 2015-11-17 12:15:33 | 显示全部楼层
说的你好像有OgreMaxExporter和LEXIExporter的源码一样
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-2-25 14:17

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表