最近一直在试图把魔兽3的mdx文件转为Ogre Mesh,学习一下基础的3D编程。Ogre Mesh的导出在很久之前也曾试图做过,并且还把WOW的m2模型以及WMO模型导入到了Max中,但是只做到了骨架的导入,动画数据始终出不来,于是放弃。

这次依然是碰到这里的问题,导出静态的Mesh很快就完成,包括模型与材质,代码也比较简单。

// 模型数据
bool ModelLoaderMdx::loadGeosets(Ogre::MeshPtr model, MdxDataStreamPtr dataStream, int size)
{
unsigned int index = 0;
while(size > 0)
{
int geosetSize = dataStream->read<int>();
size -= geosetSize;
Ogre::String meshName = m_modelName + Ogre::String("_sub_") + Ogre::StringConverter::toString(index++);
Ogre::SubMesh* subMesh = model->createSubMesh(meshName);
// 硬件缓冲编号
// 分别为顶点坐标 法线 贴图坐标
#define HARDWARE_BUFFER_SOURCE_VERTEX 0
#define HARDWARE_BUFFER_SOURCE_NORMAL 1
#define HARDWARE_BUFFER_SOURCE_TEXPOS 2
//
// 顶点数据
//
if(!expectTag(dataStream, 'VRTX'))
{
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Expect VRTX data for geoset",
"ModelLoaderMdx::loadGeosets");
}
unsigned int vertexCount = dataStream->read<unsigned int>();
// 不使用共享顶点数据
// 每个SubMesh都创建自己的VertexData
subMesh->useSharedVertices = false;
subMesh->vertexData = OGRE_NEW Ogre::VertexData();
subMesh->vertexData->vertexStart = 0;
subMesh->vertexData->vertexCount = vertexCount;
subMesh->vertexData->vertexDeclaration->addElement(
HARDWARE_BUFFER_SOURCE_VERTEX, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
size_t vertexSize = sizeof(float) * 3;
assert(subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_VERTEX) == vertexSize);
if (subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_VERTEX) != vertexSize)
{
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "VertexSize error",
"ModelLoaderMdx::loadGeoset");
}
Ogre::HardwareVertexBufferSharedPtr vertexBuffer;
vertexBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
vertexSize,
vertexCount,
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
void* vertexBufferData = vertexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
unsigned int vertexBufferDataPos = 0;
for (unsigned int i = 0; i < vertexCount; ++i)
{
Ogre::Vector3 data(
dataStream->read<float>(),
dataStream->read<float>(),
dataStream->read<float>()
);
transformCoord(data);
memcpy((char*)vertexBufferData + vertexBufferDataPos, &data, sizeof(Ogre::Vector3));
vertexBufferDataPos += sizeof(Ogre::Vector3);
}
vertexBuffer->unlock();
subMesh->vertexData->vertexBufferBinding->setBinding(HARDWARE_BUFFER_SOURCE_VERTEX, vertexBuffer);
//
// 法线数据
//
if(!expectTag(dataStream, 'NRMS'))
{
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Expect NRMS data for material",
"ModelLoaderMdx::loadGeosets");
}
unsigned int normalCount = dataStream->read<unsigned int>();
if(normalCount != vertexCount)
{
std::stringstream stream;
stream << "Normal count mismatch, " << normalCount << " normals for " << vertexCount << " vertices)!";
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, stream.str(),
"ModelLoaderMdx::loadGeoset");
}
subMesh->vertexData->vertexDeclaration->addElement(
HARDWARE_BUFFER_SOURCE_NORMAL, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
size_t normalSize = sizeof(float) * 3;
assert(subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_NORMAL) == normalSize);
if (subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_NORMAL) != normalSize)
{
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "NormalSize error",
"ModelLoaderMdx::loadGeoset");
}
Ogre::HardwareVertexBufferSharedPtr normalBuffer;
normalBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
normalSize,
normalCount,
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
void* normalBufferData = normalBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
unsigned int normalBufferDataPos = 0;
for (unsigned int i = 0; i < normalCount; ++i)
{
Ogre::Vector3 data(
dataStream->read<float>(),
dataStream->read<float>(),
dataStream->read<float>()
);
transformCoord(data);
memcpy((char*)normalBufferData + normalBufferDataPos, &data, sizeof(Ogre::Vector3));
normalBufferDataPos += sizeof(Ogre::Vector3);
}
normalBuffer->unlock();
subMesh->vertexData->vertexBufferBinding->setBinding(HARDWARE_BUFFER_SOURCE_NORMAL, normalBuffer);
…………
        //
