reference——World Streamer Manual.pdf

chapter4——world streamer details and settings

Streaming solution consists of:

scene splitter——this tools used to create virtual grids and layers from your scene objects. Scene splitter also generates scenes from virtual grid elements. During scene generating process scene splitter create also scene collections which we called “SC+Prefix”. Scene collection is created for each layer.

Scene collections. This prefabs which we call “SC+Prefix” hold information about scenes, grid element size, world size and much more details that are useful for streaming process. As we mentioned they are formed and refreshed by scene splitter or local area updater tool, during scene generation process.

Scene objects. They are connected to scene collections “SC+Prefix”, they are formed and refreshed by scene splitter or local area updater tool during scene generation process.

Streamer prefabs (Major, Minor). They hold and use scene collections “SC+Prefix” in your “Gameplay” scene and they stream content according to options that you set. First streamer at your scene should be Major, it should be used for:

  • terrains
  • big objects (if you don’t stream terrains)
  • all objects (if you use only one layer)
    All other streamer should be minor.

Collider streamers. They holds scene which will be loaded after chosen object hit his collider.

……

4.1 Scene splitter
This tool is used to split your world objects into virtual grids and prepare them into streaming. As objects we mean: models, objects, lights, particles, terrains. Every grid element “grid eye” will be a “pack” of data that World Streamer load into memory as one object.

We always advice you to open “scene splitter” at empty scene that we will call “Work” scene. You should copy into it whole content that you want to stream. Directional lights, player, UI should be at your “Gameplay” scene, so remove them from this “Work” scene or hide during splitting process. If you will properly set your layers, this objects could stay here.

总结:就是要区分工作场景和游戏运行场景,我们要把所有需要划分的物体复制到工作场景中去,而对于灯光、玩家、UI都应该保留在游戏运行场景中,他们不参与流的划分。还有一种方法是,在工作场景中把他们隐藏起来,后者如果你设置好划分的层之后,确保他们不参与划分也是可以的。

To open “Scene Splitter” window click at “World Streamer"→"Scene Splitter”


When you open “Scene Splitter” window you will find 2 sections.
Scene Generation section will prepare your objects to stream. In this section you will generate layers, scenes, virtual grids and scene collections from this virtual grids.
Build Settings section could easily and massively add your just generated/refreshed scenes to build settings.

scene generation options:

add layer button creates a group/layer of objects. layer separates specified objects from the rest of objects, this layer/group will be streamed independently from others. as an example of layers/group we could use: terrains, small models, big models, medium models, far low poly terrains, lights, particles, fx. please also read about layer order in this section, to get very important info about how scene splitter recognize your objects. you mush have at least one layer to split your scene.

split X, ,split Y, split Z buttons gives you ability to chose what axis will be used during virtual grid generation. if you create space game you will probably check x,y,z. if you create RTS of RPG, car game you probably will check x and z because height is not so important. for unity terrain you should check only x and z. if you want to unload terrains when player is to high over terrains you could check y too.

x size, y size, z size values are responsible for size of one virtual grid element eye. you are creating virtual grid which is based on your checked split x, split y, split z axis and their size which you chose right here. grid element size should be estimated by you. u could easily change it and test different values. they should not be to big because you will load too much objects at once. they should not be to small because you will have huge amount of scenes, which are probably unnecessary. you have to confront that also to object size, if your big building is 200x200 units u should not stream it in 20x20 grid element size. but u could steam a group of these buildings in 1000x1000 virtual grid element of course if they are not heavy as one grid element.

for unity terrain x size and z size should/must be the same size as terrain length and width.

You could visualize your virtual grid element size by using our gizmo. After you click “Split Scene” or “S” button, when you click at virtual grid element that system just created, you will see its boundaries. Before this you have to fill all info about virtual grid and layer to create first split.

GameObject Prefix is really important value. While splitting system is searching for objects, because it wants to put them into correct layers, it’s checking each object’s name. If you will leave game object prefix as empty, system will put all objects at the scene into one layer.
If for Example.1 you want to put your unity terrains into layer “Terrain_Lod0”, fill game object prefix for example by “Terrain”. Add “Terrain” word at beginning of each terrain object at the scene.

===========================================================================

场景分割的代码:

