魔兽mdx文件导出为Ogre Mesh的小进展
最近一直在试图把魔兽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的小进展相关推荐
- 基于魔兽哈希算法的Ogre资源文件扩展的设计与实现
一.功能需求 1.需要实现的功能: (1).创建.打开和关闭资源包. (2).压缩资源包.消除数据添加.修改和删除带来的数据碎片,扩展索引表容量,重设资源包密钥. (3).合并资源包.将外部的资源包整 ...
- 数据库抽取,生成CSV文件导出,CSVUtils工具类
2019独角兽企业重金招聘Python工程师标准>>> 开发背景: 最近一直在忙一个任务调度系统,需求一直没定下来,需求一直变更,调度一直改,往往复复... 等这波忙完了可以写一下关 ...
- 关于文件导出(下载)功能不兼容IE浏览器的解决方案
关于文件导出(下载)功能不兼容IE浏览器的解决方案 参考文章: (1)关于文件导出(下载)功能不兼容IE浏览器的解决方案 (2)https://www.cnblogs.com/padaleidelei ...
- GDI对象存储和查看lib文件导出函数
GDI对象存储 C++对象通常存储在栈.堆或者由应用程序通过定制的新操作符分配的任何地址空间里.基本上,它总是存放在用户模式的地址空间里,除非我们正在讨论内核模式设备驱动程序. Win ...
- php excel文件导出之二 图像导出
PHP文件导出 之图像 和 文字同一时候导出 事实上之前写了个php文件导出.跟这个极为相似,由于项目须要对图像进行导出.查询一番.又写了一个, 这个能实现图像的导出(仅仅能是本地图像,不能使用远程图 ...
- asp.net导出excel-一行代码实现excel、xml、pdf、word、html、csv等7种格式文件导出功能而且美观-SNF快速开发平台...
分享: 腾讯微博 新浪微博 搜狐微博 网易微博 腾讯朋友 百度贴吧 豆瓣 QQ好友 人人网 作者:王春天 原文地址:http://www.cnblogs.com/spring_ ...
- Markdown文件导出为HTML的小程序
Markdown文件导出为HTML的小程序 为什么做 最近把一些学习经验记下来,总结成MarkDown文件,不知不觉已经有12篇了. Sublime Text 的 MarkDown Preview 插 ...
- 导出文件_一招解决PDF文件导出图片
将PDF文件保存为高清图片是经常需要进行的保存方式之一,因为PDF文件虽然安全性高,但是相比较图片而言,还是不易进行查看的,那么如何将PDF文件导出图片呢?以前也了解过很多方法,不过最好的当然不是截图 ...
- hdfs文件如何导出到服务器,[Hadoop] 如何将 HDFS 文件导出到 Windows文件系统
介绍如何在 Windows 环境中, 将保存在 HDFS 上的文件导出到本机上 数据导入到 HDFS 后 当然也要有方法将数据从 HDFS 导出到本机系统上 在 HADOOP JAVA API 所提供 ...
最新文章
- 忍不住要发感慨,我的这个罗技鼠真好用...
- 使用.htaccess删除.html扩展名_Visual Studio Code | 从下载安装到使用!
- C语言中低位存放,C语言 大端小端存储解析以及判断方法
- 传递参数命令——xargs
- matlab simulink笔记04——switch模块
- java货物进销管理系统_java实验 货物进销管理系统
- 天堂里的游戏(51Nod-1417)
- 黑客入侵交警计算机系统删交通违法记录牟利
- android edittext的监听,android editText 监听事件
- 数据分析数据可视化(一)
- 吴恩达机器学习笔记——线性代数知识回顾、梯度下降、多项式线性回归、正则方程
- php怎么将农历转换成公历,php 公历农历如何实现转换
- 后端码农谈前端(CSS篇)第二课:CSS的5个来源
- scrapy爬虫实例:凤凰网
- 合肥市直计算机知识pdf,事业单位计算机专业知识整理(全)-20210419115129.pdf-原创力文档...
- w7设置双显示器_Win7双显示器怎么设置方法 Win7双显示器设置方法
- 先进先出页面置换算法的模拟(c++实现)
- Gitlab CI/CD Sonar 集成简版
- BUUCTF--[网鼎杯 2020 半决赛]AliceWebsite
- Java根据生日计算年龄
热门文章
- 基于python的停车场管理系统的设计与实现/智能停车管理系统
- UNIX 标准化 --ISO C标准 IEEE POSIX 标准 Single Unix Specification(SUS)
- win10清理c盘_系统C盘磁盘空间不够用的解决办法
- flume学习之一 是什么,主要应用在什么场景
- 心流状态---人们做事时内心的一种状态
- 阅读笔记:Blindly Assess Image Quality in the Wild Guided by A Self-Adaptive Hyper Network
- 【语音算法】语音的预处理--端点检测
- python实现绘制ROC曲线寻找指标最佳诊断临界值
- 大数据归档-冷热数据分离
- configure: error: cannot run /bin/bash config/config.sub 解决configure配置问题