// 顶点索引
//
if(!expectTag(dataStream, 'PVTX'))
{
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Expect PVTX data for geoset",
"ModelLoaderMdx::loadGeosets");
}
unsigned int indexCount = dataStream->read<unsigned int>();
assert(totalIndexCount == indexCount);
if (totalIndexCount != indexCount)
{
std::stringstream stream;
stream << "indexCount is " << indexCount << ", but totalIndexCount for all faces is " << totalIndexCount;
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, stream.str(),
"ModelLoaderMdx::loadGeoset");
}
subMesh->indexData->indexStart = 0;
subMesh->indexData->indexCount = indexCount;
Ogre::HardwareIndexBufferSharedPtr indexBuffer;
indexBuffer = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
Ogre::HardwareIndexBuffer::IT_16BIT,
indexCount,
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
void* indexBufferData = indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
dataStream->read(indexBufferData, indexCount * sizeof(unsigned short));
// 三角形反转, 将原来的反面朝外
unsigned short* tmpData = (unsigned short*)indexBufferData;
for (unsigned int i = 0; i < indexCount; i += 3)
{
unsigned short tmp = tmpData[i + 1];
tmpData[i + 1] = tmpData[i + 2];
tmpData[i + 2] = tmp;
}
indexBuffer->unlock();
subMesh->indexData->indexBuffer = indexBuffer;
subMesh->operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
…………
// 材质ID
unsigned int materialID = dataStream->read<unsigned int>();
Ogre::String materialName = m_modelName + Ogre::String("_") + boost::lexical_cast<Ogre::String>(materialID);
subMesh->setMaterialName(materialName);
…………
//
// 贴图坐标
//
if(!expectTag(dataStream, 'UVBS'))
{
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Expect UVBS data for geoset",
"ModelLoaderMdx::loadGeosets");
}
unsigned int texturePositionCount = dataStream->read<unsigned int>();
if(texturePositionCount != vertexCount)
{
std::stringstream stream;
stream << "Texture position count mismatch, " << texturePositionCount << " texture positions for " << vertexCount << " vertices)!";
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, stream.str(),
"ModelLoaderMdx::loadGeoset");
}
// TextureCoord Data
subMesh->vertexData->vertexDeclaration->addElement(
HARDWARE_BUFFER_SOURCE_TEXPOS, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
size_t texPosSize = sizeof(float) * 2;
assert(subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_TEXPOS) == texPosSize);
if (subMesh->vertexData->vertexDeclaration->getVertexSize(HARDWARE_BUFFER_SOURCE_TEXPOS) != texPosSize)
{
OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "TexturePositionSize error",
"ModelLoaderMdx::loadGeoset");
}
Ogre::HardwareVertexBufferSharedPtr texPosBuffer;
texPosBuffer = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(
texPosSize,
texturePositionCount,
Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
void* texPosBufferData = texPosBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
dataStream->read(texPosBufferData, texPosSize * texturePositionCount);
texPosBuffer->unlock();
subMesh->vertexData->vertexBufferBinding->setBinding(HARDWARE_BUFFER_SOURCE_TEXPOS, texPosBuffer);
}
return true;
}

但是到了动画数据这里问题又出来了,而且mdx模型与m2模型还有些差别,mdx模型中没有骨骼数据,只有max中最简单的三种变换数据,Ogre中只有MorphAnimation能够实现此种动画。

Ogre的MorphAnimation的第一个KeyFrame必须带有完整的顶点信息,而mdx模型中旋转、缩放与位移是分开的,也就是一个KeyFrame上可能只有一种变换,或者多种。而实际上在max中制作动画的时候这三种变换也是独立开的,Ogre的论坛上找到一篇讨论有人提到了这个问题,可惜制作者的回复是MorphAnimation只实现到这样……

也确实,现在除了一些小物件的动画外,主角,怪物的动画都用skeleton了,也许MorphAnimation就快退出历史的舞台,在Ogre中看不到了,也不能指望会有什么改进。

继续实现之,那就只能在有KeyFrame的地方把三种变换都计算一次,然后取得最终变换后的位置数据,也就是做人工的动画帧采样。在War3EditorSource的基础上做了些修改,终于,一帧帧的动画计算出来了。

不过问题依然还有很多,比如mdx模型,尤其是怪物和角色模型中大量用到了ReplacableTexture,这些需要通过读配置文件来获取可用的贴图,另外模型上附带的粒子特效、纹理动画等都还没有导出,看看这个没有贴图的攻击中的蝎子,前面的路仍然很远。

