891 lines
29 KiB
C#
891 lines
29 KiB
C#
using System.Text;
|
|
using GaiaCommon1;
|
|
using UnityEngine;
|
|
|
|
namespace Gaia
|
|
{
|
|
public class GaiaWorldManager
|
|
{
|
|
private Bounds m_worldBoundsWU;
|
|
|
|
private Vector3 m_worldBoundsWUMin;
|
|
|
|
private Vector3 m_worldBoundsWUMax;
|
|
|
|
private Vector3 m_worldBoundsWUSize;
|
|
|
|
private Bounds m_worldBoundsTU;
|
|
|
|
private Vector3 m_worldBoundsTUMin;
|
|
|
|
private Vector3 m_worldBoundsTUMax;
|
|
|
|
private Vector3 m_worldBoundsTUSize;
|
|
|
|
private Bounds m_worldBoundsNU;
|
|
|
|
private Vector3 m_worldBoundsNUMin;
|
|
|
|
private Vector3 m_worldBoundsNUMax;
|
|
|
|
private Vector3 m_WUtoTU = Vector3.one;
|
|
|
|
private Vector3 m_TUtoWU = Vector3.one;
|
|
|
|
private Vector3 m_TUtoNU = Vector3.one;
|
|
|
|
private Vector3 m_NUtoTU = Vector3.one;
|
|
|
|
private Vector3 m_WUtoNU = Vector3.one;
|
|
|
|
private Vector3 m_NUtoWU = Vector3.one;
|
|
|
|
private Vector3 m_NUZeroOffset = Vector3.zero;
|
|
|
|
private Vector3 m_TUZeroOffset = Vector3.zero;
|
|
|
|
private ulong m_boundsCheckErrors;
|
|
|
|
private Terrain[,] m_physicalTerrainArray;
|
|
|
|
private UnityHeightMap[,] m_heightMapTerrainArray;
|
|
|
|
private int m_tileCount;
|
|
|
|
public int TileCount => m_tileCount;
|
|
|
|
public Terrain[,] PhysicalTerrainArray
|
|
{
|
|
get
|
|
{
|
|
return m_physicalTerrainArray;
|
|
}
|
|
set
|
|
{
|
|
m_physicalTerrainArray = value;
|
|
}
|
|
}
|
|
|
|
public UnityHeightMap[,] HeightMapTerrainArray
|
|
{
|
|
get
|
|
{
|
|
return m_heightMapTerrainArray;
|
|
}
|
|
set
|
|
{
|
|
m_heightMapTerrainArray = value;
|
|
}
|
|
}
|
|
|
|
public Bounds WorldBoundsWU => m_worldBoundsWU;
|
|
|
|
public Bounds WorldBoundsTU => m_worldBoundsTU;
|
|
|
|
public Bounds WorldBoundsNU => m_worldBoundsNU;
|
|
|
|
public Vector3 WUtoTUConversionFactor => m_WUtoTU;
|
|
|
|
public Vector3 WUtoNUConversionFactor => m_WUtoNU;
|
|
|
|
public ulong BoundsCheckErrors
|
|
{
|
|
get
|
|
{
|
|
return m_boundsCheckErrors;
|
|
}
|
|
set
|
|
{
|
|
m_boundsCheckErrors = value;
|
|
}
|
|
}
|
|
|
|
public GaiaWorldManager()
|
|
{
|
|
}
|
|
|
|
public GaiaWorldManager(Terrain[] terrains)
|
|
{
|
|
Terrain terrain = null;
|
|
m_worldBoundsWU = default(Bounds);
|
|
m_worldBoundsTU = default(Bounds);
|
|
m_worldBoundsNU = default(Bounds);
|
|
string text = IsValidWorld(terrains);
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
Debug.LogError("GaiaWorldManager(terrains) ERROR" + text);
|
|
return;
|
|
}
|
|
for (int i = 0; i < terrains.Length; i++)
|
|
{
|
|
terrain = terrains[i];
|
|
Bounds bounds = new Bounds(terrain.transform.position, terrain.terrainData.size);
|
|
bounds.center += bounds.extents;
|
|
if (i == 0)
|
|
{
|
|
m_worldBoundsWU = new Bounds(bounds.center, bounds.size);
|
|
}
|
|
else
|
|
{
|
|
m_worldBoundsWU.Encapsulate(bounds);
|
|
}
|
|
Bounds bounds2 = default(Bounds);
|
|
m_WUtoTU = new Vector3((float)terrain.terrainData.heightmapResolution / terrain.terrainData.size.x, (float)(terrain.terrainData.heightmapResolution - 1) / Mathf.Max(terrain.terrainData.size.x, terrain.terrainData.size.z) * terrain.terrainData.size.y / terrain.terrainData.size.y, (float)terrain.terrainData.heightmapResolution / terrain.terrainData.size.z);
|
|
m_TUtoWU = new Vector3(1f / m_WUtoTU.x, 1f / m_WUtoTU.y, 1f / m_WUtoTU.z);
|
|
bounds2.center = Vector3.Scale(bounds.center, m_WUtoTU);
|
|
bounds2.size = Vector3.Scale(bounds.size, m_WUtoTU);
|
|
if (i == 0)
|
|
{
|
|
m_worldBoundsTU = new Bounds(bounds2.center, bounds2.size);
|
|
}
|
|
else
|
|
{
|
|
m_worldBoundsTU.Encapsulate(bounds2);
|
|
}
|
|
}
|
|
if (terrain != null)
|
|
{
|
|
m_TUtoNU = new Vector3(1f / m_worldBoundsTU.size.x, 1f / m_worldBoundsTU.size.y, 1f / m_worldBoundsTU.size.z);
|
|
m_NUtoTU = m_worldBoundsTU.size;
|
|
m_WUtoNU = Vector3.Scale(m_WUtoTU, m_TUtoNU);
|
|
m_NUtoWU = m_worldBoundsWU.size;
|
|
}
|
|
m_worldBoundsNU.center = Vector3.Scale(m_worldBoundsTU.center, m_TUtoNU);
|
|
m_worldBoundsNU.size = Vector3.Scale(m_worldBoundsTU.size, m_TUtoNU);
|
|
m_NUZeroOffset = Vector3.zero - m_worldBoundsNU.min;
|
|
m_TUZeroOffset = Vector3.zero - m_worldBoundsTU.min;
|
|
m_tileCount = (int)(m_worldBoundsNU.size.x * m_worldBoundsNU.size.z);
|
|
m_physicalTerrainArray = new Terrain[(int)m_worldBoundsNU.size.x, (int)m_worldBoundsNU.size.z];
|
|
m_heightMapTerrainArray = new UnityHeightMap[(int)m_worldBoundsNU.size.x, (int)m_worldBoundsNU.size.z];
|
|
for (int j = 0; j < terrains.Length; j++)
|
|
{
|
|
terrain = terrains[j];
|
|
Vector3 vector = WUtoPTI(terrain.transform.position);
|
|
m_physicalTerrainArray[(int)vector.x, (int)vector.z] = terrain;
|
|
}
|
|
m_worldBoundsWUMax = m_worldBoundsWU.max;
|
|
m_worldBoundsWUMin = m_worldBoundsWU.min;
|
|
m_worldBoundsWUSize = m_worldBoundsWU.size;
|
|
m_worldBoundsTUMax = m_worldBoundsTU.max;
|
|
m_worldBoundsTUMin = m_worldBoundsTU.min;
|
|
m_worldBoundsTUSize = m_worldBoundsTU.size;
|
|
m_worldBoundsNUMax = m_worldBoundsNU.max;
|
|
m_worldBoundsNUMin = m_worldBoundsNU.min;
|
|
}
|
|
|
|
public string IsValidWorld(Terrain[] terrains)
|
|
{
|
|
Terrain terrain = null;
|
|
Terrain terrain2 = null;
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
for (int i = 0; i < terrains.Length; i++)
|
|
{
|
|
terrain2 = terrains[i];
|
|
if (terrain == null)
|
|
{
|
|
terrain = terrain2;
|
|
}
|
|
if (terrain2.terrainData.size.x != terrain2.terrainData.size.z)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} is not a square {terrain2.terrainData.size.x} {terrain2.terrainData.size.z}");
|
|
}
|
|
if (terrain2.terrainData.size != terrain.terrainData.size)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} size does not match {terrain2.terrainData.size} {terrain.terrainData.size}");
|
|
}
|
|
if (terrain2.terrainData.heightmapResolution != terrain.terrainData.heightmapResolution)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} heightmapResolution does not match {terrain2.terrainData.heightmapResolution} {terrain.terrainData.heightmapResolution}");
|
|
}
|
|
if (terrain2.terrainData.alphamapResolution != terrain.terrainData.alphamapResolution)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} alphamapResolution does not match {terrain2.terrainData.alphamapResolution} {terrain.terrainData.alphamapResolution}");
|
|
}
|
|
if (terrain2.terrainData.baseMapResolution != terrain.terrainData.baseMapResolution)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} baseMapResolution does not match {terrain2.terrainData.baseMapResolution} {terrain.terrainData.baseMapResolution}");
|
|
}
|
|
if (terrain2.terrainData.detailResolution != terrain.terrainData.detailResolution)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} detailResolution does not match {terrain2.terrainData.detailResolution} {terrain.terrainData.detailResolution}");
|
|
}
|
|
if (terrain2.terrainData.alphamapLayers != terrain.terrainData.alphamapLayers)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} alphamapLayers does not match {terrain2.terrainData.alphamapLayers} {terrain.terrainData.alphamapLayers}");
|
|
}
|
|
if (terrain2.terrainData.detailPrototypes.Length != terrain.terrainData.detailPrototypes.Length)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} detailPrototypes.Length does not match {terrain2.terrainData.detailPrototypes.Length} {terrain.terrainData.detailPrototypes.Length}");
|
|
}
|
|
if (GaiaSplatPrototype.GetGaiaSplatPrototypes(terrain2).Length != GaiaSplatPrototype.GetGaiaSplatPrototypes(terrain).Length)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} splatPrototypes.Length does not match {GaiaSplatPrototype.GetGaiaSplatPrototypes(terrain2).Length} {GaiaSplatPrototype.GetGaiaSplatPrototypes(terrain).Length}");
|
|
}
|
|
if (terrain2.terrainData.treePrototypes.Length != terrain.terrainData.treePrototypes.Length)
|
|
{
|
|
stringBuilder.Append($"\nTerrain {terrain2.name} - {terrain.name} treePrototypes.Length does not match {terrain2.terrainData.treePrototypes.Length} {terrain.terrainData.treePrototypes.Length}");
|
|
}
|
|
}
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
private Terrain GetTerrainWU(Vector3 positionWU)
|
|
{
|
|
if (!InBoundsWU(positionWU))
|
|
{
|
|
m_boundsCheckErrors++;
|
|
return null;
|
|
}
|
|
Vector3 vector = WUtoPTI(positionWU);
|
|
return m_physicalTerrainArray[(int)vector.x, (int)vector.z];
|
|
}
|
|
|
|
private Terrain GetTerrainTU(Vector3 positionTU)
|
|
{
|
|
if (!InBoundsTU(positionTU))
|
|
{
|
|
m_boundsCheckErrors++;
|
|
return null;
|
|
}
|
|
TUtoPTI(ref positionTU);
|
|
return m_physicalTerrainArray[(int)positionTU.x, (int)positionTU.z];
|
|
}
|
|
|
|
private Terrain GetTerrainNU(Vector3 positionNU)
|
|
{
|
|
if (!InBoundsNU(positionNU))
|
|
{
|
|
m_boundsCheckErrors++;
|
|
return null;
|
|
}
|
|
NUtoPTI(ref positionNU);
|
|
return m_physicalTerrainArray[(int)positionNU.x, (int)positionNU.z];
|
|
}
|
|
|
|
private UnityHeightMap GetHeightMapWU(Vector3 positionWU)
|
|
{
|
|
if (!InBoundsWU(positionWU))
|
|
{
|
|
m_boundsCheckErrors++;
|
|
return null;
|
|
}
|
|
Vector3 vector = WUtoPTI(positionWU);
|
|
UnityHeightMap unityHeightMap = m_heightMapTerrainArray[(int)vector.x, (int)vector.z];
|
|
if (unityHeightMap == null)
|
|
{
|
|
Terrain terrainWU = GetTerrainWU(positionWU);
|
|
if (terrainWU != null)
|
|
{
|
|
unityHeightMap = (m_heightMapTerrainArray[(int)vector.x, (int)vector.z] = new UnityHeightMap(terrainWU));
|
|
}
|
|
}
|
|
return unityHeightMap;
|
|
}
|
|
|
|
private UnityHeightMap GetHeightMapTU(Vector3 positionTU)
|
|
{
|
|
if (!InBoundsTU(positionTU))
|
|
{
|
|
m_boundsCheckErrors++;
|
|
return null;
|
|
}
|
|
TUtoPTI(ref positionTU);
|
|
UnityHeightMap unityHeightMap = m_heightMapTerrainArray[(int)positionTU.x, (int)positionTU.z];
|
|
if (unityHeightMap == null)
|
|
{
|
|
Terrain terrainTU = GetTerrainTU(positionTU);
|
|
if (terrainTU != null)
|
|
{
|
|
unityHeightMap = (m_heightMapTerrainArray[(int)positionTU.x, (int)positionTU.z] = new UnityHeightMap(terrainTU));
|
|
}
|
|
}
|
|
return unityHeightMap;
|
|
}
|
|
|
|
private UnityHeightMap GetHeightMapNU(Vector3 positionNU)
|
|
{
|
|
if (!InBoundsNU(positionNU))
|
|
{
|
|
m_boundsCheckErrors++;
|
|
return null;
|
|
}
|
|
NUtoPTI(ref positionNU);
|
|
UnityHeightMap unityHeightMap = m_heightMapTerrainArray[(int)positionNU.x, (int)positionNU.z];
|
|
if (unityHeightMap == null)
|
|
{
|
|
Terrain terrainNU = GetTerrainNU(positionNU);
|
|
if (terrainNU != null)
|
|
{
|
|
unityHeightMap = (m_heightMapTerrainArray[(int)positionNU.x, (int)positionNU.z] = new UnityHeightMap(terrainNU));
|
|
}
|
|
}
|
|
return unityHeightMap;
|
|
}
|
|
|
|
public void LoadFromWorld()
|
|
{
|
|
for (int i = 0; i < m_heightMapTerrainArray.GetLength(0); i++)
|
|
{
|
|
for (int j = 0; j < m_heightMapTerrainArray.GetLength(1); j++)
|
|
{
|
|
UnityHeightMap unityHeightMap = m_heightMapTerrainArray[i, j];
|
|
if (unityHeightMap == null)
|
|
{
|
|
Terrain terrain = m_physicalTerrainArray[i, j];
|
|
if (terrain != null)
|
|
{
|
|
m_heightMapTerrainArray[i, j] = new UnityHeightMap(terrain);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unityHeightMap.LoadFromTerrain(m_physicalTerrainArray[i, j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SaveToWorld(bool forceWrite = false)
|
|
{
|
|
for (int i = 0; i < m_heightMapTerrainArray.GetLength(0); i++)
|
|
{
|
|
for (int j = 0; j < m_heightMapTerrainArray.GetLength(1); j++)
|
|
{
|
|
UnityHeightMap unityHeightMap = m_heightMapTerrainArray[i, j];
|
|
if (unityHeightMap == null)
|
|
{
|
|
continue;
|
|
}
|
|
if (!forceWrite)
|
|
{
|
|
if (unityHeightMap.IsDirty())
|
|
{
|
|
unityHeightMap.SaveToTerrain(m_physicalTerrainArray[i, j]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unityHeightMap.SaveToTerrain(m_physicalTerrainArray[i, j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetHeightWU(float heightWU)
|
|
{
|
|
float height = Mathf.Clamp01(heightWU / m_worldBoundsWUSize.y);
|
|
for (int i = 0; i < m_heightMapTerrainArray.GetLength(0); i++)
|
|
{
|
|
for (int j = 0; j < m_heightMapTerrainArray.GetLength(1); j++)
|
|
{
|
|
m_heightMapTerrainArray[i, j].SetHeight(height);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetHeightWU(Vector3 positionWU, float height)
|
|
{
|
|
UnityHeightMap heightMapWU = GetHeightMapWU(positionWU);
|
|
if (heightMapWU != null)
|
|
{
|
|
positionWU = WUtoPTO(positionWU);
|
|
heightMapWU[(int)positionWU.x, (int)positionWU.z] = height;
|
|
}
|
|
else
|
|
{
|
|
m_boundsCheckErrors++;
|
|
}
|
|
}
|
|
|
|
public float GetHeightWU(Vector3 positionWU)
|
|
{
|
|
UnityHeightMap heightMapWU = GetHeightMapWU(positionWU);
|
|
if (heightMapWU != null)
|
|
{
|
|
positionWU = WUtoPTO(positionWU);
|
|
return heightMapWU[(int)positionWU.x, (int)positionWU.z];
|
|
}
|
|
return float.MinValue;
|
|
}
|
|
|
|
public float GetHeightInterpolatedWU(Vector3 positionWU)
|
|
{
|
|
UnityHeightMap heightMapWU = GetHeightMapWU(positionWU);
|
|
if (heightMapWU != null)
|
|
{
|
|
positionWU = WUtoPTO(positionWU);
|
|
return heightMapWU[positionWU.x, positionWU.z];
|
|
}
|
|
return float.MinValue;
|
|
}
|
|
|
|
public void SetHeightTU(Vector3 positionTU, float height)
|
|
{
|
|
UnityHeightMap heightMapTU = GetHeightMapTU(positionTU);
|
|
if (heightMapTU != null)
|
|
{
|
|
TUtoPTO(ref positionTU);
|
|
heightMapTU[(int)positionTU.x, (int)positionTU.z] = height;
|
|
}
|
|
else
|
|
{
|
|
m_boundsCheckErrors++;
|
|
}
|
|
}
|
|
|
|
public float GetHeightTU(Vector3 positionTU)
|
|
{
|
|
UnityHeightMap heightMapTU = GetHeightMapTU(positionTU);
|
|
if (heightMapTU != null)
|
|
{
|
|
TUtoPTO(ref positionTU);
|
|
return heightMapTU[(int)positionTU.x, (int)positionTU.z];
|
|
}
|
|
return float.MinValue;
|
|
}
|
|
|
|
public float GetHeightInterpolatedTU(Vector3 positionTU)
|
|
{
|
|
UnityHeightMap heightMapTU = GetHeightMapTU(positionTU);
|
|
if (heightMapTU != null)
|
|
{
|
|
TUtoPTO(ref positionTU);
|
|
return heightMapTU[positionTU.x, positionTU.z];
|
|
}
|
|
return float.MinValue;
|
|
}
|
|
|
|
public void FlattenWorld()
|
|
{
|
|
for (int i = 0; i < m_heightMapTerrainArray.GetLength(0); i++)
|
|
{
|
|
for (int j = 0; j < m_heightMapTerrainArray.GetLength(1); j++)
|
|
{
|
|
UnityHeightMap unityHeightMap = m_heightMapTerrainArray[i, j];
|
|
if (unityHeightMap == null)
|
|
{
|
|
Terrain terrain = m_physicalTerrainArray[i, j];
|
|
if (terrain != null)
|
|
{
|
|
unityHeightMap = (m_heightMapTerrainArray[i, j] = new UnityHeightMap(terrain));
|
|
}
|
|
}
|
|
if (unityHeightMap != null)
|
|
{
|
|
unityHeightMap.SetHeight(0f);
|
|
unityHeightMap.SaveToTerrain(m_physicalTerrainArray[i, j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SmoothWorld()
|
|
{
|
|
for (int i = 0; i < m_heightMapTerrainArray.GetLength(0); i++)
|
|
{
|
|
for (int j = 0; j < m_heightMapTerrainArray.GetLength(1); j++)
|
|
{
|
|
UnityHeightMap unityHeightMap = m_heightMapTerrainArray[i, j];
|
|
if (unityHeightMap == null)
|
|
{
|
|
Terrain terrain = m_physicalTerrainArray[i, j];
|
|
if (terrain != null)
|
|
{
|
|
unityHeightMap = (m_heightMapTerrainArray[i, j] = new UnityHeightMap(terrain));
|
|
}
|
|
}
|
|
if (unityHeightMap != null)
|
|
{
|
|
unityHeightMap.Smooth(1);
|
|
unityHeightMap.SaveToTerrain(m_physicalTerrainArray[i, j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ExportWorldAsPng(string path)
|
|
{
|
|
Vector3 center = m_worldBoundsTU.center;
|
|
HeightMap heightMap = new HeightMap((int)m_worldBoundsTUSize.z, (int)m_worldBoundsTUSize.x);
|
|
int num = 0;
|
|
for (int i = (int)m_worldBoundsTUMin.x; i < (int)m_worldBoundsTUMax.x; i++)
|
|
{
|
|
center.x = i;
|
|
int num2 = 0;
|
|
for (int j = (int)m_worldBoundsTUMin.z; j < (int)m_worldBoundsTUMax.z; j++)
|
|
{
|
|
center.z = j;
|
|
heightMap[num2, num] = GetHeightTU(center);
|
|
num2++;
|
|
}
|
|
num++;
|
|
}
|
|
GaiaUtils.CompressToSingleChannelFileImage(heightMap.Heights(), path, TextureFormat.RGBA32, exportPNG: true, exportJPG: false);
|
|
}
|
|
|
|
public void ExportSplatmapAsPng(string path, int textureIdx)
|
|
{
|
|
Terrain activeTerrain = Terrain.activeTerrain;
|
|
if (activeTerrain == null)
|
|
{
|
|
Debug.LogError("No active terrain, unable to export splatmaps");
|
|
return;
|
|
}
|
|
int alphamapWidth = activeTerrain.terrainData.alphamapWidth;
|
|
int alphamapHeight = activeTerrain.terrainData.alphamapHeight;
|
|
int alphamapLayers = activeTerrain.terrainData.alphamapLayers;
|
|
if (textureIdx < alphamapLayers)
|
|
{
|
|
HeightMap heightMap = new HeightMap(activeTerrain.terrainData.GetAlphamaps(0, 0, alphamapWidth, alphamapHeight), textureIdx);
|
|
heightMap.Flip();
|
|
GaiaUtils.CompressToSingleChannelFileImage(heightMap.Heights(), path, TextureFormat.RGBA32, exportPNG: true, exportJPG: false);
|
|
}
|
|
else
|
|
{
|
|
GaiaUtils.CompressToMultiChannelFileImage(activeTerrain.terrainData.GetAlphamaps(0, 0, alphamapWidth, alphamapHeight), path, TextureFormat.RGBA32, exportPNG: true, exportJPG: false);
|
|
}
|
|
}
|
|
|
|
public void ExportGrassmapAsPng(string path)
|
|
{
|
|
Terrain activeTerrain = Terrain.activeTerrain;
|
|
if (activeTerrain == null)
|
|
{
|
|
Debug.LogError("No active terrain, unable to export grassmaps");
|
|
return;
|
|
}
|
|
int detailWidth = activeTerrain.terrainData.detailWidth;
|
|
int detailHeight = activeTerrain.terrainData.detailHeight;
|
|
int num = activeTerrain.terrainData.detailPrototypes.Length;
|
|
float[,,] array = new float[detailWidth, detailHeight, num];
|
|
for (int i = 0; i < activeTerrain.terrainData.detailPrototypes.Length; i++)
|
|
{
|
|
int[,] detailLayer = activeTerrain.terrainData.GetDetailLayer(0, 0, activeTerrain.terrainData.detailWidth, activeTerrain.terrainData.detailHeight, i);
|
|
for (int j = 0; j < detailWidth; j++)
|
|
{
|
|
for (int k = 0; k < detailHeight; k++)
|
|
{
|
|
array[j, k, i] = (float)detailLayer[j, k] / 16f;
|
|
}
|
|
}
|
|
for (int l = 0; l < detailWidth; l++)
|
|
{
|
|
for (int m = 0; m < detailHeight; m++)
|
|
{
|
|
array[m, l, i] = array[l, m, i];
|
|
}
|
|
}
|
|
}
|
|
GaiaUtils.CompressToMultiChannelFileImage(array, path, TextureFormat.RGBA32, exportPNG: true, exportJPG: false);
|
|
}
|
|
|
|
public void ExportNormalmapAsPng(string path)
|
|
{
|
|
for (int i = 0; i < m_physicalTerrainArray.GetLength(0); i++)
|
|
{
|
|
for (int j = 0; j < m_physicalTerrainArray.GetLength(1); j++)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ExportNormalmapAsPng1(string path)
|
|
{
|
|
Terrain terrain = null;
|
|
int num = 0;
|
|
int num2 = 0;
|
|
float[,,] array = null;
|
|
for (int i = 0; i < m_physicalTerrainArray.GetLength(0); i++)
|
|
{
|
|
for (int j = 0; j < m_physicalTerrainArray.GetLength(1); j++)
|
|
{
|
|
terrain = m_physicalTerrainArray[i, j];
|
|
if (!(terrain != null))
|
|
{
|
|
continue;
|
|
}
|
|
num = terrain.terrainData.heightmapResolution;
|
|
num2 = terrain.terrainData.heightmapResolution;
|
|
array = new float[num, num2, 4];
|
|
for (int k = 0; k < num; k++)
|
|
{
|
|
for (int l = 0; l < num2; l++)
|
|
{
|
|
Vector3 interpolatedNormal = terrain.terrainData.GetInterpolatedNormal((float)k / (float)num, (float)l / (float)num2);
|
|
array[k, l, 0] = interpolatedNormal.x * 0.5f + 0.5f;
|
|
array[k, l, 1] = interpolatedNormal.y * 0.5f + 0.5f;
|
|
array[k, l, 2] = interpolatedNormal.z * 0.5f + 0.5f;
|
|
}
|
|
}
|
|
GaiaUtils.CompressToMultiChannelFileImage(array, path + "_" + i + "_" + j, TextureFormat.RGBA32, exportPNG: true, exportJPG: false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ExportWaterflowMapAsPng(int iterations, string path)
|
|
{
|
|
for (int i = 0; i < m_physicalTerrainArray.GetLength(0); i++)
|
|
{
|
|
for (int j = 0; j < m_physicalTerrainArray.GetLength(1); j++)
|
|
{
|
|
GaiaUtils.CompressToSingleChannelFileImage(m_heightMapTerrainArray[i, j].FlowMap(iterations).Normalise().Heights(), path + "_" + i + "_" + j + ".png", TextureFormat.RGBA32, exportPNG: true, exportJPG: false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ExportShorelineMask(string path, float shoreHeightWU, float shoreWidthWU)
|
|
{
|
|
Vector3 center = m_worldBoundsTU.center;
|
|
float shoreHeightNU = shoreHeightWU / m_worldBoundsWUSize.y;
|
|
Vector3 vector = WUtoTU(new Vector3(shoreWidthWU, shoreWidthWU, shoreWidthWU));
|
|
HeightMap heightMap = new HeightMap((int)m_worldBoundsTUSize.z, (int)m_worldBoundsTUSize.x);
|
|
float num = 0f;
|
|
for (float num2 = m_worldBoundsTUMin.x; num2 < m_worldBoundsTUMax.x; num2 += 1f)
|
|
{
|
|
center.x = num2;
|
|
float num3 = 0f;
|
|
for (float num4 = m_worldBoundsTUMin.z; num4 < m_worldBoundsTUMax.z; num4 += 1f)
|
|
{
|
|
center.z = num4;
|
|
MakeMask(center, shoreHeightNU, vector.x, heightMap);
|
|
num3 += 1f;
|
|
}
|
|
num += 1f;
|
|
}
|
|
heightMap.Flip();
|
|
GaiaUtils.CompressToSingleChannelFileImage(heightMap.Heights(), path, TextureFormat.RGBA32, exportPNG: true, exportJPG: false);
|
|
}
|
|
|
|
private void MakeMask(Vector3 positionTU, float shoreHeightNU, float maskSizeTU, HeightMap waterMask)
|
|
{
|
|
float num = positionTU.x - maskSizeTU;
|
|
float num2 = positionTU.x + maskSizeTU;
|
|
float num3 = positionTU.z - maskSizeTU;
|
|
float num4 = positionTU.z + maskSizeTU;
|
|
Vector3 center = m_worldBoundsTU.center;
|
|
for (float num5 = num; num5 < num2; num5 += 1f)
|
|
{
|
|
center.x = num5;
|
|
for (float num6 = num3; num6 < num4; num6 += 1f)
|
|
{
|
|
center.z = num6;
|
|
if (!InBoundsTU(center) || !(GetHeightTU(center) <= shoreHeightNU))
|
|
{
|
|
continue;
|
|
}
|
|
float num7 = GaiaCommon1.Utils.Math_Distance(num5, num6, positionTU.x, positionTU.z) / maskSizeTU;
|
|
if (num7 <= 1f)
|
|
{
|
|
num7 = 1f - num7;
|
|
int x = (int)(num5 + m_TUZeroOffset.x);
|
|
int z = (int)(num6 + m_TUZeroOffset.z);
|
|
if (num7 > waterMask[x, z])
|
|
{
|
|
waterMask[x, z] = num7;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool InBoundsWU(Vector3 positionWU)
|
|
{
|
|
if (positionWU.x >= m_worldBoundsWUMin.x && positionWU.z >= m_worldBoundsWUMin.z && positionWU.x < m_worldBoundsWUMax.x && positionWU.z < m_worldBoundsWUMax.z)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool InBoundsTU(Vector3 positionTU)
|
|
{
|
|
if (positionTU.x >= m_worldBoundsTUMin.x && positionTU.z >= m_worldBoundsTUMin.z && positionTU.x < m_worldBoundsTUMax.x && positionTU.z < m_worldBoundsTUMax.z)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool InBoundsNU(Vector3 positionNU)
|
|
{
|
|
if (positionNU.x >= m_worldBoundsNUMin.x && positionNU.z >= m_worldBoundsNUMin.z && positionNU.x < m_worldBoundsNUMax.x && positionNU.z < m_worldBoundsNUMax.z)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public Vector3 WUtoTU(Vector3 positionWU)
|
|
{
|
|
return Vector3.Scale(positionWU, m_WUtoTU);
|
|
}
|
|
|
|
public Vector3 WUtoNU(Vector3 positionWU)
|
|
{
|
|
return Vector3.Scale(positionWU, m_WUtoNU);
|
|
}
|
|
|
|
public Vector3 WUtoPTI(Vector3 positionWU)
|
|
{
|
|
positionWU = WUtoNU(positionWU);
|
|
NUtoPTI(ref positionWU);
|
|
return positionWU;
|
|
}
|
|
|
|
public Vector3 WUtoPTO(Vector3 positionWU)
|
|
{
|
|
positionWU = WUtoTU(positionWU);
|
|
TUtoPTO(ref positionWU);
|
|
return positionWU;
|
|
}
|
|
|
|
public Vector3 TUtoWU(Vector3 positionTU)
|
|
{
|
|
return Vector3.Scale(positionTU, m_TUtoWU);
|
|
}
|
|
|
|
public Vector3 TUtoNU(Vector3 positionTU)
|
|
{
|
|
return Vector3.Scale(positionTU, m_TUtoNU);
|
|
}
|
|
|
|
public void TUtoPTI(ref Vector3 positionTU)
|
|
{
|
|
positionTU.x = (float)(int)(positionTU.x + m_NUZeroOffset.x) * m_TUtoNU.x;
|
|
positionTU.y = (float)(int)(positionTU.y + m_NUZeroOffset.y) * m_TUtoNU.y;
|
|
positionTU.z = (float)(int)(positionTU.z + m_NUZeroOffset.z) * m_TUtoNU.z;
|
|
}
|
|
|
|
public void TUtoPTO(ref Vector3 positionTU)
|
|
{
|
|
positionTU.x = (positionTU.x + m_TUZeroOffset.x) % m_worldBoundsTUSize.x;
|
|
positionTU.y = (positionTU.y + m_TUZeroOffset.y) % m_worldBoundsTUSize.y;
|
|
positionTU.z = (positionTU.z + m_TUZeroOffset.z) % m_worldBoundsTUSize.z;
|
|
}
|
|
|
|
public Vector3 NUtoWU(Vector3 positionNU)
|
|
{
|
|
return Vector3.Scale(positionNU, m_NUtoWU);
|
|
}
|
|
|
|
public Vector3 NUtoTU(Vector3 positionNU)
|
|
{
|
|
return Vector3.Scale(positionNU, m_NUtoTU);
|
|
}
|
|
|
|
public void NUtoPTI(ref Vector3 positionNU)
|
|
{
|
|
positionNU.x = Mathf.Floor(positionNU.x + m_NUZeroOffset.x);
|
|
positionNU.y = Mathf.Floor(positionNU.y + m_NUZeroOffset.y);
|
|
positionNU.z = Mathf.Floor(positionNU.z + m_NUZeroOffset.z);
|
|
}
|
|
|
|
public void NUtoPTO(ref Vector3 positionNU)
|
|
{
|
|
positionNU.x = (positionNU.x + m_NUZeroOffset.x) % 1f * m_worldBoundsTUSize.x;
|
|
positionNU.y = (positionNU.y + m_NUZeroOffset.y) % 1f * m_worldBoundsTUSize.y;
|
|
positionNU.z = (positionNU.z + m_NUZeroOffset.z) % 1f * m_worldBoundsTUSize.z;
|
|
}
|
|
|
|
public Vector3 Ceil(Vector3 source)
|
|
{
|
|
return new Vector3(Mathf.Ceil(source.x), Mathf.Ceil(source.y), Mathf.Ceil(source.z));
|
|
}
|
|
|
|
public Vector3 Floor(Vector3 source)
|
|
{
|
|
return new Vector3(Mathf.Floor(source.x), Mathf.Floor(source.y), Mathf.Floor(source.z));
|
|
}
|
|
|
|
public void Test()
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
stringBuilder.Append("GaiaWorldManagerTest\n");
|
|
stringBuilder.Append($"World Bounds WU : Min {m_worldBoundsWU.min}, Centre {m_worldBoundsWU.center}, Max {m_worldBoundsWU.max}, Size {m_worldBoundsWU.size}\n");
|
|
stringBuilder.Append($"World Bounds TU : Min {m_worldBoundsTU.min}, Centre {m_worldBoundsTU.center}, Max {m_worldBoundsTU.max}, Size {m_worldBoundsTU.size}\n");
|
|
stringBuilder.Append($"World Bounds NU : Min {m_worldBoundsNU.min}, Centre {m_worldBoundsNU.center}, Max {m_worldBoundsNU.max}, Size {m_worldBoundsNU.size}\n");
|
|
stringBuilder.Append("\nBounds Tests:");
|
|
Vector3 vector = new Vector3(m_worldBoundsWU.min.x - 1f, m_worldBoundsWU.min.y, m_worldBoundsWU.min.z);
|
|
stringBuilder.Append($"\n<MIN - InBoundsWU({vector}) = {InBoundsWU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsWU.min.x, m_worldBoundsWU.min.y, m_worldBoundsWU.min.z);
|
|
stringBuilder.Append($" MIN - InBoundsWU({vector}) = {InBoundsWU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsWU.max.x, m_worldBoundsWU.max.y, m_worldBoundsWU.max.z);
|
|
stringBuilder.Append($" MAX - InBoundsWU({vector}) = {InBoundsWU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsWU.max.x + 1f, m_worldBoundsWU.max.y, m_worldBoundsWU.max.z);
|
|
stringBuilder.Append($">MAX - InBoundsWU({vector}) = {InBoundsWU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsTU.min.x - 1f, m_worldBoundsTU.min.y, m_worldBoundsTU.min.z);
|
|
stringBuilder.Append($"\n<MIN - InBoundsTU({vector}) = {InBoundsTU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsTU.min.x, m_worldBoundsTU.min.y, m_worldBoundsTU.min.z);
|
|
stringBuilder.Append($" MIN - InBoundsTU({vector}) = {InBoundsTU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsTU.max.x, m_worldBoundsTU.max.y, m_worldBoundsTU.max.z);
|
|
stringBuilder.Append($" MAX - InBoundsTU({vector}) = {InBoundsTU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsTU.max.x + 1f, m_worldBoundsTU.max.y, m_worldBoundsTU.max.y);
|
|
stringBuilder.Append($">MAX - InBoundsTU({vector}) = {InBoundsTU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsNU.min.x - 0.1f, m_worldBoundsNU.min.y, m_worldBoundsNU.min.z);
|
|
stringBuilder.Append($"\n<MIN - InBoundsNU({vector}) = {InBoundsNU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsNU.min.x, m_worldBoundsNU.min.y, m_worldBoundsNU.min.z);
|
|
stringBuilder.Append($" MIN - InBoundsNU({vector}) = {InBoundsNU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsNU.max.x, m_worldBoundsNU.max.y, m_worldBoundsNU.max.z);
|
|
stringBuilder.Append($" MAX - InBoundsNU({vector}) = {InBoundsNU(vector)}\n");
|
|
vector = new Vector3(m_worldBoundsNU.max.x + 0.1f, m_worldBoundsNU.max.y, m_worldBoundsNU.max.z);
|
|
stringBuilder.Append($">MAX - InBoundsNU({vector}) = {InBoundsNU(vector)}\n");
|
|
stringBuilder.Append("\nPosition Conversion Tests (<MIN, CENTRE, >MAX):");
|
|
vector = new Vector3(m_worldBoundsWU.min.x - 1f, m_worldBoundsWU.center.y, m_worldBoundsWU.max.z + 1f);
|
|
stringBuilder.Append($"\nInBoundsWU({vector}) = {InBoundsWU(vector)}\n");
|
|
stringBuilder.Append($"WUtoTU({vector}) = {WUtoTU(vector).x:0.000}, {WUtoTU(vector).z:0.000}\n");
|
|
stringBuilder.Append($"WUtoNU({vector}) = {WUtoNU(vector).x:0.000}, {WUtoNU(vector).z:0.000}\n");
|
|
stringBuilder.Append($"WUtoPTI({vector}) = {WUtoPTI(vector).x}, {WUtoPTI(vector).z}\n");
|
|
stringBuilder.Append($"WUtoPTO({vector}) = {WUtoPTO(vector).x}, {WUtoPTO(vector).z}\n");
|
|
stringBuilder.Append("\nPosition Conversion Tests (MIN, CENTRE, MAX):");
|
|
vector = new Vector3(m_worldBoundsWU.min.x, m_worldBoundsWU.center.y, m_worldBoundsWU.max.z);
|
|
stringBuilder.Append($"\nInBoundsWU({vector}) = {InBoundsWU(vector)}\n");
|
|
stringBuilder.Append($"WUtoTU({vector}) = {WUtoTU(vector).x:0.000}, {WUtoTU(vector).z:0.000}\n");
|
|
stringBuilder.Append($"WUtoNU({vector}) = {WUtoNU(vector).x:0.000}, {WUtoNU(vector).z:0.000}\n");
|
|
stringBuilder.Append($"WUtoPTI({vector}) = {WUtoPTI(vector).x}, {WUtoPTI(vector).z}\n");
|
|
stringBuilder.Append($"WUtoPTO({vector}) = {WUtoPTO(vector).x}, {WUtoPTO(vector).z}\n");
|
|
vector = WUtoTU(vector);
|
|
stringBuilder.Append($"\nTUtoWU({vector}) = {TUtoWU(vector)}\n");
|
|
stringBuilder.Append($"TUtoNU({vector}) = {TUtoNU(vector)}\n");
|
|
vector = TUtoNU(vector);
|
|
stringBuilder.Append($"\nNUtoWU({vector}) = {NUtoWU(vector)}\n");
|
|
stringBuilder.Append($"NUtoTU({vector}) = {NUtoTU(vector)}\n");
|
|
stringBuilder.Append("\nTerrain Tests:");
|
|
FlattenWorld();
|
|
m_boundsCheckErrors = 0uL;
|
|
TestBlobWU(m_worldBoundsWU.min, 100, 0.25f);
|
|
TestBlobTU(m_worldBoundsTU.center, 100, 0.5f);
|
|
TestBlobWU(m_worldBoundsWU.max, 100, 1f);
|
|
SaveToWorld();
|
|
stringBuilder.Append($"Bounds check errors : {m_boundsCheckErrors}");
|
|
Debug.Log(stringBuilder.ToString());
|
|
}
|
|
|
|
public void TestBlobWU(Vector3 positionWU, int widthWU, float height)
|
|
{
|
|
Vector3 vector = WUtoTU(new Vector3(widthWU, widthWU, widthWU));
|
|
Vector3 vector2 = WUtoTU(positionWU);
|
|
for (int i = (int)(vector2.x - vector.x); i < (int)(vector2.x + vector.x); i++)
|
|
{
|
|
for (int j = (int)(vector2.z - vector.z); j < (int)(vector2.z + vector.z); j++)
|
|
{
|
|
Vector3 positionTU = new Vector3(i, m_worldBoundsTU.center.y, j);
|
|
SetHeightTU(positionTU, height);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void TestBlobTU(Vector3 positionTU, int widthWU, float height)
|
|
{
|
|
Vector3 vector = WUtoTU(new Vector3(widthWU, widthWU, widthWU));
|
|
for (int i = (int)(positionTU.x - vector.x); i < (int)(positionTU.x + vector.x); i++)
|
|
{
|
|
for (int j = (int)(positionTU.z - vector.z); j < (int)(positionTU.z + vector.z); j++)
|
|
{
|
|
Vector3 positionTU2 = new Vector3(i, m_worldBoundsTU.center.y, j);
|
|
SetHeightTU(positionTU2, height);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|