PLATEAUのデータは以下からダウンロード
FBXがよい感じだった
図郭マップで必要な区画のデータを確認して使うイメージ
FBXダウンロードデータの内容
bldg
→建物。lod1は軽いけどテクスチャ貼られてない。lod2はテクスチャあり
brid
→高架道路とか橋とか
dem
→地面。テクスチャはない;;
tran
→道の線。地図みたいな
unityにはlod2を使うけど重すぎでスマホで動かないので軽量化を行う
Macなので結論としてはMeshBakerを使った
MeshBakerを使った軽量化の手順
アセットをいれたら GameObject > Create Other > Mesh Backer から
TextureBaker and MultiMeshBaker を選ぶ
If your source objects exceed 64k vertices use a TextureBaker & MultiMeshBaker
ソース オブジェクトの頂点が 64k を超える場合は、Multiで
そうで無い場合はTextureBaker & MeshBakerでよい
ヒエラルキーにTextureBakerができるのでそれのInspecterをみる
Open Tools For Adding Objectsボタンでウィンドウを開く
Search For Meshes To Add タブを表示して
Exclude meshes with out-of-bounds UVs のチェックを外す
軽量化したいファイルをヒエラルキーに配置して、親オブジェクトでまとめておく。それを選択した状態で
Add Selected Meshes To Targetボタンを押す
最初のヒエラルキーにTextureBaker(0)のInspecterのObjects To Be Combinedにデータがセットされる。↑上記では4731
その下のCreate Empty Assets For Combined Materialボタンを押して任意の場所にデータを作る。→Texture Back ResultとCombined Mesh Materialにデータがセットされる。
Max Atlas Sizeを減らしたらガビった。一旦8192で
Back Materials Into Combined Material ボタンを押す。しばらく待つ。
完了したらヒエラルキーのTextureBaker(0)の中のMultiMeshBakerを選ぶ
InspectorでOutputをBack Into Prefabにする
ヒエラルキーにEmptyオブジェクトを作成してProjectにドラッグしてプレハブ化する
それをCombined Mesh Prefabにセットする
Use Shared SettingsはNoneにする
Backを押す。しばらくまつ。
ヒエラルキーに作成したプレハブに軽量化されたデータができている。元のFBXは非表示にして確認してみる。
最初のドローコールが3457とかだったのが64!?
軽量化後
WARNING -> applicationDidReceiveMemoryWarning()
対象区画のbldgとbridとdemをセットで設置して、Macでは実行できたけどiPhone実機ではメモリ不足で動かず・・原因を究明すると
demでした!1枚meshで問題ないと思ってたら..
広大な地面の1枚mesh。blenderで編集しようとしたけど超大量の頂点があってめちゃヘビー。平らな板だと街のビルがところどころ浮いちゃうし。
ということでdemの地面meshをterrainに変更した。
Special Thanks!↓
上記より
Object2Terrain.cs
using UnityEngine;
using UnityEditor;
public class Object2Terrain : EditorWindow
{
[MenuItem("Terrain/Object to Terrain", false, 2000)]
static void OpenWindow()
{
EditorWindow.GetWindow<Object2Terrain>(true);
}
private int resolution = 512;
private Vector3 addTerrain;
int bottomTopRadioSelected = 0;
static string[] bottomTopRadio = new string[] { "Bottom Up", "Top Down" };
private float shiftHeight = 0f;
void OnGUI()
{
resolution = EditorGUILayout.IntField("Resolution", resolution);
addTerrain = EditorGUILayout.Vector3Field("Add terrain", addTerrain);
shiftHeight = EditorGUILayout.Slider("Shift height", shiftHeight, -1f, 1f);
bottomTopRadioSelected = GUILayout.SelectionGrid(bottomTopRadioSelected, bottomTopRadio, bottomTopRadio.Length, EditorStyles.radioButton);
if (GUILayout.Button("Create Terrain"))
{
if (Selection.activeGameObject == null)
{
EditorUtility.DisplayDialog("No object selected", "Please select an object.", "Ok");
return;
}
else
{
CreateTerrain();
}
}
}
delegate void CleanUp();
void CreateTerrain()
{
//fire up the progress bar
ShowProgressBar(1, 100);
TerrainData terrain = new TerrainData();
terrain.heightmapResolution = resolution;
GameObject terrainObject = Terrain.CreateTerrainGameObject(terrain);
Undo.RegisterCreatedObjectUndo(terrainObject, "Object to Terrain");
MeshCollider collider = Selection.activeGameObject.GetComponent<MeshCollider>();
CleanUp cleanUp = null;
//Add a collider to our source object if it does not exist.
//Otherwise raycasting doesn't work.
if (!collider)
{
collider = Selection.activeGameObject.AddComponent<MeshCollider>();
cleanUp = () => DestroyImmediate(collider);
}
Bounds bounds = collider.bounds;
float sizeFactor = collider.bounds.size.y / (collider.bounds.size.y + addTerrain.y);
terrain.size = collider.bounds.size + addTerrain;
bounds.size = new Vector3(terrain.size.x, collider.bounds.size.y, terrain.size.z);
// Do raycasting samples over the object to see what terrain heights should be
float[,] heights = new float[terrain.heightmapWidth, terrain.heightmapHeight];
Ray ray = new Ray(new Vector3(bounds.min.x, bounds.max.y + bounds.size.y, bounds.min.z), -Vector3.up);
RaycastHit hit = new RaycastHit();
float meshHeightInverse = 1 / bounds.size.y;
Vector3 rayOrigin = ray.origin;
int maxHeight = heights.GetLength(0);
int maxLength = heights.GetLength(1);
Vector2 stepXZ = new Vector2(bounds.size.x / maxLength, bounds.size.z / maxHeight);
for (int zCount = 0; zCount < maxHeight; zCount++)
{
ShowProgressBar(zCount, maxHeight);
for (int xCount = 0; xCount < maxLength; xCount++)
{
float height = 0.0f;
if (collider.Raycast(ray, out hit, bounds.size.y * 3))
{
height = (hit.point.y - bounds.min.y) * meshHeightInverse;
height += shiftHeight;
//bottom up
if (bottomTopRadioSelected == 0)
{
height *= sizeFactor;
}
//clamp
if (height < 0)
{
height = 0;
}
}
heights[zCount, xCount] = height;
rayOrigin.x += stepXZ[0];
ray.origin = rayOrigin;
}
rayOrigin.z += stepXZ[1];
rayOrigin.x = bounds.min.x;
ray.origin = rayOrigin;
}
terrain.SetHeights(0, 0, heights);
EditorUtility.ClearProgressBar();
if (cleanUp != null)
{
cleanUp();
}
}
void ShowProgressBar(float progress, float maxProgress)
{
float p = progress / maxProgress;
EditorUtility.DisplayProgressBar("Creating Terrain...", Mathf.RoundToInt(p * 100f) + " %", p);
}
}
地面をterrainに変更したら大丈夫でした!
そのほかのポイント
・ビルのmeshで少し修正したいところがあって直接unityのprobuilderを使って修正したら重くて変更できなくなった。→重いオブジェクトが存在するファイルではprobuilderは使わないほうがよい
Not allowed to call RecalculateNormals() on mesh 'surfaceMember(Clone)' MeshBakerを使うときに、元ファイルのビルのマテリアルがなぜか(clone)とか(instance)になっているとうまくいかないので、元のbldgのプレハブを置き直すとマテリアルの(instance)が取れてエラーもなくなった
コメント