魔兽mdx文件导出为Ogre Mesh的小进展相关推荐

  1. 基于魔兽哈希算法的Ogre资源文件扩展的设计与实现

    一.功能需求 1.需要实现的功能: (1).创建.打开和关闭资源包. (2).压缩资源包.消除数据添加.修改和删除带来的数据碎片,扩展索引表容量,重设资源包密钥. (3).合并资源包.将外部的资源包整 ...

  2. 数据库抽取,生成CSV文件导出,CSVUtils工具类

    2019独角兽企业重金招聘Python工程师标准>>> 开发背景: 最近一直在忙一个任务调度系统,需求一直没定下来,需求一直变更,调度一直改,往往复复... 等这波忙完了可以写一下关 ...

  3. 关于文件导出(下载)功能不兼容IE浏览器的解决方案

    关于文件导出(下载)功能不兼容IE浏览器的解决方案 参考文章: (1)关于文件导出(下载)功能不兼容IE浏览器的解决方案 (2)https://www.cnblogs.com/padaleidelei ...

  4. GDI对象存储和查看lib文件导出函数

    GDI对象存储     C++对象通常存储在栈.堆或者由应用程序通过定制的新操作符分配的任何地址空间里.基本上,它总是存放在用户模式的地址空间里,除非我们正在讨论内核模式设备驱动程序.     Win ...

  5. php excel文件导出之二 图像导出

    PHP文件导出 之图像 和 文字同一时候导出 事实上之前写了个php文件导出.跟这个极为相似,由于项目须要对图像进行导出.查询一番.又写了一个, 这个能实现图像的导出(仅仅能是本地图像,不能使用远程图 ...

  6. asp.net导出excel-一行代码实现excel、xml、pdf、word、html、csv等7种格式文件导出功能而且美观-SNF快速开发平台...

    分享: 腾讯微博  新浪微博   搜狐微博   网易微博  腾讯朋友  百度贴吧  豆瓣   QQ好友  人人网 作者:王春天  原文地址:http://www.cnblogs.com/spring_ ...

  7. Markdown文件导出为HTML的小程序

    Markdown文件导出为HTML的小程序 为什么做 最近把一些学习经验记下来,总结成MarkDown文件,不知不觉已经有12篇了. Sublime Text 的 MarkDown Preview 插 ...

  8. 导出文件_一招解决PDF文件导出图片

    将PDF文件保存为高清图片是经常需要进行的保存方式之一,因为PDF文件虽然安全性高,但是相比较图片而言,还是不易进行查看的,那么如何将PDF文件导出图片呢?以前也了解过很多方法,不过最好的当然不是截图 ...

  9. hdfs文件如何导出到服务器,[Hadoop] 如何将 HDFS 文件导出到 Windows文件系统

    介绍如何在 Windows 环境中, 将保存在 HDFS 上的文件导出到本机上 数据导入到 HDFS 后 当然也要有方法将数据从 HDFS 导出到本机系统上 在 HADOOP JAVA API 所提供 ...

最新文章

  1. 正则学习(2)--- 简单匹配原理
  2. mysql创建索引小案例
  3. OpenStack Nova计算服务管理(四)
  4. Java 8 Friday:让我们弃用那些旧版库
  5. mysql 结果保存到文件_将MySQL中sql运行结果保存到文件
  6. 任意文件上传之绕过云waf+本地防火墙双重防护
  7. 微信多开软件苹果版_微信PC版 v3.0.0.57 多开amp;消息防撤回
  8. 基于Socket的UDP和TCP编程介绍-转
  9. crossApp初级-CAView类-5
  10. 中国电信物联网开发平台北向开发获取设备ID及其历史产生的数据
  11. 不会拼音学计算机怎么写,不会拼音不会拼音怎怎么打字?
  12. 牛客SQL练习-45-将titles_test表名修改为titles_2017
  13. 翻译管理协作翻译平台-crowdin
  14. Diffusion models代码解读:入门与实战
  15. Camera HAL3学习
  16. StreamEye使用说明
  17. 对凯恩期《通论》的一点随想
  18. java实现word转pdf在线预览格式
  19. 全面预算新玩法,给你一个崭新的全局角度看管理
  20. DPDK实战之skeleton(basicfwd)

热门文章

  1. 如何用电脑控制手机屏幕,写工作日志
  2. 使用阿里云服务器搭建代理服务器
  3. win7计算机收藏夹位置,Win7收藏夹在哪?Win7怎么找收藏夹文件路径?
  4. 北洋大讲堂之“斯凯网络CEO宋涛-我的创业之路”感想
  5. vue Cli3官网地址
  6. win7计算机名怎么是感叹号,Win7旗舰版系统电脑网络连接不上显示感叹号怎么回事?...
  7. Mac上的“任务管理器”在哪里?
  8. C# 特性类[笔记]
  9. Deep Learning(深度学习)学习笔记整理
  10. zypper in 安装下载不了_Color Wheel下载与Color Wheel如何配搭衣服颜色?