3. 读取地图

本贴最后更新于 2564 天前,其中的信息可能已经渤澥桑田

流星里地图文件读取出来需要解析 gmb 文件和 des 文件,部分模型可能与 gmc 相关
类似假设点击第一关 炎硫岛 就会触发如下逻辑
读取 sn14.des,为什么是这一个是因为 meteor.res 里指定的
读取 sn14.gmb
des 文件描述了这个关卡里的实体和场景物品列表[虚体]
释义 sn14.des
SceneObjects 66 DummeyObjects 92 场景实体有 66 个 场景物品有 92 个
Object Plane01 物品名称
{
Position: 42.823 13.902 -14.560 位置世界变换
Quaternion: -1.000 0.000 0.000 0.000 旋转世界变换
TextureAnimation: 0 0.000 0.000 UV 动画速度
Custom:自身属性
{
}
}
一般来说 des 文件里每一个实体的模型数据都在 gmb 文件里可以找到,而且坐标,旋转等无需设置,gmb 里的坐标即为世界坐标系,已经跟你算好了
gmb 和 des 是很大关系的,有了世界变换矩阵,很容易就可以将在 gmb 里的顶点数据转换到模型空间,然后再在 u3d 里设置 gameobject 的世界变换矩阵

(2 种有什么区别?)
解释一下,一种是一个 gameObject,放在原点,然后添加 MeshFilter 组件,组件上的 Mesh 顶点数据,与 gmb 文件里一样,但是这种时候,一旦此物体绕 Y 轴旋转,那么就是绕原点过 Y 轴转动
如果是一个 gameObject 设置为 des 文件里描述的坐标,那么其就可以绕自身的轴心过 Y 轴转动,不同的是他的 MeshFilter 里的 Mesh 顶点数据,需要通过 gmb 里的顶点,通过世界变换矩阵的逆矩阵算出来

注意看右上角,坐标

注意看右上角,坐标

场景物品,指的是,属性箱子,武器箱子,酒坛,板凳等一些场景上与玩家发生交互的动态物品,这部分数据一般在 cmodel 下有其对应的 des 文件描述

要用 U3D 里显示一个地图,最好的办法是在编辑状态下调用加载地图函数,然后贴图或者其他不正确的地方,由于地图已经在编辑状态下的场景中,所以我们可以随便调整
还是使用上次创建的工程
要加载地图,数据是必不可少的,类似 des,gmb 还有地图上模型贴图,都要放到 Resources 目录下。
其次,des 文件和 gmc 文件以及 gmc 文件,都需要在后缀上加入.bytes,这个是 u3d 读取自定义数据的方法,如果不清楚可以下载源工程查看目录结构

新建一个编辑器类 LoadInspector 放在"Assets/Meteor/Editor/"目录下
新建一个 MapLoader 类放在"Assets"目录下,此类用于加载地图的静态部分
新建一个 Loader 类放在"Assets"目录下,此类用于加载地图的动态部分
在 MapLoader 类里增加一个接口,我希望加载指定的地图的时候,就读取指定的地图到我的此场景内,并且把所有地图元素添加到一个地图根节点上
于是在 MapLoader 类里设计 public void LoadMap(int level)接口
在 Loader 类里设计 public void LoadSceneObjs(int level)接口

在 LoadInspector 类里添加

[CustomEditor(typeof(Loader))]
public class LoadInspector : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
Loader myTarget = (Loader)target;
if (GUILayout.Button("AddSceneObj"))
{
myTarget.LoadSceneObjs(myTarget.LevelId);
}
}
}
[CustomEditor(typeof(MapLoader))]
public class MapLoaderInspector : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
MapLoader myTarget = (MapLoader)target;
if (GUILayout.Button("Load"))
{
myTarget.LoadMap(myTarget.levelId);
}
}
}
新建一个场景叫 MapLoader,创建一个空物体(Map),放在原点(0,0,0)各项属性都重置,无位置,旋转,缩放为 1
在这个物体上加上我们创建的 2 个组件类,一个 MapLoader,一个 Loader
在解读一个地图前,我们需要定义一些资源解析类
DesLoader,GmbLoader,GmcLoader
由于代码量还是有一些,所以还是放图和工程吧

由于原本的游戏工程关联性比较强,所以一些还未实现的模块类似脚本模块,暂时注释起来了,这个工程只加载了地图和场景道具
而且内置的表格数据,关卡 id 15 对应的炎硫岛地图,所以里面的 id 值都填的 15 地图表格文件为 fubenbase.txt,第一个就是 id goodlist 就是关卡的物品列表 sn14 之类的

还是说几点。
第一。由于任意一个关卡,可能引用到任意模型,等数据,所以整个模型,以及贴图等资源都得放到工程里,所以会导致工程比较大【此工程只导入了 sn14 的地图贴图,要导入其他的地图,需要自行导入贴图以及 des gmb 文件】

第二。由于配置里写明了有些模式下,一些物品是不应该出现的,但是工程里是全部显示,所以可能与游戏里剧情模式下物品不是一致的

第三。流星里的 shader 和灯光是全部忽略了的,所以地图和实际显示不一致,这个要自己按照原本流星的 shader 来调整,这部分由于不是太熟悉动态控制创建 shader 并且设置二层的叠加模式,以及一些参数,所以都忽略了
(我个人知道的都是事先写好一个模式的 shader 来使用,如果是这样,就需要把流星使用的 shader 列一个表,按照每个类型的 shader 一个个来写。不过这样比较耗时,每种 shader 组合的方式(参数,包括有无 uv 动画,是否双面,是否透明,以及叠加模式等等)也是太多)

