3. 读取地图

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

流星里地图文件读取出来需要解析 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 后像阴影了

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 22 关注
  • 以太坊

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

    34 引用 • 367 回帖 • 3 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 8 关注
  • OAuth

    OAuth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是 oAuth 的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 oAuth 是安全的。oAuth 是 Open Authorization 的简写。

    36 引用 • 103 回帖 • 8 关注
  • 创业

    你比 99% 的人都优秀么?

    82 引用 • 1398 回帖
  • flomo

    flomo 是新一代 「卡片笔记」 ,专注在碎片化时代,促进你的记录,帮你积累更多知识资产。

    3 引用 • 82 回帖 • 2 关注
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 60 回帖 • 461 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖 • 1 关注
  • 强迫症

    强迫症(OCD)属于焦虑障碍的一种类型,是一组以强迫思维和强迫行为为主要临床表现的神经精神疾病,其特点为有意识的强迫和反强迫并存,一些毫无意义、甚至违背自己意愿的想法或冲动反反复复侵入患者的日常生活。

    15 引用 • 161 回帖 • 1 关注
  • CAP

    CAP 指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

    11 引用 • 5 回帖 • 566 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 596 关注
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    324 引用 • 1395 回帖 • 2 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 2 关注
  • BND

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

    107 引用 • 1281 回帖 • 25 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 345 关注
  • 运维

    互联网运维工作,以服务为中心,以稳定、安全、高效为三个基本点,确保公司的互联网业务能够 7×24 小时为用户提供高质量的服务。

    148 引用 • 257 回帖
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 592 关注
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    10 引用 • 54 回帖 • 127 关注
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    106 引用 • 152 回帖
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 497 关注
  • Kafka

    Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是现代系统中许多功能的基础。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。

    35 引用 • 35 回帖
  • 音乐

    你听到信仰的声音了么?

    59 引用 • 509 回帖
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    51 引用 • 37 回帖
  • 开源

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

    396 引用 • 3416 回帖 • 1 关注
  • Mobi.css

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

    1 引用 • 6 回帖 • 697 关注