void SceneChanged ()
{currentScene = EditorSceneManager.GetActiveScene ().path;

获取当前打开场景的路径:

sceneSplitterSettings = FindObjectOfType (typeof(SceneSplitterSettings)) as SceneSplitterSettings;
if (sceneSplitterSettings == null)CreateSettings ();

创建这个物体,并附加脚本:SceneSplitterSettings

SceneCollection[] sceneCollections = FindObjectsOfType (typeof(SceneCollection)) as SceneCollection[];
currentCollections.Clear ();
listSizeCollections = 0;
sceneLayers.Clear ();
if (sceneCollections.Length > 0) {if (sceneLayers == null)sceneLayers = new List<SceneCollection> ();sceneLayers.AddRange (sceneCollections);splits = new List<Dictionary<string,GameObject>> ();foreach (var item in sceneLayers) {if (item.transform.parent != sceneSplitterSettings.transform)item.transform.parent = sceneSplitterSettings.transform;splits.Add (new Dictionary<string, GameObject> ());}}

SceneCollection和SceneLayer是同一个概念。

 foreach (var layer in sceneLayers) {FindCollection (layer);}currentColliders.Clear ();currentColliders.AddRange (FindObjectsOfType (typeof(ColliderScene)) as ColliderScene[]);listSizeColliders = currentColliders.Count;
 public void FindCollection (SceneCollection layer){string scenesPath = this.sceneSplitterSettings.scenesPath + layer.prefixScene + "/";GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath (scenesPath + "SC_" + layer.prefixScene + ".prefab", typeof(GameObject));if (prefab != null) {SceneCollection sceneCollection = prefab.GetComponent<SceneCollection> ();if (!currentCollections.Contains (sceneCollection))currentCollections.Add (sceneCollection);listSizeCollections = currentCollections.Count;}}

真正的分割:

foreach (var layer in sceneLayers) {SplitScene (layer);}
 void SplitScene (SceneCollection layer){warning = "";splits [layer.layerNumber] = new Dictionary<string, GameObject> ();layer.xLimitsx = int.MaxValue;layer.xLimitsy = int.MinValue;layer.yLimitsx = int.MaxValue;layer.yLimitsy = int.MinValue;layer.zLimitsx = int.MaxValue;layer.zLimitsy = int.MinValue;GameObject[] allObjects = UnityEngine.Object.FindObjectsOfType<GameObject> ();FindSceneGO (layer.prefixScene, allObjects, splits [layer.layerNumber]);ClearSceneGO (layer);
void FindSceneGO(string prefixScene, GameObject[] allObjects, Dictionary<string, GameObject> splits)
{foreach(var item in allObjects){if(item == null) continue;if(item.GetComponent<SceneSplitManager>() == null) continue; //找划分之后的根节点if(item.transform.parent!=null || !item.name.StartsWith(prefixScene) continue;GameObject go;string sceneID = "";sceneID = item.name.Replace(prefixScene, "");if(!splits.TryGetValue(sceneId, out go))splits.Add(sceneID, item);}
}

void ClearSceneGO(SceneCollection layer)
{ObjectsParent[] objectsParents = FindObjectsOfType<ObjectsParent>();ObjectsParent objectsParent = null;}

首先,ClearSceneGO这个函数的大体作用是啥?
比如下面的图:

这个CubeRoot上面有一个脚本:ObjectsParent,它的gameObjectPrefix=Cube
第二个SphereRoot,它的它的gameObjectPrefix=Sphere

而此时的layer情况:

于是,我们的CubeA/B/C/D,会被分割为:

而在每次分割的时候,都会产生多个类似于上面的Scene1_xx_xx的节点。而第二次再进行分割的时候,会先把Scene1_xx_xx这些节点删除,在删除之前,CubeA/B/C/D都会被再次回到CubeRoot这个节点下。

所以ClearSceneGO的含义就是将现有场景中的Scene1_xx_xx删除,将其子节点还原到之前未分割的状态。

ok,再次回到函数:

void ClearSceneGO (SceneCollection layer)
{ObjectsParent[] objectsParents = FindObjectsOfType<ObjectsParent> ();ObjectsParent objectsParent = null;foreach (var parent in objectsParents) {if (parent.gameObjectPrefix == layer.prefixName) {objectsParent = parent;break;}}

第一句是找到所有带有ObjectsParent脚本的物体,然后定义一个变量ObjectsParent,遍历所有父物体,找到一个和当前layer的前缀相同的父物体,将此父物体作为将来要分离的子物体的父物体。比如上面的截图中,CubeRoot上ObjectsParent脚本的前缀变量是Cube,而SphereRoot的ObjectsParent脚本的前缀变量是Sphere,所以CubeA/B/C/D都会重置为CubeRoot的子物体,而不是SphereRoot的子物体。


List<string> toRemove = new List<string> ();foreach (var item in splits [layer.layerNumber]) {if (item.Value.GetComponent<SceneSplitManager> ()) {

定义一个将要移除的key列表,遍历当前层的下面的所有物体,如果物体上有组件SceneSplitManager,表面这个是分割后的物体的根节点,就比如上面的分割之后的Scene1_xx_xx的物体,因为分割之后,其上有这个脚本。

Transform splitTrans = item.Value.transform;
foreach (Transform splitChild in splitTrans) {if (objectsParent != null && (splitChild.name.StartsWith (objectsParent.gameObjectPrefix) || string.IsNullOrEmpty (objectsParent.gameObjectPrefix)))splitChild.SetParent (objectsParent.transform, true);elsesplitChild.parent = null;
}

splitTrans指向的就是Scene1_xx_xx的这个根节点,遍历其子节点,如果上面的objectsParent不为空,也就是CubeRoot不为空,则判断子物体的名字是不是以objects的前缀开头,或者objectsParent的前缀就是空,则将这个子物体的父物体设置为CubeRoot。
比如上面的CubeA/B/C/D就会设置它们的父物体为CubeRoot; 而如果objectsParent为null,则CubeA/B/C/D的父亲就为null。

while (splitTrans.childCount > 0) {foreach (Transform splitChild in splitTrans) {if (objectsParent != null && (splitChild.name.StartsWith (objectsParent.gameObjectPrefix) || string.IsNullOrEmpty (objectsParent.gameObjectPrefix)))splitChild.SetParent (objectsParent.transform, true);elsesplitChild.parent = null;}}

这段代码,完成类似的功能,但是可以注释掉,因为重复了。

GameObject.DestroyImmediate (splitTrans.gameObject);toRemove.Add (item.Key);}}foreach (var item in toRemove) {splits [layer.layerNumber].Remove (item);}

遍历完成之后,删除Scenex_xx_xx类似的根节点,把当前的key加入的删除列表,最后,遍历删除列表,从split
中删除这些key:

继续SplitScene函数的讲解:

遍历当前的所有物体,如果item=null,continue。

if (item.GetComponent<SceneSplitManager> () != null || item.GetComponent<SceneCollection> () != null || item.GetComponent<SceneSplitterSettings> () != null|| item.GetComponent<ObjectsParent> () != null)continue;

如果物体上有组件SceneSplitManager组件,continue,因为它是已经是类似于上面的Scene_xx_xx的根节点了。
如果物体上有组件SceneCollection组件,continue,因为它是层所在的节点
如果物体上有组件SceneSplitterSettings组件,continue,因为它是层配置所在的节点
如果物体上有组件ObjectsParent组件,continue,因为它是物体的根节点

string itemId = GetID (item.transform.position, layer);
string GetID (Vector3 position, SceneCollection layer)
{int xId = (int)(Mathf.FloorToInt (position.x / layer.xSize));if (Mathf.Abs ((position.x / layer.xSize) - Mathf.RoundToInt (position.x / layer.xSize)) < 0.001f) {xId = (int)Mathf.RoundToInt (position.x / layer.xSize);}int yId = (int)(Mathf.FloorToInt (position.y / layer.ySize));if (Mathf.Abs ((position.y / layer.ySize) - Mathf.RoundToInt (position.y / layer.ySize)) < 0.001f) {yId = (int)Mathf.RoundToInt (position.y / layer.ySize);}int zId = (int)(Mathf.FloorToInt (position.z / layer.zSize));if (Mathf.Abs ((position.z / layer.zSize) - Mathf.RoundToInt (position.z / layer.zSize)) < 0.001f) {zId = (int)Mathf.RoundToInt (position.z / layer.zSize);}return (layer.xSplitIs ? "_x" + xId : "") +(layer.ySplitIs ? "_y" + yId : "")+ (layer.zSplitIs ? "_z" + zId : "");
}

根据节点的位置,层计算id。

string itemId = GetID (item.transform.position, layer);GameObject split = null;
if (!splits [layer.layerNumber].TryGetValue (itemId, out split)) {split = new GameObject (layer.prefixScene + itemId);SceneSplitManager sceneSplitManager = split.AddComponent<SceneSplitManager> ();sceneSplitManager.sceneName = split.name;sceneSplitManager.size = new Vector3 (layer.xSize != 0 ? layer.xSize : 100, layer.ySize != 0 ? layer.ySize : 100, layer.zSize != 0 ? layer.zSize : 100);sceneSplitManager.position = GetSplitPosition (item.transform.position, layer);sceneSplitManager.color = layer.color;splits [layer.layerNumber].Add (itemId, split);

如果splits不包含这个itemId的时候,则添加进去。
新创建一个物体,给物体添加一个脚本SceneSplitManager
赋值名字
赋值size
赋值颜色,主要是用来在gizmos中绘制区域使用。

 Vector3 splitPosId = GetSplitPositionID (item.transform.position, layer);if (layer.xSplitIs) {if (splitPosId.x < layer.xLimitsx) {layer.xLimitsx = (int)splitPosId.x;}if (splitPosId.x > layer.xLimitsy) {layer.xLimitsy = (int)splitPosId.x;}} else {layer.xLimitsx = 0;layer.xLimitsy = 0;}

获取位置之后,更新layer的各维度的最小值和最大值。
记得初始的时候,layer.xLimitsx 为最大值;layer.xLimitsy为最小值。然后进行更新。

World Streamer学习2相关推荐

  1. World Streamer学习4

    打开场景:Tutorial World Streamer - Advanced_Game_Float_Fix_Looped_Safe_Place 只显示一个: 选中这个物体之后: 提示将这个strea ...

  2. World Streamer学习5

    上一个篇的最后,我们已经彻底被源码中的计算物体坐标的地方搞晕了,这个真的不太好懂,幸好的断点下的地方比较准确,才促使这个问题得以解决. 首先,我们在这个地方输出一个log: 可以看到当角色的位置达到了 ...

  3. World Streamer学习1

    1.首先找到插件包,可以淘宝买个便宜的. 2.导入到unity项目:World Streamer v1.9.6.unitypackage 3.文件夹: 4.读World Streamer Manual ...

  4. 计算机操作系统 - 目录1

    目录 概述 进程管理 死锁 内存管理 设备管理 链接 参考资料 Tanenbaum A S, Bos H. Modern operating systems[M]. Prentice Hall Pre ...

  5. 计算机操作系统 - 目录

    计算机操作系统 概述 进程管理 死锁 内存管理 设备管理 链接 参考资料 Tanenbaum A S, Bos H. Modern operating systems[M]. Prentice Hal ...

  6. 香侬科技Service Streamer:加速深度学习Web服务、极大提高GPU利用率。| 百万人学AI评选

    2020 无疑是特殊的一年,而 AI 在开年的这场"战疫"中表现出了惊人的力量.站在"新十年"的起点上,CSDN[百万人学AI]评选活动正式启动.本届评选活动在 ...

  7. FFMPEG开源音视频项目学习汇总

    ~非常感谢雷霄骅老师的无私帮助,本文转载自:http://blog.csdn.net/leixiaohua1020/article/details/42658139~       本文汇总一下自己视音 ...

  8. Openvino学习之openvino2022.1版安装配置

    Openvino学习之openvino2022.1版安装配置 文章目录 Openvino学习之openvino2022.1版安装配置 前言 一.从安装角度看新版本的变化 二.安装 1.官网地址 2.安 ...

  9. ethereum-etl学习3

    ethereum-etl学习3 > ethereumetl stream --start-block 500000 -e block,transaction,log,token_transfer ...

最新文章

  1. 作用域,上下文,闭包
  2. Linux学习之一-从三个重要人物的故事和一张思维导图说起
  3. 数据库oracle 别名不能更新,数据库oracle改成mysql后Hibernate不能使用别名问题
  4. sqlserver 中事务与错误机制的处理
  5. 没有bug队——加贝——Python 练习实例 1,2
  6. 2020-06-05 原始套接字/AF_PACKET链路层访问
  7. ubuntu系统重启后桌面分辨率减小的原因及解决方法
  8. Hadoop设置任务执行队列及优先级
  9. form表单提交数据
  10. 连接服务器显示用户账户无效,发现MT4真实账户无效该怎么办?
  11. 现有VI 创建子VI(LabVIEW软件)
  12. 基于Android的医院预下单叫号排队系统
  13. 服务器编程之路:进无止境(下)
  14. 什么是互联网营销?看一篇这就够了
  15. 为了理想,因为爱情-开课第一天有感(鸡汤向)
  16. 11,MSI文件简介
  17. C#多线程工业源码 替代传统plc搭载的触摸屏 工控屏幕一体机直接和plc通信
  18. PostgreSQL密码重置方法
  19. 详解Git合并冲突——原因及解决 “Automatic merge failed; fix conflicts and then commit the result.“
  20. Android碎片化与兼容性问题的元凶

热门文章

  1. 使用PyTorch进行知识蒸馏的代码示例
  2. RTrPPG: An Ultra Light 3DCNN for Real-Time Remote Photoplethysmography
  3. 【观察】大数据3.0新时代 星环科技的思与行
  4. 关于SQL中的ASSERTION(某单位想举行一个小型的联谊会……)
  5. Swift - 判等
  6. pytorch版本RetinaFace人脸检测模型推理加速
  7. CorelDRAW2022新版首发功能曝光介绍
  8. win8连接wifi成功但受限制_连接wifi成功但受限制如何解决 连接wifi成功但受限制解决【步骤】...
  9. Android Studio 4.1.2 自定义 APP 启动图标样式步骤【APP开发之入门四】
  10. 使用Git对Word或Excel文件进行版本管理