好了,附上一张图

工程地址
http://pan.baidu.com/s/1gfh8tph

代码里有个 BUG,那就是不但实体名称要相同而且实体的序号也要和 gmb 里的模型序号相同,否则 2 个同名称的实体,会导致模型错乱,在皇天城,有二座屋子的楼顶会因此无法正常显示[只需要序号相同,客户端不会判定名字]

2017/10/12 更新
地图读取逻辑应该是
GMB 里每个对象有顶点组(右手坐标系)
DES 文件里有该对象的世界变换矩阵(右手坐标系)
读取时,先用顶点按照 世界变换矩阵的逆矩阵,变换到自身坐标系
然后创建一个 GameObject。添加 MeshFilter 时,把变换到自身坐标系的数据写进其 Mesh 中
然后设置该 GameObject 的世界变换矩阵为 Des 中该对象的一样(坐标系要转换)
这样再针对材质和 Mesh 用 AssetDataBase.CreateAsset(mat[x], "xx.mat") CreateAsset(mesh[x], "xx.asset")存储到本地目录中
这样任意一个地图加载后,如果要其中的某个子物件就可以直接找到 mesh 使用了,很容易就可以修改地图

保存材质列表,需要说一下,一般流星的地图,会这样设计材质引用
首先是材质列表 简单来说,就是一个 unlit/texture 加他指定的一张贴图
其次是 shader 列表
这样我们先生成 与材质列表数量一样多的材质,Material[] mat = new Material[gmb.TexturesCount];
然后对每个材质,赋上贴图
然后针对每个 Mesh 的每个三角面,都会引用一个 shader,而这个 shader 里又会指明用哪个序号的材质,这样每个 Mesh 的每个子网格都有一个材质球和一个 shader 共同起作用。
材质球记录了贴图等一些 shader 相关属性的数据,shader 决定 blend 算法,以及是否双面 透明度

假设以金华城的一个屋子 ian1633 作为示例
读取 sn13.gmb
会得到其中有
45 张贴图

我们创建 45 个材质

	   string shaders = "Unlit/Texture";
    //shaders = "Mobile/Diffuse";
    Material[] mat = new Material[gmb.TexturesCount];
    for (int x = 0; x < gmb.TexturesCount; x++)
    {
        mat[x] = new Material(Shader.Find(shaders));
        string tex = gmb.TexturesNames[x];
        int del = tex.LastIndexOf('.');
        if (del != -1)
            tex = tex.Substring(0, del);
        Texture texture = Resources.Load<Texture>(tex);
        //这里的贴图可能是一个ifl文件,这种先不考虑,手动修改
        if (texture == null)
            Debug.LogError("texture miss:" + tex);
        mat[x].SetTexture("_MainTex", texture);
        mat[x].name = string.Format("{0:D2}_{1:D2}", level, x);
        AssetDatabase.CreateAsset(mat[x], "Assets/Materials/" +  level + "/" + mat[x].name + ".mat");
        AssetDatabase.Refresh();
    }

48 个 shader

然后这个 mesh 引用了 22,16,15,17,19,这 5 个 shader
22 号引用的第 20 号贴图 贴图名称 sn13h07.jpg
16 号引用的第 15 号贴图,贴图名称 sn13h03.jpg
...

这样通过引用贴图,实际就是找到了对应的材质球,然后赋给网格材质球数组就可以了
List targetMat = new List();
targetMat.Add(mat[shader 数据里的贴图序号]);
MeshRenderer mr = objMesh.AddComponent();
mr.materials = targetMat.ToArray();
这样网格就可以勉强显示出贴图了(shader 里其他的参数对效果起了很大影响,但是在这里统一使用的是 unlit/texture 无光照贴图,这样地图上很多东西显示还是不正常的)

举个例子,在地图里有一些阴影贴图,代表模型受光照后投射到地面(或其他模型)上的影子。
还是用金华城举例子
他第二个元件就是
sd003,命名上就有 shadow003 缩写的示意,他是一个桥下的阴影
所以我们在之前的基础上给这个模型的材质,换一个 shader 用来显示阴影
shader 分有光和无光跟光照有关系。
总之现在的手游采用的方式都是 场景静态物烘产生 Lightmap,动态物用 light probe 打区域灯,角色用 projector 做投影。
完毕后让 sd003 的材质球使用这个 shader,然后在材质球参数上调整 Times 参数,就可以看到这个阴影贴图,会变暗或者变亮,看上去就好像阳光照在其上的物体所形成的阴影一样

Times 参数很大,导致很暗

调整 shader 的参数 Times 后像阴影了

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    86 引用 • 122 回帖 • 625 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 3 关注
  • abitmean

    有点意思就行了

    29 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 733 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 376 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    209 引用 • 2031 回帖
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    167 引用 • 1513 回帖
  • webpack

    webpack 是一个用于前端开发的模块加载器和打包工具,它能把各种资源,例如 JS、CSS(less/sass)、图片等都作为模块来使用和处理。

    41 引用 • 130 回帖 • 261 关注
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    408 引用 • 3574 回帖
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 633 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 175 关注
  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    125 引用 • 169 回帖 • 1 关注
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    351 引用 • 1814 回帖
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖 • 43 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 483 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    186 引用 • 318 回帖 • 302 关注
  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    198 引用 • 550 回帖
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    311 引用 • 546 回帖
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 399 关注
  • CodeMirror
    1 引用 • 2 回帖 • 129 关注
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 27 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 9 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    200 引用 • 120 回帖
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 531 关注
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 167 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 638 关注