3. 读取地图

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

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

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 559 关注
  • 百度

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

    63 引用 • 785 回帖 • 164 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • 友情链接

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

    24 引用 • 373 回帖
  • Caddy

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

    12 引用 • 54 回帖 • 159 关注
  • Postman

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

    4 引用 • 3 回帖 • 7 关注
  • 电影

    这是一个不能说的秘密。

    121 引用 • 604 回帖 • 1 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 464 关注
  • Swift

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

    36 引用 • 37 回帖 • 535 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 161 关注
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 15 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 683 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 53 关注
  • 工具

    子曰:“工欲善其事,必先利其器。”

    288 引用 • 734 回帖 • 2 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 159 关注
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    88 引用 • 1235 回帖 • 410 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    132 引用 • 1114 回帖 • 125 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1737 回帖 • 1 关注
  • Jenkins

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

    53 引用 • 37 回帖 • 3 关注
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    91 引用 • 751 回帖 • 1 关注
  • 自由行
    4 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    77 引用 • 430 回帖 • 1 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    171 引用 • 512 回帖