592 lines
17 KiB
C#
592 lines
17 KiB
C#
#if GRIFFIN
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using Type = System.Type;
|
|
|
|
namespace Pinwheel.Griffin
|
|
{
|
|
public class GGeometry : ScriptableObject
|
|
{
|
|
[System.Serializable]
|
|
public enum GStorageMode
|
|
{
|
|
SaveToAsset, GenerateOnEnable
|
|
}
|
|
|
|
public const string HEIGHT_MAP_NAME = "Height Map";
|
|
|
|
[SerializeField]
|
|
private GTerrainData terrainData;
|
|
public GTerrainData TerrainData
|
|
{
|
|
get
|
|
{
|
|
return terrainData;
|
|
}
|
|
internal set
|
|
{
|
|
terrainData = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
internal float width;
|
|
public float Width
|
|
{
|
|
get
|
|
{
|
|
return width;
|
|
}
|
|
set
|
|
{
|
|
width = Mathf.Max(1, value);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
internal float height;
|
|
public float Height
|
|
{
|
|
get
|
|
{
|
|
return height;
|
|
}
|
|
set
|
|
{
|
|
height = Mathf.Max(0, value);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
internal float length;
|
|
public float Length
|
|
{
|
|
get
|
|
{
|
|
return length;
|
|
}
|
|
set
|
|
{
|
|
length = Mathf.Max(1, value);
|
|
}
|
|
}
|
|
|
|
public Vector3 Size
|
|
{
|
|
get
|
|
{
|
|
return new Vector3(Width, Height, Length);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private int heightMapResolution;
|
|
public int HeightMapResolution
|
|
{
|
|
get
|
|
{
|
|
return heightMapResolution;
|
|
}
|
|
set
|
|
{
|
|
int oldValue = heightMapResolution;
|
|
heightMapResolution = Mathf.Clamp(Mathf.ClosestPowerOfTwo(value), GCommon.TEXTURE_SIZE_MIN, GCommon.TEXTURE_SIZE_MAX);
|
|
if (oldValue != heightMapResolution)
|
|
{
|
|
ResampleHeightMap();
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private Texture2D heightMap;
|
|
public Texture2D HeightMap
|
|
{
|
|
get
|
|
{
|
|
if (heightMap == null)
|
|
{
|
|
heightMap = GCommon.CreateTexture(HeightMapResolution, Color.clear, HeightMapFormat);
|
|
heightMap.filterMode = FilterMode.Bilinear;
|
|
heightMap.wrapMode = TextureWrapMode.Clamp;
|
|
heightMap.name = HEIGHT_MAP_NAME;
|
|
heightmapVersion = GVersionInfo.Number;
|
|
}
|
|
GCommon.TryAddObjectToAsset(heightMap, TerrainData);
|
|
if (heightMap.format != HeightMapFormat)
|
|
{
|
|
ReFormatHeightMap();
|
|
}
|
|
return heightMap;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private float heightmapVersion;
|
|
private const float HEIGHT_MAP_VERSION_ENCODE_RG = 246;
|
|
|
|
public static TextureFormat HeightMapFormat
|
|
{
|
|
get
|
|
{
|
|
return TextureFormat.RGBA32;
|
|
}
|
|
}
|
|
|
|
public static RenderTextureFormat HeightMapRTFormat
|
|
{
|
|
get
|
|
{
|
|
return RenderTextureFormat.ARGB32;
|
|
}
|
|
}
|
|
|
|
internal Texture2D subDivisionMap;
|
|
public Texture2D Internal_SubDivisionMap
|
|
{
|
|
get
|
|
{
|
|
if (subDivisionMap == null)
|
|
{
|
|
Internal_CreateNewSubDivisionMap();
|
|
}
|
|
return subDivisionMap;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private int meshBaseResolution;
|
|
public int MeshBaseResolution
|
|
{
|
|
get
|
|
{
|
|
return meshBaseResolution;
|
|
}
|
|
set
|
|
{
|
|
meshBaseResolution = Mathf.Min(meshResolution, Mathf.Clamp(value, 0, GCommon.MAX_MESH_BASE_RESOLUTION));
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private int meshResolution;
|
|
public int MeshResolution
|
|
{
|
|
get
|
|
{
|
|
return meshResolution;
|
|
}
|
|
set
|
|
{
|
|
meshResolution = Mathf.Clamp(value, 0, GCommon.MAX_MESH_RESOLUTION);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private int chunkGridSize;
|
|
public int ChunkGridSize
|
|
{
|
|
get
|
|
{
|
|
return chunkGridSize;
|
|
}
|
|
set
|
|
{
|
|
chunkGridSize = Mathf.Max(1, value);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private int lodCount;
|
|
public int LODCount
|
|
{
|
|
get
|
|
{
|
|
return lodCount;
|
|
}
|
|
set
|
|
{
|
|
lodCount = Mathf.Clamp(value, 1, GCommon.MAX_LOD_COUNT);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private int displacementSeed;
|
|
public int DisplacementSeed
|
|
{
|
|
get
|
|
{
|
|
return displacementSeed;
|
|
}
|
|
set
|
|
{
|
|
displacementSeed = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private float displacementStrength;
|
|
public float DisplacementStrength
|
|
{
|
|
get
|
|
{
|
|
return displacementStrength;
|
|
}
|
|
set
|
|
{
|
|
displacementStrength = Mathf.Max(0, value);
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private GAlbedoToVertexColorMode albedoToVertexColorMode;
|
|
public GAlbedoToVertexColorMode AlbedoToVertexColorMode
|
|
{
|
|
get
|
|
{
|
|
return albedoToVertexColorMode;
|
|
}
|
|
set
|
|
{
|
|
albedoToVertexColorMode = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private GStorageMode storageMode;
|
|
public GStorageMode StorageMode
|
|
{
|
|
get
|
|
{
|
|
return storageMode;
|
|
}
|
|
set
|
|
{
|
|
storageMode = value;
|
|
if (storageMode == GStorageMode.GenerateOnEnable)
|
|
{
|
|
TerrainData.GeometryData = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private bool allowTimeSlicedGeneration;
|
|
public bool AllowTimeSlicedGeneration
|
|
{
|
|
get
|
|
{
|
|
return allowTimeSlicedGeneration;
|
|
}
|
|
set
|
|
{
|
|
allowTimeSlicedGeneration = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private bool smoothNormal;
|
|
public bool SmoothNormal
|
|
{
|
|
get
|
|
{
|
|
return smoothNormal;
|
|
}
|
|
set
|
|
{
|
|
smoothNormal = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private bool useSmoothNormalMask;
|
|
public bool UseSmoothNormalMask
|
|
{
|
|
get
|
|
{
|
|
return useSmoothNormalMask;
|
|
}
|
|
set
|
|
{
|
|
useSmoothNormalMask = value;
|
|
}
|
|
}
|
|
|
|
[SerializeField]
|
|
private bool mergeUv;
|
|
public bool MergeUv
|
|
{
|
|
get
|
|
{
|
|
return mergeUv;
|
|
}
|
|
set
|
|
{
|
|
mergeUv = value;
|
|
}
|
|
}
|
|
|
|
private List<Rect> dirtyRegion;
|
|
private List<Rect> DirtyRegion
|
|
{
|
|
get
|
|
{
|
|
if (dirtyRegion == null)
|
|
{
|
|
dirtyRegion = new List<Rect>();
|
|
}
|
|
return dirtyRegion;
|
|
}
|
|
set
|
|
{
|
|
dirtyRegion = value;
|
|
}
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
name = "Geometry";
|
|
Width = GRuntimeSettings.Instance.geometryDefault.width;
|
|
Height = GRuntimeSettings.Instance.geometryDefault.height;
|
|
Length = GRuntimeSettings.Instance.geometryDefault.length;
|
|
HeightMapResolution = GRuntimeSettings.Instance.geometryDefault.heightMapResolution;
|
|
MeshResolution = GRuntimeSettings.Instance.geometryDefault.meshResolution;
|
|
MeshBaseResolution = GRuntimeSettings.Instance.geometryDefault.meshBaseResolution;
|
|
ChunkGridSize = GRuntimeSettings.Instance.geometryDefault.chunkGridSize;
|
|
LODCount = GRuntimeSettings.Instance.geometryDefault.lodCount;
|
|
DisplacementSeed = GRuntimeSettings.Instance.geometryDefault.displacementSeed;
|
|
DisplacementStrength = GRuntimeSettings.Instance.geometryDefault.displacementStrength;
|
|
AlbedoToVertexColorMode = GRuntimeSettings.Instance.geometryDefault.albedoToVertexColorMode;
|
|
StorageMode = GRuntimeSettings.Instance.geometryDefault.storageMode;
|
|
AllowTimeSlicedGeneration = GRuntimeSettings.Instance.geometryDefault.allowTimeSlicedGeneration;
|
|
SmoothNormal = GRuntimeSettings.Instance.geometryDefault.smoothNormal;
|
|
UseSmoothNormalMask = GRuntimeSettings.Instance.geometryDefault.useSmoothNormalMask;
|
|
MergeUv = GRuntimeSettings.Instance.geometryDefault.mergeUv;
|
|
}
|
|
|
|
public void ResetFull()
|
|
{
|
|
Reset();
|
|
GCommon.FillTexture(HeightMap, Color.clear);
|
|
SetRegionDirty(GCommon.UnitRect);
|
|
TerrainData.SetDirty(GTerrainData.DirtyFlags.GeometryTimeSliced);
|
|
}
|
|
|
|
private void ResampleHeightMap()
|
|
{
|
|
if (heightMap == null)
|
|
return;
|
|
Texture2D tmp = GCommon.CreateTexture(HeightMapResolution, Color.clear, HeightMapFormat);
|
|
RenderTexture rt = new RenderTexture(HeightMapResolution, HeightMapResolution, 32, HeightMapRTFormat);
|
|
|
|
GCommon.CopyTexture(heightMap, tmp);
|
|
tmp.name = heightMap.name;
|
|
tmp.filterMode = heightMap.filterMode;
|
|
tmp.wrapMode = heightMap.wrapMode;
|
|
Object.DestroyImmediate(heightMap, true);
|
|
heightMap = tmp;
|
|
GCommon.TryAddObjectToAsset(heightMap, TerrainData);
|
|
|
|
Internal_CreateNewSubDivisionMap();
|
|
SetRegionDirty(GCommon.UnitRect);
|
|
}
|
|
|
|
private void ReFormatHeightMap()
|
|
{
|
|
if (heightMap == null)
|
|
return;
|
|
if (heightmapVersion < HEIGHT_MAP_VERSION_ENCODE_RG)
|
|
{
|
|
Texture2D tmp = GCommon.CreateTexture(HeightMapResolution, Color.clear, HeightMapFormat);
|
|
RenderTexture rt = new RenderTexture(HeightMapResolution, HeightMapResolution, 32, HeightMapRTFormat);
|
|
Material mat = GInternalMaterials.HeightmapConverterEncodeRGMaterial;
|
|
mat.SetTexture("_MainTex", heightMap);
|
|
GCommon.DrawQuad(rt, GCommon.FullRectUvPoints, mat, 0);
|
|
GCommon.CopyFromRT(tmp, rt);
|
|
rt.Release();
|
|
Object.DestroyImmediate(rt);
|
|
|
|
tmp.name = heightMap.name;
|
|
tmp.filterMode = heightMap.filterMode;
|
|
tmp.wrapMode = heightMap.wrapMode;
|
|
Object.DestroyImmediate(heightMap, true);
|
|
heightMap = tmp;
|
|
GCommon.TryAddObjectToAsset(heightMap, TerrainData);
|
|
|
|
heightmapVersion = HEIGHT_MAP_VERSION_ENCODE_RG;
|
|
Debug.Log("Polaris auto upgrade: Converted Height Map from RGBAFloat to RGBA32.");
|
|
}
|
|
}
|
|
|
|
internal void Internal_CreateNewSubDivisionMap()
|
|
{
|
|
if (subDivisionMap != null)
|
|
{
|
|
if (subDivisionMap.width != GCommon.SUB_DIV_MAP_RESOLUTION ||
|
|
subDivisionMap.height != GCommon.SUB_DIV_MAP_RESOLUTION)
|
|
Object.DestroyImmediate(subDivisionMap);
|
|
}
|
|
|
|
if (subDivisionMap == null)
|
|
{
|
|
subDivisionMap = new Texture2D(GCommon.SUB_DIV_MAP_RESOLUTION, GCommon.SUB_DIV_MAP_RESOLUTION, TextureFormat.RGBA32, false);
|
|
}
|
|
|
|
int resolution = GCommon.SUB_DIV_MAP_RESOLUTION;
|
|
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32);
|
|
Material mat = GInternalMaterials.SubDivisionMapMaterial;
|
|
Graphics.Blit(HeightMap, rt, mat);
|
|
GCommon.CopyFromRT(subDivisionMap, rt);
|
|
rt.Release();
|
|
Object.DestroyImmediate(rt);
|
|
}
|
|
|
|
internal void Internal_CreateNewSubDivisionMap(Texture altHeightMap)
|
|
{
|
|
if (subDivisionMap != null)
|
|
{
|
|
if (subDivisionMap.width != GCommon.SUB_DIV_MAP_RESOLUTION ||
|
|
subDivisionMap.height != GCommon.SUB_DIV_MAP_RESOLUTION)
|
|
Object.DestroyImmediate(subDivisionMap);
|
|
}
|
|
|
|
if (subDivisionMap == null)
|
|
{
|
|
subDivisionMap = new Texture2D(GCommon.SUB_DIV_MAP_RESOLUTION, GCommon.SUB_DIV_MAP_RESOLUTION, TextureFormat.ARGB32, false);
|
|
}
|
|
|
|
int resolution = GCommon.SUB_DIV_MAP_RESOLUTION;
|
|
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32);
|
|
Material mat = GInternalMaterials.SubDivisionMapMaterial;
|
|
Graphics.Blit(altHeightMap, rt, mat);
|
|
GCommon.CopyFromRT(subDivisionMap, rt);
|
|
rt.Release();
|
|
Object.DestroyImmediate(rt);
|
|
}
|
|
|
|
public void CleanUp()
|
|
{
|
|
int count = 0;
|
|
List<Vector3Int> keys = TerrainData.GeometryData.GetKeys();
|
|
for (int i = 0; i < keys.Count; ++i)
|
|
{
|
|
bool delete = false;
|
|
try
|
|
{
|
|
int indexX = keys[i].x;
|
|
int indexY = keys[i].y;
|
|
int lod = keys[i].z;
|
|
if (indexX >= ChunkGridSize || indexY >= ChunkGridSize)
|
|
{
|
|
delete = true;
|
|
}
|
|
else if (lod >= LODCount)
|
|
{
|
|
delete = true;
|
|
}
|
|
else
|
|
{
|
|
delete = false;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
delete = false;
|
|
}
|
|
|
|
if (delete)
|
|
{
|
|
count += 1;
|
|
TerrainData.GeometryData.DeleteMesh(keys[i]);
|
|
}
|
|
}
|
|
|
|
if (count > 0)
|
|
{
|
|
Debug.Log(string.Format("Deleted {0} object{1} from generated data!", count, count > 1 ? "s" : ""));
|
|
}
|
|
}
|
|
|
|
public void SetRegionDirty(Rect uvRect)
|
|
{
|
|
DirtyRegion.Add(uvRect);
|
|
}
|
|
|
|
public void SetRegionDirty(IEnumerable<Rect> uvRects)
|
|
{
|
|
DirtyRegion.AddRange(uvRects);
|
|
}
|
|
|
|
public Rect[] GetDirtyRegions()
|
|
{
|
|
return DirtyRegion.ToArray();
|
|
}
|
|
|
|
public void ClearDirtyRegions()
|
|
{
|
|
DirtyRegion.Clear();
|
|
}
|
|
|
|
public void CopyTo(GGeometry des)
|
|
{
|
|
des.Width = Width;
|
|
des.Height = Height;
|
|
des.Length = Length;
|
|
des.HeightMapResolution = HeightMapResolution;
|
|
des.MeshResolution = MeshResolution;
|
|
des.MeshBaseResolution = MeshBaseResolution;
|
|
des.ChunkGridSize = ChunkGridSize;
|
|
des.LODCount = LODCount;
|
|
des.DisplacementSeed = DisplacementSeed;
|
|
des.DisplacementStrength = DisplacementStrength;
|
|
des.AlbedoToVertexColorMode = AlbedoToVertexColorMode;
|
|
des.StorageMode = StorageMode;
|
|
des.AllowTimeSlicedGeneration = AllowTimeSlicedGeneration;
|
|
}
|
|
|
|
public Vector4 GetDecodedHeightMapSample(Vector2 uv)
|
|
{
|
|
Vector4 c = HeightMap.GetPixelBilinear(uv.x, uv.y);
|
|
Vector2 encodedHeight = new Vector2(c.x, c.y);
|
|
float decodedHeight = GCommon.DecodeTerrainHeight(encodedHeight);
|
|
c.x = decodedHeight;
|
|
c.y = decodedHeight;
|
|
return c;
|
|
}
|
|
|
|
public float GetHeightMapMemoryStats()
|
|
{
|
|
if (heightMap == null)
|
|
return 0;
|
|
return heightMap.width * heightMap.height * 4;
|
|
}
|
|
|
|
public void RemoveHeightMap()
|
|
{
|
|
if (heightMap != null)
|
|
{
|
|
GUtilities.DestroyObject(heightMap);
|
|
}
|
|
}
|
|
|
|
public float[,] GetHeights()
|
|
{
|
|
int res = HeightMapResolution;
|
|
float[,] samples = new float[res, res];
|
|
Vector4 color;
|
|
|
|
for (int z = 0; z < res; ++z)
|
|
{
|
|
for (int x = 0; x< res; ++x)
|
|
{
|
|
color = HeightMap.GetPixel(x, z);
|
|
float h = GCommon.DecodeTerrainHeight(color);
|
|
samples[z, x] = h;
|
|
}
|
|
}
|
|
return samples;
|
|
}
|
|
}
|
|
}
|
|
#endif
|