Initial commit
This commit is contained in:
1 parent
ee9615239e
commit
16feac691f
4093 files changed
+1030491
No files matched your search
@@ -0,0 +1,145 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// Bounds class using double precision. Will be used to just store the min max values first, but might be extended to offer similar
|
||||
/// functionality of the regular float bounds class at some point.
|
||||
/// </summary>
|
||||
///
|
||||
[System.Serializable]
|
||||
public class BoundsDouble
|
||||
{
|
||||
[SerializeField]
|
||||
Vector3Double m_Center;
|
||||
[SerializeField]
|
||||
Vector3Double m_Extents;
|
||||
|
||||
public Vector3Double center
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Center;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Center = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3Double size
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Extents * 2f;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Extents = value * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3Double extents
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Extents;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Extents = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3Double min
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.center - this.extents;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.SetMinMax(value, this.max);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3Double max
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.center + this.extents;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.SetMinMax(this.min, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMinMax(Vector3Double min, Vector3Double max)
|
||||
{
|
||||
this.extents = (max - min) * 0.5f;
|
||||
this.center = min + this.extents;
|
||||
}
|
||||
|
||||
|
||||
public BoundsDouble()
|
||||
{
|
||||
this.center = Vector3Double.zero;
|
||||
this.size = Vector3Double.zero;
|
||||
}
|
||||
|
||||
public static implicit operator Bounds(BoundsDouble bd)
|
||||
{
|
||||
return new Bounds(bd.center,bd.size);
|
||||
}
|
||||
|
||||
public static implicit operator BoundsDouble(Bounds b)
|
||||
{
|
||||
return new BoundsDouble(b.center, b.size);
|
||||
}
|
||||
|
||||
public BoundsDouble(Vector3Double center, Vector3Double size)
|
||||
{
|
||||
this.center = center;
|
||||
this.size = size;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Intersects(Bounds bounds)
|
||||
{
|
||||
return this.min.x <= bounds.max.x && this.max.x >= bounds.min.x && (this.min.y <= bounds.max.y && this.max.y >= bounds.min.y) && this.min.z <= bounds.max.z && this.max.z >= bounds.min.z;
|
||||
}
|
||||
|
||||
public bool Contains(Vector3Double point)
|
||||
{
|
||||
return min.x <= point.x && point.x <= max.x && min.y <= point.y && point.y <= max.y && min.z <= point.z && point.z <= max.z;
|
||||
}
|
||||
|
||||
public void Encapsulate(Vector3 point)
|
||||
{
|
||||
this.SetMinMax(Vector3.Min(this.min, point), Vector3.Max(this.max, point));
|
||||
}
|
||||
|
||||
public void Encapsulate(Bounds bounds)
|
||||
{
|
||||
this.Encapsulate(bounds.center - bounds.extents);
|
||||
this.Encapsulate(bounds.center + bounds.extents);
|
||||
}
|
||||
|
||||
public void Encapsulate(Vector3Double point)
|
||||
{
|
||||
this.SetMinMax(Vector3.Min(this.min, point), Vector3.Max(this.max, point));
|
||||
}
|
||||
|
||||
public void Encapsulate(BoundsDouble bounds)
|
||||
{
|
||||
this.Encapsulate(bounds.center - bounds.extents);
|
||||
this.Encapsulate(bounds.center + bounds.extents);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e01322610414ca4c9882930da92c208
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public enum ExportPreset { ExportToOBJFiles, ConvertToMesh, CreateImpostors, ConvertToMeshAndImpostors, ConvertToLowPolyMesh, ConvertToLowPolyMeshAndImpostors, Custom}
|
||||
public enum ExportSelection { AllTerrains, SingleTerrainOnly }
|
||||
public enum ConversionAction { MeshTerrain, ColliderOnly, OBJFileExport }
|
||||
public enum LODSettingsMode { Impostor, LowPoly, Custom }
|
||||
public enum SaveFormat { Triangles, Quads }
|
||||
public enum SaveResolution { Full = 0, Half, Quarter, Eighth, Sixteenth }
|
||||
public enum NormalEdgeMode { Smooth, Sharp }
|
||||
public enum TextureExportMethod { OrthographicBake, BaseMapExport }
|
||||
public enum BakeLighting { NeutralLighting, CurrentSceneLighting }
|
||||
public enum AddAlphaChannel { None, Heightmap }
|
||||
public enum ExportedTerrainShader { Standard, VertexColor }
|
||||
public enum TextureExportResolution { x32 = 32, x64 = 64, x128 = 128, x256 = 256, x512 = 512, x1024 = 1024, x2048 = 2048, x4096 = 4096, x8192 = 8192 }
|
||||
public enum SourceTerrainTreatment { Nothing, Deactivate, StoreInBackupScenes, Delete }
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class ExportTerrainLODSettings
|
||||
{
|
||||
public SaveResolution m_saveResolution = SaveResolution.Half;
|
||||
public NormalEdgeMode m_normalEdgeMode = NormalEdgeMode.Smooth;
|
||||
public LODSettingsMode m_LODSettingsMode = LODSettingsMode.Impostor;
|
||||
public bool m_settingsFoldedOut = false;
|
||||
public bool m_exportTextures = true;
|
||||
public bool m_exportNormalMaps = true;
|
||||
public bool m_exportSplatmaps = true;
|
||||
public bool m_createMaterials = true;
|
||||
public ExportedTerrainShader m_materialShader = ExportedTerrainShader.Standard;
|
||||
public bool m_bakeVertexColors = true;
|
||||
public int m_VertexColorSmoothing = 3;
|
||||
public LayerMask m_bakeLayerMask = ~0; //equals "Everything"
|
||||
public TextureExportMethod m_textureExportMethod = TextureExportMethod.OrthographicBake;
|
||||
public AddAlphaChannel m_addAlphaChannel = AddAlphaChannel.Heightmap;
|
||||
public TextureExportResolution m_textureExportResolution = TextureExportResolution.x2048;
|
||||
public BakeLighting m_bakeLighting = BakeLighting.NeutralLighting;
|
||||
public string namePrefix;
|
||||
public bool m_captureBaseMapTextures = false;
|
||||
public float m_LODGroupScreenRelativeTransitionHeight = 0.8f;
|
||||
|
||||
public bool CompareTo(ExportTerrainLODSettings compareToLOD)
|
||||
{
|
||||
if (m_saveResolution != compareToLOD.m_saveResolution ||
|
||||
m_normalEdgeMode != compareToLOD.m_normalEdgeMode ||
|
||||
m_LODSettingsMode != compareToLOD.m_LODSettingsMode ||
|
||||
m_exportTextures != compareToLOD.m_exportTextures ||
|
||||
m_exportNormalMaps != compareToLOD.m_exportNormalMaps ||
|
||||
m_exportSplatmaps != compareToLOD.m_exportSplatmaps ||
|
||||
m_createMaterials != compareToLOD.m_createMaterials ||
|
||||
m_materialShader != compareToLOD.m_materialShader ||
|
||||
m_bakeVertexColors != compareToLOD.m_bakeVertexColors ||
|
||||
m_VertexColorSmoothing != compareToLOD.m_VertexColorSmoothing ||
|
||||
m_bakeLayerMask != compareToLOD.m_bakeLayerMask ||
|
||||
m_textureExportMethod != compareToLOD.m_textureExportMethod ||
|
||||
m_addAlphaChannel != compareToLOD.m_addAlphaChannel ||
|
||||
m_textureExportResolution != compareToLOD.m_textureExportResolution ||
|
||||
m_bakeLighting != compareToLOD.m_bakeLighting ||
|
||||
m_captureBaseMapTextures != compareToLOD.m_captureBaseMapTextures)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class ExportTerrainSettings : ScriptableObject, ISerializationCallbackReceiver
|
||||
{
|
||||
//public bool m_deactivateOriginalTerrains = true;
|
||||
public SourceTerrainTreatment m_sourceTerrainTreatment = SourceTerrainTreatment.Deactivate;
|
||||
public SaveFormat m_saveFormat = SaveFormat.Triangles;
|
||||
public bool m_addMeshCollider = true;
|
||||
public bool m_addMeshColliderImpostor = true;
|
||||
public ExportSelection m_exportSelection = ExportSelection.AllTerrains;
|
||||
public Texture2D m_terrainExportMask;
|
||||
public Gaia.GaiaConstants.ImageChannel m_terrainExportMaskChannel = GaiaConstants.ImageChannel.R;
|
||||
public bool m_terrainExportInvertMask = false;
|
||||
public bool m_copyGaiaGameObjects = true;
|
||||
public bool m_copyGaiaGameObjectsImpostor = false;
|
||||
public bool m_convertSourceTerrains = false;
|
||||
public ConversionAction m_convertSourceTerrainsAction = ConversionAction.MeshTerrain;
|
||||
public SaveResolution m_colliderExportResolution = SaveResolution.Full;
|
||||
public bool m_colliderExportAddTreeColliders = true;
|
||||
public bool m_colliderExportAddGameObjectColliders = true;
|
||||
public bool m_colliderExportCreateColliderScenes = true;
|
||||
public bool m_colliderExportBakeCombinedCollisionMesh = true;
|
||||
public bool m_createImpostorScenes = false;
|
||||
public List<ExportTerrainLODSettings> m_exportTerrainLODSettingsSourceTerrains = new List<ExportTerrainLODSettings>();
|
||||
public List<ExportTerrainLODSettings> m_exportTerrainLODSettingsImpostors = new List<ExportTerrainLODSettings>();
|
||||
public string m_exportPath;
|
||||
//public LODSettingsMode m_exportPreset = LODSettingsMode.Impostor;
|
||||
public ExportPreset m_newExportPreset = ExportPreset.ConvertToMesh;
|
||||
public bool m_customSettingsFoldedOut;
|
||||
public int m_presetIndex = -99;
|
||||
public string m_lastUsedPresetName = "";
|
||||
public Mesh m_colliderTreeReplacement = null;
|
||||
|
||||
public bool CompareTo(ExportTerrainSettings compareSettings)
|
||||
{
|
||||
if (m_saveFormat != compareSettings.m_saveFormat ||
|
||||
m_addMeshCollider != compareSettings.m_addMeshCollider ||
|
||||
m_addMeshColliderImpostor != compareSettings.m_addMeshColliderImpostor ||
|
||||
m_terrainExportMask != compareSettings.m_terrainExportMask ||
|
||||
m_terrainExportMaskChannel != compareSettings.m_terrainExportMaskChannel ||
|
||||
m_terrainExportInvertMask != compareSettings.m_terrainExportInvertMask ||
|
||||
m_convertSourceTerrainsAction != compareSettings.m_convertSourceTerrainsAction ||
|
||||
m_colliderExportResolution != compareSettings.m_colliderExportResolution ||
|
||||
m_colliderExportCreateColliderScenes != compareSettings.m_colliderExportCreateColliderScenes ||
|
||||
m_colliderExportAddTreeColliders != compareSettings.m_colliderExportAddTreeColliders ||
|
||||
m_colliderExportAddGameObjectColliders != compareSettings.m_colliderExportAddGameObjectColliders ||
|
||||
m_copyGaiaGameObjects != compareSettings.m_copyGaiaGameObjects ||
|
||||
m_copyGaiaGameObjectsImpostor != compareSettings.m_copyGaiaGameObjectsImpostor ||
|
||||
m_convertSourceTerrains != compareSettings.m_convertSourceTerrains ||
|
||||
m_createImpostorScenes != compareSettings.m_createImpostorScenes)
|
||||
return false;
|
||||
|
||||
if (m_exportTerrainLODSettingsSourceTerrains.Count != compareSettings.m_exportTerrainLODSettingsSourceTerrains.Count)
|
||||
return false;
|
||||
if (m_exportTerrainLODSettingsImpostors.Count != compareSettings.m_exportTerrainLODSettingsImpostors.Count)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < m_exportTerrainLODSettingsSourceTerrains.Count; i++)
|
||||
{
|
||||
if (!m_exportTerrainLODSettingsSourceTerrains[i].CompareTo(compareSettings.m_exportTerrainLODSettingsSourceTerrains[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_exportTerrainLODSettingsSourceTerrains.Count; i++)
|
||||
{
|
||||
if (!m_exportTerrainLODSettingsSourceTerrains[i].CompareTo(compareSettings.m_exportTerrainLODSettingsSourceTerrains[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region Serialization
|
||||
|
||||
public void OnBeforeSerialize()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21e8ff62d6df01841b560dfaec24f3a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3802c93c5db497459e9988a3577489e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,415 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Fractal generator
|
||||
/// </summary>
|
||||
public class FractalGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// The types of fractals we support
|
||||
/// </summary>
|
||||
public enum Fractals { Perlin, Billow, RidgeMulti };
|
||||
|
||||
/// <summary>
|
||||
/// Seed - different seeds generate replicable different fractals
|
||||
/// </summary>
|
||||
private float m_seed = 0;
|
||||
public float Seed
|
||||
{
|
||||
get { return m_seed; }
|
||||
set { m_seed = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The amount of detail in the fractal - more octaves mean more detail and longer calc time.
|
||||
/// </summary>
|
||||
private int m_octaves = 8;
|
||||
public int Octaves
|
||||
{
|
||||
get { return m_octaves; }
|
||||
set { m_octaves = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The roughness of the fractal noise. Controls how quickly amplitudes diminish for successive octaves. 0..1.
|
||||
/// </summary>
|
||||
private float m_persistence = 0.65f;
|
||||
public float Persistence
|
||||
{
|
||||
get { return m_persistence; }
|
||||
set { m_persistence = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The frequency of the first octave
|
||||
/// </summary>
|
||||
private float m_frequency = 1f;
|
||||
public float Frequency
|
||||
{
|
||||
get { return m_frequency; }
|
||||
set { m_frequency = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The frequency multiplier between successive octaves. Experiment between 1.5 - 3.5.
|
||||
/// </summary>
|
||||
private float m_lacunarity = 1.5f;
|
||||
public float Lacunarity
|
||||
{
|
||||
get { return m_lacunarity; }
|
||||
set { m_lacunarity = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offset X by a given value, allows local fractal area to be explored.
|
||||
/// </summary>
|
||||
private float m_XOffset = 0f;
|
||||
public float XOffset
|
||||
{
|
||||
get { return m_XOffset; }
|
||||
set { m_XOffset = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offset height by a given value. Decease to get islands, increease to get plateaus.
|
||||
/// </summary>
|
||||
private float m_ZOffset = 0f;
|
||||
public float ZOffset
|
||||
{
|
||||
get { return m_ZOffset; }
|
||||
set { m_ZOffset = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offset Y by a given value, allows local fractal area to be explored.
|
||||
/// </summary>
|
||||
private float m_YOffset = 0f;
|
||||
public float YOffset
|
||||
{
|
||||
get { return m_YOffset; }
|
||||
set { m_YOffset = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type of fractal we are generating
|
||||
/// </summary>
|
||||
private Fractals m_fractalType = Fractals.Perlin;
|
||||
public Fractals FractalType
|
||||
{
|
||||
get { return m_fractalType; }
|
||||
set
|
||||
{
|
||||
m_fractalType = value;
|
||||
switch (m_fractalType)
|
||||
{
|
||||
case Fractals.Perlin:
|
||||
{
|
||||
m_noiseCalculator = GetValue_Perlin;
|
||||
break;
|
||||
}
|
||||
case Fractals.Billow:
|
||||
{
|
||||
m_noiseCalculator = GetValue_Billow;
|
||||
break;
|
||||
}
|
||||
case Fractals.RidgeMulti:
|
||||
{
|
||||
CalcSpectralWeights();
|
||||
m_noiseCalculator = GetValue_RidgedMulti;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float[] m_spectralWeights = new float[20]; //Used by ridged fractal
|
||||
private delegate float GetCalcValue(float x, float z); //Switch in the relevant fractal algorithm
|
||||
private GetCalcValue m_noiseCalculator; //Switch in the relevant fractal algorithm
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public FractalGenerator()
|
||||
{
|
||||
FractalType = Fractals.Perlin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct and initialise a fractal generator
|
||||
/// </summary>
|
||||
/// <param name="frequency">The frequency of the first octave</param>
|
||||
/// <param name="lacunarity">The frequency multiplier between successive octaves. Experiment between 1.5 - 3.5.</param>
|
||||
/// <param name="octaves">The amount of detail in the fractal - more octaves mean more detail and longer calc time.</param>
|
||||
/// <param name="persistance">The roughness of the fractal noise. Controls how quickly amplitudes diminish for successive octaves. 0..1.</param>
|
||||
/// <param name="seed">Seed - different seeds generate replicable different fractals</param>
|
||||
/// <param name="type">The type of generator being used</param>
|
||||
public FractalGenerator(float frequency, float lacunarity, int octaves, float persistance, float seed, Fractals type)
|
||||
{
|
||||
m_frequency = frequency;
|
||||
m_lacunarity = lacunarity;
|
||||
m_octaves = octaves;
|
||||
m_persistence = persistance;
|
||||
m_seed = seed;
|
||||
switch (type)
|
||||
{
|
||||
case Fractals.Perlin:
|
||||
m_noiseCalculator = GetValue_Perlin;
|
||||
break;
|
||||
case Fractals.Billow:
|
||||
m_noiseCalculator = GetValue_Billow;
|
||||
break;
|
||||
case Fractals.RidgeMulti:
|
||||
CalcSpectralWeights();
|
||||
m_noiseCalculator = GetValue_RidgedMulti;
|
||||
break;
|
||||
default:
|
||||
m_noiseCalculator = GetValue_Perlin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set some reasonable defaults for the fractal type
|
||||
/// </summary>
|
||||
public void SetDefaults()
|
||||
{
|
||||
switch (m_fractalType)
|
||||
{
|
||||
case Fractals.Perlin:
|
||||
{
|
||||
m_frequency = 1f;
|
||||
m_lacunarity = 2f;
|
||||
m_octaves = 6;
|
||||
m_persistence = 0.5f;
|
||||
m_seed = 0;
|
||||
m_noiseCalculator = GetValue_Perlin;
|
||||
break;
|
||||
}
|
||||
case Fractals.Billow:
|
||||
{
|
||||
m_frequency = 1f;
|
||||
m_lacunarity = 2f;
|
||||
m_octaves = 6;
|
||||
m_persistence = 0.5f;
|
||||
m_seed = 0;
|
||||
m_noiseCalculator = GetValue_Billow;
|
||||
break;
|
||||
}
|
||||
case Fractals.RidgeMulti:
|
||||
{
|
||||
m_frequency = 1f;
|
||||
m_lacunarity = 2f;
|
||||
m_octaves = 6;
|
||||
m_seed = 0;
|
||||
CalcSpectralWeights();
|
||||
m_noiseCalculator = GetValue_RidgedMulti;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the noise value at this point
|
||||
/// </summary>
|
||||
/// <param name="x">x location</param>
|
||||
/// <param name="z">z location</param>
|
||||
/// <returns></returns>
|
||||
public float GetValue(float x, float z)
|
||||
{
|
||||
return m_noiseCalculator(x, z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the noise value at this point
|
||||
/// </summary>
|
||||
/// <param name="x">x location</param>
|
||||
/// <param name="z">z location</param>
|
||||
/// <returns>Value at this point</returns>
|
||||
public double GetValue(double x, double z)
|
||||
{
|
||||
return GetValue((float)x, (float)z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the noise value at this point
|
||||
/// </summary>
|
||||
/// <param name="x">x location</param>
|
||||
/// <param name="z">z location</param>
|
||||
/// <returns>Value in range 0..1 at this point</returns>
|
||||
public float GetNormalisedValue(float x, float z)
|
||||
{
|
||||
return Mathf.Clamp01((GetValue(x, z) + 1f) / 2f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the noise value at this point
|
||||
/// </summary>
|
||||
/// <param name="x">x location</param>
|
||||
/// <param name="z">z location</param>
|
||||
/// <returns>Value in range 0..1 at this point</returns>
|
||||
public double GetNormalisedValue(double x, double z)
|
||||
{
|
||||
return GetNormalisedValue((float)x, (float)z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate a perlin fractal
|
||||
/// </summary>
|
||||
/// <param name="x">x location</param>
|
||||
/// <param name="z">z location</param>
|
||||
/// <returns></returns>
|
||||
public float GetValue_Perlin(float x, float z)
|
||||
{
|
||||
float value = 0f;
|
||||
float signal = 0f;
|
||||
float persistence = 1f;
|
||||
float nx, nz;
|
||||
|
||||
x += m_seed;
|
||||
z += m_seed;
|
||||
x += m_XOffset;
|
||||
z += m_ZOffset;
|
||||
x *= m_frequency;
|
||||
z *= m_frequency;
|
||||
|
||||
for (int octave = 0; octave < m_octaves; octave++)
|
||||
{
|
||||
nx = x;
|
||||
nz = z;
|
||||
signal = SimplexNoiseGenerator.Generate(nx, nz);
|
||||
value += signal * persistence;
|
||||
x *= m_lacunarity;
|
||||
z *= m_lacunarity;
|
||||
persistence *= m_persistence;
|
||||
}
|
||||
|
||||
value += m_YOffset * 2.4f;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate a billow fractal
|
||||
/// </summary>
|
||||
/// <param name="x">x location</param>
|
||||
/// <param name="z">z location</param>
|
||||
/// <returns></returns>
|
||||
public float GetValue_Billow(float x, float z)
|
||||
{
|
||||
float value = 0f;
|
||||
float signal = 0f;
|
||||
float persistence = 1f;
|
||||
float nx, nz;
|
||||
|
||||
x += m_seed;
|
||||
z += m_seed;
|
||||
|
||||
x += m_XOffset;
|
||||
z += m_ZOffset;
|
||||
x *= m_frequency;
|
||||
z *= m_frequency;
|
||||
|
||||
for (int octave = 0; octave < m_octaves; octave++)
|
||||
{
|
||||
nx = x;
|
||||
nz = z;
|
||||
signal = SimplexNoiseGenerator.Generate(nx, nz);
|
||||
signal = 2f * Mathf.Abs(signal) - 1f;
|
||||
value += signal * persistence;
|
||||
x *= m_lacunarity;
|
||||
z *= m_lacunarity;
|
||||
persistence *= m_persistence;
|
||||
}
|
||||
|
||||
value += m_YOffset * 2.4f;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate a ridged multi fractal
|
||||
/// </summary>
|
||||
/// <param name="x">x location</param>
|
||||
/// <param name="z">z location</param>
|
||||
/// <returns></returns>
|
||||
public float GetValue_RidgedMulti(float x, float z)
|
||||
{
|
||||
float signal = 0.0f;
|
||||
float value = 0.0f;
|
||||
float weight = 1.0f;
|
||||
float offset = 1f;
|
||||
float gain = m_persistence;
|
||||
float nx, nz;
|
||||
|
||||
x += m_seed;
|
||||
z += m_seed;
|
||||
x += m_XOffset;
|
||||
z += m_ZOffset;
|
||||
x *= m_frequency;
|
||||
z *= m_frequency;
|
||||
|
||||
for (int octave = 0; octave < m_octaves; octave++)
|
||||
{
|
||||
nx = x;
|
||||
nz = z;
|
||||
|
||||
//Get the coherent-noise value from input value and add it to final result
|
||||
signal = SimplexNoiseGenerator.Generate(nx, nz);
|
||||
|
||||
//Make the ridges
|
||||
signal = Mathf.Abs(signal);
|
||||
signal = offset - signal;
|
||||
|
||||
//Square signal to increase sharpness of ridges.
|
||||
signal *= signal;
|
||||
|
||||
//The weighting from previous octave is applied to the signal.
|
||||
signal *= weight;
|
||||
|
||||
//Weight successive contributions by previous signal.
|
||||
weight = signal * gain;
|
||||
if (weight > 1.0)
|
||||
{
|
||||
weight = 1.0f;
|
||||
}
|
||||
if (weight < 0.0f)
|
||||
{
|
||||
weight = 0.0f;
|
||||
}
|
||||
|
||||
//Add the signal to output value.
|
||||
value += signal * m_spectralWeights[octave];
|
||||
|
||||
//Next Octave
|
||||
x *= m_lacunarity;
|
||||
z *= m_lacunarity;
|
||||
}
|
||||
|
||||
value = (value * 1.25f) - 1.0f;
|
||||
|
||||
value += m_YOffset;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate spectral weights for the ridged fractal
|
||||
/// </summary>
|
||||
private void CalcSpectralWeights()
|
||||
{
|
||||
float h = 1.0f;
|
||||
float frequency = 1.0f;
|
||||
int maxSpectra = m_spectralWeights.GetLength(0);
|
||||
for (int i = 0; i < maxSpectra; i++)
|
||||
{
|
||||
m_spectralWeights[i] = Mathf.Pow(frequency, -h);
|
||||
frequency *= m_lacunarity;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fc7d4487628fdf43b722927dad252e3
|
||||
timeCreated: 1449268396
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,495 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
|
||||
public static class GaiaDirectories
|
||||
{
|
||||
public const string SESSION_OPERATIONS_DIRECTORY = "/Session Operations";
|
||||
public const string SESSION_SCENE_PROFILE_DIRECTORY = "/Scene Profiles";
|
||||
public const string TERRAIN_SCENES_DIRECTORY = "/Terrain Scenes";
|
||||
public const string IMPOSTOR_SCENES_DIRECTORY = "/Impostor Scenes";
|
||||
public const string COLLIDER_SCENES_DIRECTORY = "/Collider Scenes";
|
||||
public const string BACKUP_SCENES_DIRECTORY = "/Backup Scenes";
|
||||
public const string TERRAIN_DATA_DIRECTORY = "/Terrain Data";
|
||||
public const string SETTINGS_DIRECTORY = "/Settings";
|
||||
public const string STAMP_DIRECTORY = "/Stamps";
|
||||
public const string USER_STAMP_DIRECTORY = "/My Saved Stamps";
|
||||
public const string TERRAIN_LAYERS_DIRECTORY = "/Terrain Layers";
|
||||
public const string EXPORT_DIRECTORY = "/Exports";
|
||||
public const string STAMPER_EXPORT_DIRECTORY = "/Stamper Exports";
|
||||
public const string STAMPER_TERRAIN_EXPORT_DIRECTORY = "/Stamper Terrain Exports";
|
||||
public const string SCANNER_EXPORT_DIRECTORY = "/Scanner Exports";
|
||||
public const string MASK_MAP_EXPORT_DIRECTORY = "/Mask Maps";
|
||||
public const string COLLISION_DATA_DIRECTORY = "/TerrainCollisionData";
|
||||
public const string GAIA_PRO = "/Procedural Worlds/Gaia/Gaia Pro";
|
||||
public const string GAIA_SHADER_DIRECTORY = "/Procedural Worlds/PW Shader Library";
|
||||
public const string TERRAIN_MESH_EXPORT_DIRECTORY = "/Mesh Terrains";
|
||||
public const string GAIA_WATER_MATERIAL_DIRECTORY = "/Gaia Lighting and Water/Gaia Water/Ocean Water/Resources/Material";
|
||||
public const string TEMP_EXPORT_PATH = "Assets/Temp Export";
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Gaia Pro folder exists in the project
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool GetGaiaProDirectory()
|
||||
{
|
||||
bool isPro = false;
|
||||
string dataPath = Application.dataPath;
|
||||
|
||||
if (Directory.Exists(dataPath + GAIA_PRO))
|
||||
{
|
||||
isPro = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isPro = false;
|
||||
}
|
||||
|
||||
return isPro;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the Gaia directory in the project
|
||||
/// </summary>
|
||||
/// <returns>String containing the Gaia directory</returns>
|
||||
public static string GetGaiaDirectory()
|
||||
{
|
||||
//Default Directory, will be returned if not in Editor
|
||||
string gaiaDirectory = "Assets/Procedural Worlds/Gaia/";
|
||||
#if UNITY_EDITOR
|
||||
string[] assets = AssetDatabase.FindAssets("Gaia_ReadMe", null);
|
||||
for (int idx = 0; idx < assets.Length; idx++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(assets[idx]);
|
||||
if (Path.GetFileName(path) == "Gaia_ReadMe.txt")
|
||||
{
|
||||
gaiaDirectory = path.Replace("/Gaia_ReadMe.txt","");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return gaiaDirectory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Gaia Session Directory. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Session directory</returns>
|
||||
public static string GetSessionDirectory()
|
||||
{
|
||||
GaiaSettings gaiaSettings = GaiaUtils.GetGaiaSettings();
|
||||
Directory.CreateDirectory(gaiaSettings.m_sessionsDirectory);
|
||||
return gaiaSettings.m_sessionsDirectory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Gaia Data Directory. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Data directory</returns>
|
||||
public static string GetSettingsDirectory()
|
||||
{
|
||||
return GetGaiaSubDirectory(SETTINGS_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to store terrain scenes in, according to the session filename
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The session to get / create this path for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetTerrainScenePathForSession(GaiaSession gaiaSession=null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetScenePath(gaiaSession) + TERRAIN_SCENES_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to store terrain scenes in, according to the Terrain Scene Storage scriptable object
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The session to get / create this path for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetTerrainScenePathForStorageFile(TerrainSceneStorage terrainSceneStorage = null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (terrainSceneStorage == null)
|
||||
{
|
||||
terrainSceneStorage = TerrainLoaderManager.Instance.TerrainSceneStorage;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(AssetDatabase.GetAssetPath(terrainSceneStorage).Replace(terrainSceneStorage.name + ".asset","") + TERRAIN_SCENES_DIRECTORY);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to store impostor scenes in, according to the session filename
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The session to get / create this path for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetImpostorScenePath(GaiaSession gaiaSession = null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetScenePath(gaiaSession) + IMPOSTOR_SCENES_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to store collider scenes in, according to the session filename
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The session to get / create this path for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetColliderScenePath(GaiaSession gaiaSession = null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetScenePath(gaiaSession) + COLLIDER_SCENES_DIRECTORY);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to store impostor scenes in, according to the session filename
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The session to get / create this path for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetBackupScenePath(GaiaSession gaiaSession = null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetScenePath(gaiaSession) + BACKUP_SCENES_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a path to store scriptable object data for the session operations.
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The session to create the directory for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetSessionOperationPath(GaiaSession gaiaSession, bool create = true)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return CreatePathIfDoesNotExist(GetSessionSubFolderPath(gaiaSession, create) + SESSION_OPERATIONS_DIRECTORY);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a folder that is named as the session asset, to store session related data into.
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The session to create the directory for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetSessionSubFolderPath(GaiaSession gaiaSession, bool create = true)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string masterScenePath = AssetDatabase.GetAssetPath(gaiaSession).Replace(".asset", "");
|
||||
if (String.IsNullOrEmpty(masterScenePath))
|
||||
{
|
||||
GaiaSessionManager gsm = GaiaSessionManager.GetSessionManager(false);
|
||||
gsm.SaveSession();
|
||||
masterScenePath = AssetDatabase.GetAssetPath(gsm.m_session).Replace(".asset", "");
|
||||
}
|
||||
if (create)
|
||||
return CreatePathIfDoesNotExist(masterScenePath);
|
||||
else
|
||||
return masterScenePath;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
public static string GetSceneProfilesFolderPath(GaiaSession gaiaSession, bool create = true)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return CreatePathIfDoesNotExist(GetSessionSubFolderPath(gaiaSession, create) + SESSION_SCENE_PROFILE_DIRECTORY);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to store scene files in, according to the Gaia Session path
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The session to get / create the directory for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetScenePath(GaiaSession gaiaSession = null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return GetSessionSubFolderPath(gaiaSession);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to store terrain scenes in, according to the session filename
|
||||
/// /// </summary>
|
||||
/// <param name="gaiaSession">The current session to get / create this directory for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetTerrainDataScenePath(GaiaSession gaiaSession = null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetScenePath(gaiaSession) + TERRAIN_DATA_DIRECTORY);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a path for temporary exports (before they are copied to the final destination outside the "Assets" folder)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetTempExportPath()
|
||||
{
|
||||
return TEMP_EXPORT_PATH;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to store terrain layer files in
|
||||
/// </summary>
|
||||
/// <param name="gaiaSession">The current session to get / create this directory for</param>
|
||||
/// <returns></returns>
|
||||
public static string GetTerrainLayerPath(GaiaSession gaiaSession = null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetScenePath(gaiaSession) + TERRAIN_LAYERS_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Gaia Stamps Directory. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Stamps directory</returns>
|
||||
public static string GetStampDirectory()
|
||||
{
|
||||
return GetGaiaSubDirectory(STAMP_DIRECTORY);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Gaia Mask Export Directory. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Stamps directory</returns>
|
||||
//public static string GetMaskDirectory()
|
||||
//{
|
||||
// return GetGaiaSubDirectory(MASK_DIRECTORY);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Gaia Mask Export Directory. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Stamps directory</returns>
|
||||
public static string GetExportDirectory(GaiaSession gaiaSession = null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetScenePath(gaiaSession) + EXPORT_DIRECTORY);
|
||||
}
|
||||
|
||||
public static string GetUserBiomeDirectory(string biomeName ="")
|
||||
{
|
||||
GaiaSettings gaiaSettings = GaiaUtils.GetGaiaSettings();
|
||||
//If no biome name was passed in, return the path to the root biome user data folder
|
||||
if (biomeName != "")
|
||||
{
|
||||
return CreatePathIfDoesNotExist(gaiaSettings.m_biomesDirectory + "/" + biomeName.Replace(" Biome", ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreatePathIfDoesNotExist(gaiaSettings.m_biomesDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetUserSettingsDirectory()
|
||||
{
|
||||
GaiaSettings gaiaSettings = GaiaUtils.GetGaiaSettings();
|
||||
return CreatePathIfDoesNotExist(gaiaSettings.m_userSettingsDirectory);
|
||||
}
|
||||
|
||||
|
||||
public static string GetMaskMapExportDirectory(GaiaSession gaiaSession =null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetExportDirectory(gaiaSession) + MASK_MAP_EXPORT_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Gaia User Stamp directory. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Stamps directory</returns>
|
||||
public static string GetUserStampDirectory()
|
||||
{
|
||||
GaiaSettings gaiaSettings = GaiaUtils.GetGaiaSettings();
|
||||
return CreatePathIfDoesNotExist(gaiaSettings.m_userStampsDirectory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default stamper export directory within the user folder. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Stamps directory</returns>
|
||||
public static string GetStamperExportsDirectory()
|
||||
{
|
||||
return CreatePathIfDoesNotExist(GetUserStampDirectory() + STAMPER_EXPORT_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default stamper terrain export directory within the user folder. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Stamps directory</returns>
|
||||
public static string GetStamperTerrainExportsDirectory()
|
||||
{
|
||||
return CreatePathIfDoesNotExist(GetUserStampDirectory() + STAMPER_TERRAIN_EXPORT_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default scanner export directory within the user folder. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Stamps directory</returns>
|
||||
public static string GetScannerExportDirectory()
|
||||
{
|
||||
return CreatePathIfDoesNotExist(GetUserStampDirectory() + SCANNER_EXPORT_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Gaia Collision Data Directory. Will create it if it does not exist.
|
||||
/// </summary>
|
||||
/// <returns>The path to the Gaia Stamps directory</returns>
|
||||
public static string GetCollisionDataDirectory()
|
||||
{
|
||||
return GetGaiaSubDirectory(COLLISION_DATA_DIRECTORY, false);
|
||||
}
|
||||
|
||||
public static string GetTerrainMeshExportDirectory(GaiaSession gaiaSession=null)
|
||||
{
|
||||
if (gaiaSession == null)
|
||||
{
|
||||
gaiaSession = GaiaSessionManager.GetSessionManager().m_session;
|
||||
}
|
||||
return CreatePathIfDoesNotExist(GetExportDirectory(gaiaSession) + TERRAIN_MESH_EXPORT_DIRECTORY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and returns the path to a certain stamp feature type.
|
||||
/// </summary>
|
||||
/// <param name="featureType">The feature type which we want to create / get the folder for.</param>
|
||||
/// <returns>The path to the specific stamp feature insisde the stamps folder.</returns>
|
||||
public static string GetStampFeatureDirectory(GaiaConstants.FeatureType featureType)
|
||||
{
|
||||
return CreatePathIfDoesNotExist(GetStampDirectory() + "/" + featureType.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and returns the path to a certain terrain's baked collision data.
|
||||
/// </summary>
|
||||
/// <param name="terrain">The terrain for which we want to create / get the folder for.</param>
|
||||
/// <returns>The path to the collision data folder for this terrain.</returns>
|
||||
public static string GetTerrainCollisionDirectory(Terrain terrain)
|
||||
{
|
||||
return GetCollisionDataDirectory() + "/" + terrain.name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path for a specific stamp instance within the stamp / feature structure.
|
||||
/// </summary>
|
||||
/// <param name="m_featureType">The stamp feature type</param>
|
||||
/// <param name="m_featureName">The stamp name</param>
|
||||
/// <returns>The path to the specific stamp instance directory.</returns>
|
||||
public static string GetStampInstanceDirectory(GaiaConstants.FeatureType m_featureType, string m_featureName)
|
||||
{
|
||||
return CreatePathIfDoesNotExist(GetStampFeatureDirectory(m_featureType)) + "/" + m_featureName;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to a specific stamp data directory. (The Data subfolder within the stamp instance folder)
|
||||
/// </summary>
|
||||
/// <param name="m_featureType">The stamp feature type</param>
|
||||
/// <param name="m_featureName">The stamp name</param>
|
||||
/// <returns>The path to the specific stamp instance data directory.</returns>
|
||||
//public static string GetStampInstanceDataDirectory(GaiaConstants.FeatureType m_featureType, string m_featureName)
|
||||
//{
|
||||
// return CreatePathIfDoesNotExist(GetStampInstanceDirectory( m_featureType, m_featureName) + DATA_DIRECTORY);
|
||||
//}
|
||||
|
||||
public static string GetShaderDirectory()
|
||||
{
|
||||
return Application.dataPath + GAIA_SHADER_DIRECTORY;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a path to a Gaia subdirectory. The subdirectory can be optionally created if it does not exist already.
|
||||
/// </summary>
|
||||
/// <param name="subDir">The Subdir to create.</param>
|
||||
/// <param name="create">Should the subdir be created if it does not exist?</param>
|
||||
/// <returns>The complete path to the subdir.</returns>
|
||||
private static string GetGaiaSubDirectory(string subDir, bool create = true)
|
||||
{
|
||||
string path = GetGaiaDirectory() + subDir;
|
||||
if (create)
|
||||
{
|
||||
return CreatePathIfDoesNotExist(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a path exists, if not it will be created.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public static string CreatePathIfDoesNotExist(string path)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Expects a full file system path starting at a drive letter, and will return a path starting at the projects / games asset folder
|
||||
/// </summary>
|
||||
/// <param name="inputPath">Full file system path starting at a drive letter</param>
|
||||
/// <returns></returns>
|
||||
public static string GetPathStartingAtAssetsFolder(string inputPath)
|
||||
{
|
||||
return inputPath.Substring(Application.dataPath.Length - "Assets".Length);
|
||||
}
|
||||
/// <summary>
|
||||
/// Expects a path starting at the asset folder, and will return a full file system path starting at the Drive Letter
|
||||
/// </summary>
|
||||
/// <param name="inputPath">Unity path starting at the asset folder</param>
|
||||
/// <returns></returns>
|
||||
public static string GetFullFileSystemPath(string inputPath)
|
||||
{
|
||||
return Application.dataPath.Substring(Application.dataPath.Length - "Assets".Length, "Assets".Length) + inputPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02da692cce8bda742b5b55f3608ca4d5
|
||||
timeCreated: 1558370229
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,386 @@
|
||||
using UnityEngine;
|
||||
using Gaia.Pipeline;
|
||||
using UnityEngine.Rendering;
|
||||
#if HDPipeline
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
#endif
|
||||
|
||||
namespace Gaia.Pipeline.HDRP
|
||||
{
|
||||
public static class GaiaHDRPRuntimeUtils
|
||||
{
|
||||
#region Utils
|
||||
|
||||
/// <summary>
|
||||
/// Gets or creates HD camera data
|
||||
/// </summary>
|
||||
/// <param name="camera"></param>
|
||||
/// <returns></returns>
|
||||
#if HDPipeline
|
||||
public static HDAdditionalCameraData GetHDCameraData(Camera camera)
|
||||
{
|
||||
if (camera == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
HDAdditionalCameraData cameraData = camera.gameObject.GetComponent<HDAdditionalCameraData>();
|
||||
if (cameraData == null)
|
||||
{
|
||||
cameraData = camera.gameObject.AddComponent<HDAdditionalCameraData>();
|
||||
}
|
||||
|
||||
return cameraData;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or creates HD Light data
|
||||
/// </summary>
|
||||
/// <param name="light"></param>
|
||||
/// <returns></returns>
|
||||
public static HDAdditionalLightData GetHDLightData(Light light)
|
||||
{
|
||||
if (light == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
HDAdditionalLightData lightData = light.GetComponent<HDAdditionalLightData>();
|
||||
if (lightData == null)
|
||||
{
|
||||
lightData = light.gameObject.AddComponent<HDAdditionalLightData>();
|
||||
}
|
||||
|
||||
return lightData;
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Removes HDRP Post processing
|
||||
/// </summary>
|
||||
/// <param name="pipelineProfile"></param>
|
||||
public static void RemovePostProcesing(UnityPipelineProfile pipelineProfile)
|
||||
{
|
||||
GameObject postObject = GameObject.Find(pipelineProfile.m_HDPostVolumeObjectName);
|
||||
if (postObject != null)
|
||||
{
|
||||
Object.DestroyImmediate(postObject);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Configures reflections to LWRP
|
||||
/// </summary>
|
||||
public static void ConfigureReflectionProbes()
|
||||
{
|
||||
ReflectionProbe[] reflectionProbes = Object.FindObjectsOfType<ReflectionProbe>();
|
||||
if (reflectionProbes != null)
|
||||
{
|
||||
#if HDPipeline
|
||||
foreach (ReflectionProbe probe in reflectionProbes)
|
||||
{
|
||||
|
||||
if (probe.GetComponent<HDAdditionalReflectionData>() == null)
|
||||
{
|
||||
probe.gameObject.AddComponent<HDAdditionalReflectionData>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Configures and setup the terrain
|
||||
/// </summary>
|
||||
/// <param name="profile"></param>
|
||||
public static void ConfigureTerrain(UnityPipelineProfile profile)
|
||||
{
|
||||
Terrain[] terrains = Terrain.activeTerrains;
|
||||
if (terrains != null)
|
||||
{
|
||||
foreach(Terrain terrain in terrains)
|
||||
{
|
||||
terrain.materialTemplate = profile.m_highDefinitionTerrainMaterial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Syncs user HDRP profiles settings to the source.
|
||||
/// </summary>
|
||||
public static void SyncUserHDRPEnvironmentProfile()
|
||||
{
|
||||
if (GaiaGlobal.Instance.SceneProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject volumeEnvironment = GameObject.Find(GaiaConstants.HDRPEnvironmentObject);
|
||||
if (volumeEnvironment != null)
|
||||
{
|
||||
#if HDPipeline
|
||||
Volume volume = volumeEnvironment.GetComponent<Volume>();
|
||||
if (volume != null)
|
||||
{
|
||||
VolumeProfile sceneVolumeProfile = volume.sharedProfile;
|
||||
GaiaLightingProfileValues lightingProfileValues = GaiaGlobal.Instance.SceneProfile.m_lightingProfiles[GaiaGlobal.Instance.SceneProfile.m_selectedLightingProfileValuesIndex];
|
||||
if (lightingProfileValues != null)
|
||||
{
|
||||
if (lightingProfileValues.m_userCustomProfile)
|
||||
{
|
||||
VolumeProfile gaialightVolumeProfile = lightingProfileValues.EnvironmentProfileHDRP;
|
||||
if (gaialightVolumeProfile != null)
|
||||
{
|
||||
SyncHDRPVisualEnvironment(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
SyncHDRPGradientSky(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
SyncHDRPHDRISky(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
SyncHDRPPhysicallyBasedSky(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
SyncHDRPFog(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
SyncHDRPShadows(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
SyncHDRPContactShadows(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
SyncHDRPMicroShadows(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
SyncHDRPAmbientLight(sceneVolumeProfile, gaialightVolumeProfile);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
UnityEditor.EditorUtility.SetDirty(gaialightVolumeProfile);
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if HDPipeline
|
||||
private static void SyncHDRPVisualEnvironment(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneProfile.TryGet(out VisualEnvironment visualEnvironmentScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out VisualEnvironment visualEnvironmentSource))
|
||||
{
|
||||
visualEnvironmentSource.skyAmbientMode.value = visualEnvironmentScene.skyAmbientMode.value;
|
||||
visualEnvironmentSource.skyType.value = visualEnvironmentScene.skyType.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void SyncHDRPGradientSky(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneProfile.TryGet(out GradientSky gradientSkyScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out GradientSky gradientSkySource))
|
||||
{
|
||||
gradientSkySource.top.value = gradientSkyScene.top.value;
|
||||
gradientSkySource.middle.value = gradientSkyScene.middle.value;
|
||||
gradientSkySource.bottom.value = gradientSkyScene.bottom.value;
|
||||
gradientSkySource.gradientDiffusion.value = gradientSkyScene.gradientDiffusion.value;
|
||||
gradientSkySource.skyIntensityMode.value = gradientSkyScene.skyIntensityMode.value;
|
||||
gradientSkySource.exposure.value = gradientSkyScene.exposure.value;
|
||||
gradientSkySource.multiplier.value = gradientSkyScene.multiplier.value;
|
||||
gradientSkySource.updateMode.value = gradientSkyScene.updateMode.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void SyncHDRPHDRISky(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneProfile.TryGet(out HDRISky hdriSkyScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out HDRISky hdriSkySource))
|
||||
{
|
||||
hdriSkySource.hdriSky.value = hdriSkyScene.hdriSky.value;
|
||||
hdriSkySource.skyIntensityMode.value = hdriSkyScene.skyIntensityMode.value;
|
||||
hdriSkySource.exposure.value = hdriSkyScene.exposure.value;
|
||||
hdriSkySource.multiplier.value = hdriSkyScene.multiplier.value;
|
||||
hdriSkySource.rotation.value = hdriSkyScene.rotation.value;
|
||||
hdriSkySource.updateMode.value = hdriSkyScene.updateMode.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void SyncHDRPPhysicallyBasedSky(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneProfile.TryGet(out PhysicallyBasedSky physicallyBasedSkyScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out PhysicallyBasedSky physicallyBasedSkySource))
|
||||
{
|
||||
#if !UNITY_2020_2_OR_NEWER
|
||||
physicallyBasedSkySource.earthPreset.value = physicallyBasedSkyScene.earthPreset.value;
|
||||
#endif
|
||||
physicallyBasedSkySource.planetaryRadius.value = physicallyBasedSkyScene.planetaryRadius.value;
|
||||
physicallyBasedSkySource.sphericalMode.value = physicallyBasedSkyScene.sphericalMode.value;
|
||||
physicallyBasedSkySource.planetCenterPosition.value = physicallyBasedSkyScene.planetCenterPosition.value;
|
||||
physicallyBasedSkySource.planetRotation.value = physicallyBasedSkyScene.planetRotation.value;
|
||||
physicallyBasedSkySource.groundColorTexture.value = physicallyBasedSkyScene.groundColorTexture.value;
|
||||
physicallyBasedSkySource.groundTint.value = physicallyBasedSkyScene.groundTint.value;
|
||||
physicallyBasedSkySource.groundEmissionTexture.value = physicallyBasedSkyScene.groundEmissionTexture.value;
|
||||
physicallyBasedSkySource.groundEmissionMultiplier.value = physicallyBasedSkyScene.groundEmissionMultiplier.value;
|
||||
physicallyBasedSkySource.spaceRotation.value = physicallyBasedSkyScene.spaceRotation.value;
|
||||
physicallyBasedSkySource.spaceEmissionTexture.value = physicallyBasedSkyScene.spaceEmissionTexture.value;
|
||||
physicallyBasedSkySource.spaceEmissionMultiplier.value = physicallyBasedSkyScene.spaceEmissionMultiplier.value;
|
||||
physicallyBasedSkySource.airMaximumAltitude.value = physicallyBasedSkyScene.airMaximumAltitude.value;
|
||||
physicallyBasedSkySource.airDensityR.value = physicallyBasedSkyScene.airDensityR.value;
|
||||
physicallyBasedSkySource.airDensityG.value = physicallyBasedSkyScene.airDensityG.value;
|
||||
physicallyBasedSkySource.airDensityB.value = physicallyBasedSkyScene.airDensityB.value;
|
||||
physicallyBasedSkySource.airTint.value = physicallyBasedSkyScene.airTint.value;
|
||||
physicallyBasedSkySource.aerosolMaximumAltitude.value = physicallyBasedSkyScene.aerosolMaximumAltitude.value;
|
||||
physicallyBasedSkySource.aerosolDensity.value = physicallyBasedSkyScene.aerosolDensity.value;
|
||||
physicallyBasedSkySource.aerosolTint.value = physicallyBasedSkyScene.aerosolTint.value;
|
||||
physicallyBasedSkySource.aerosolAnisotropy.value = physicallyBasedSkyScene.aerosolAnisotropy.value;
|
||||
physicallyBasedSkySource.colorSaturation.value = physicallyBasedSkyScene.colorSaturation.value;
|
||||
physicallyBasedSkySource.alphaSaturation.value = physicallyBasedSkyScene.alphaSaturation.value;
|
||||
physicallyBasedSkySource.alphaMultiplier.value = physicallyBasedSkyScene.alphaMultiplier.value;
|
||||
physicallyBasedSkySource.horizonTint.value = physicallyBasedSkyScene.horizonTint.value;
|
||||
physicallyBasedSkySource.horizonZenithShift.value = physicallyBasedSkyScene.horizonZenithShift.value;
|
||||
physicallyBasedSkySource.zenithTint.value = physicallyBasedSkyScene.zenithTint.value;
|
||||
physicallyBasedSkySource.numberOfBounces.value = physicallyBasedSkyScene.numberOfBounces.value;
|
||||
physicallyBasedSkySource.skyIntensityMode.value = physicallyBasedSkyScene.skyIntensityMode.value;
|
||||
physicallyBasedSkySource.exposure.value = physicallyBasedSkyScene.exposure.value;
|
||||
physicallyBasedSkySource.multiplier.value = physicallyBasedSkyScene.multiplier.value;
|
||||
physicallyBasedSkySource.updateMode.value = physicallyBasedSkyScene.updateMode.value;
|
||||
physicallyBasedSkySource.includeSunInBaking.value = physicallyBasedSkyScene.includeSunInBaking.value;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void SyncHDRPFog(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneProfile.TryGet(out UnityEngine.Rendering.HighDefinition.Fog fogScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out UnityEngine.Rendering.HighDefinition.Fog fogSource))
|
||||
{
|
||||
fogSource.enabled.value = fogScene.enabled.value;
|
||||
fogSource.maxFogDistance.value = fogScene.maxFogDistance.value;
|
||||
fogSource.baseHeight.value = fogScene.baseHeight.value;
|
||||
fogSource.maximumHeight.value = fogScene.maximumHeight.value;
|
||||
fogSource.maxFogDistance.value = fogScene.maxFogDistance.value;
|
||||
fogSource.colorMode.value = fogScene.colorMode.value;
|
||||
fogSource.tint.value = fogScene.tint.value;
|
||||
fogSource.mipFogNear.value = fogScene.mipFogNear.value;
|
||||
fogSource.mipFogFar.value = fogScene.mipFogFar.value;
|
||||
fogSource.mipFogMaxMip.value = fogScene.mipFogMaxMip.value;
|
||||
fogSource.enableVolumetricFog.value = fogScene.enableVolumetricFog.value;
|
||||
fogSource.albedo.value = fogScene.albedo.value;
|
||||
fogSource.anisotropy.value = fogScene.anisotropy.value;
|
||||
fogSource.globalLightProbeDimmer.value = fogScene.globalLightProbeDimmer.value;
|
||||
fogSource.depthExtent.value = fogScene.depthExtent.value;
|
||||
fogSource.sliceDistributionUniformity.value = fogScene.sliceDistributionUniformity.value;
|
||||
fogSource.filter.value = fogScene.filter.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void SyncHDRPShadows(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneProfile.TryGet(out HDShadowSettings hdShadowScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out HDShadowSettings hdShadowSource))
|
||||
{
|
||||
hdShadowSource.maxShadowDistance.value = hdShadowScene.maxShadowDistance.value;
|
||||
hdShadowSource.directionalTransmissionMultiplier.value = hdShadowScene.directionalTransmissionMultiplier.value;
|
||||
hdShadowSource.cascadeShadowSplitCount.value = hdShadowScene.cascadeShadowSplitCount.value;
|
||||
hdShadowSource.cascadeShadowSplit0.value = hdShadowScene.cascadeShadowSplit0.value;
|
||||
hdShadowSource.cascadeShadowSplit1.value = hdShadowScene.cascadeShadowSplit1.value;
|
||||
hdShadowSource.cascadeShadowSplit2.value = hdShadowScene.cascadeShadowSplit2.value;
|
||||
hdShadowSource.cascadeShadowBorder0.value = hdShadowScene.cascadeShadowBorder0.value;
|
||||
hdShadowSource.cascadeShadowBorder1.value = hdShadowScene.cascadeShadowBorder1.value;
|
||||
hdShadowSource.cascadeShadowBorder2.value = hdShadowScene.cascadeShadowBorder2.value;
|
||||
hdShadowSource.cascadeShadowBorder3.value = hdShadowScene.cascadeShadowBorder3.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void SyncHDRPContactShadows(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneProfile.TryGet(out ContactShadows contactShadowsScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out ContactShadows contactShadowsSource))
|
||||
{
|
||||
contactShadowsSource.enable.value = contactShadowsScene.enable.value;
|
||||
contactShadowsSource.length.value = contactShadowsScene.length.value;
|
||||
contactShadowsSource.distanceScaleFactor.value = contactShadowsScene.distanceScaleFactor.value;
|
||||
contactShadowsSource.maxDistance.value = contactShadowsScene.maxDistance.value;
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
contactShadowsSource.minDistance.value = contactShadowsScene.minDistance.value;
|
||||
contactShadowsSource.fadeInDistance.value = contactShadowsScene.fadeInDistance.value;
|
||||
#endif
|
||||
contactShadowsSource.fadeDistance.value = contactShadowsScene.fadeDistance.value;
|
||||
contactShadowsSource.opacity.value = contactShadowsScene.opacity.value;
|
||||
contactShadowsSource.quality.value = contactShadowsScene.quality.value;
|
||||
contactShadowsSource.sampleCount = contactShadowsScene.sampleCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void SyncHDRPMicroShadows(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sceneProfile.TryGet(out MicroShadowing microShadowingScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out MicroShadowing microShadowingSource))
|
||||
{
|
||||
microShadowingSource.enable.value = microShadowingScene.enable.value;
|
||||
microShadowingSource.opacity.value = microShadowingScene.opacity.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void SyncHDRPAmbientLight(VolumeProfile sceneProfile, VolumeProfile sourceProfile)
|
||||
{
|
||||
if (sceneProfile == null || sourceProfile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if (sceneProfile.TryGet(out IndirectLightingController visualEnvironmentScene))
|
||||
{
|
||||
if (sourceProfile.TryGet(out IndirectLightingController visualEnvironmentSource))
|
||||
{
|
||||
#if !UNITY_2020_2_OR_NEWER
|
||||
visualEnvironmentSource.indirectDiffuseIntensity.value = visualEnvironmentScene.indirectDiffuseIntensity.value;
|
||||
visualEnvironmentSource.indirectSpecularIntensity.value = visualEnvironmentScene.indirectSpecularIntensity.value;
|
||||
#endif
|
||||
visualEnvironmentSource.indirectDiffuseLightingLayers.value = visualEnvironmentScene.indirectDiffuseLightingLayers.value;
|
||||
visualEnvironmentSource.reflectionLightingMultiplier.value = visualEnvironmentScene.reflectionLightingMultiplier.value;
|
||||
visualEnvironmentSource.reflectionLightingLayers.value = visualEnvironmentScene.reflectionLightingLayers.value;
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 547425c1e4156904cb14cb9b6c8823b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,166 @@
|
||||
using Gaia;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SocialPlatforms;
|
||||
|
||||
namespace ProceduralWorlds.HierachySystem
|
||||
{
|
||||
[System.Serializable]
|
||||
public class GaiaHierarchyVisibility
|
||||
{
|
||||
public string m_name;
|
||||
public bool m_isVisible;
|
||||
}
|
||||
|
||||
[ExecuteAlways]
|
||||
public class GaiaHierarchyUtils : MonoBehaviour
|
||||
{
|
||||
//All objects in the parent transforms
|
||||
[HideInInspector]
|
||||
public List<GaiaHierarchyVisibility> m_visibilityEntries = new List<GaiaHierarchyVisibility>();
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Iniatilize on enable
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
SetupHideInHierarchy();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the objects showed in Hierarchy to be shown or hidden
|
||||
/// </summary>
|
||||
public void SetupHideInHierarchy()
|
||||
{
|
||||
//Get all objects
|
||||
UpdateParentObjects();
|
||||
|
||||
//Proceed if objects exist
|
||||
if (m_visibilityEntries != null)
|
||||
{
|
||||
foreach (Transform t in transform)
|
||||
{
|
||||
GaiaHierarchyVisibility ghv = m_visibilityEntries.Find(x => x.m_name == t.name);
|
||||
if (ghv == null || ghv.m_isVisible)
|
||||
{
|
||||
foreach (Transform child in t)
|
||||
{
|
||||
child.gameObject.hideFlags = HideFlags.None;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Transform child in t)
|
||||
{
|
||||
child.gameObject.hideFlags = HideFlags.HideInHierarchy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures all GaiaHierarchyUtils components and in each of the objects showed in Hierarchy to be shown or hidden
|
||||
/// </summary>
|
||||
public void SetupAllHideInHierarchy()
|
||||
{
|
||||
bool localOnly = false;
|
||||
|
||||
if (GaiaUtils.HasDynamicLoadedTerrains())
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (EditorUtility.DisplayDialog("Apply to all terrains?", "Do you want to apply these settings to ALL terrains (inlcuding the ones which are currently not loaded), or the loaded ones only?", "All terrains", "Only loaded terrains"))
|
||||
{
|
||||
GaiaUtils.CallFunctionOnDynamicLoadedTerrains(SetupAllHideOnTerrain, true, null, "Applying hide settings to terrain scenes...");
|
||||
}
|
||||
else
|
||||
{
|
||||
localOnly = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
localOnly = true;
|
||||
}
|
||||
if (localOnly)
|
||||
{
|
||||
//Get all GaiaHierarchyUtils
|
||||
GaiaHierarchyUtils[] hierarchyUtils = FindObjectsOfType<GaiaHierarchyUtils>();
|
||||
|
||||
//Proceed if objects exist
|
||||
if (hierarchyUtils != null)
|
||||
{
|
||||
foreach (GaiaHierarchyUtils utils in hierarchyUtils)
|
||||
{
|
||||
utils.m_visibilityEntries = m_visibilityEntries;
|
||||
utils.SetupHideInHierarchy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SetupAllHideOnTerrain(Terrain t)
|
||||
{
|
||||
GaiaHierarchyUtils hierarchyUtils = t.GetComponentInChildren<GaiaHierarchyUtils>();
|
||||
if (hierarchyUtils != null)
|
||||
{
|
||||
hierarchyUtils.m_visibilityEntries = m_visibilityEntries;
|
||||
hierarchyUtils.SetupHideInHierarchy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update the visibility state for all parent objects that hold game objects
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public void UpdateParentObjects()
|
||||
{
|
||||
//Build up a new list that keeps the existing settings, this will take care of sorting if the hierarchy has changed as well.
|
||||
List<GaiaHierarchyVisibility> newList = new List<GaiaHierarchyVisibility>();
|
||||
|
||||
foreach (Transform t in transform)
|
||||
{
|
||||
|
||||
GaiaHierarchyVisibility ghv = m_visibilityEntries.Find(x => x.m_name == t.name);
|
||||
if (ghv == null || ghv.m_isVisible)
|
||||
{
|
||||
newList.Add(new GaiaHierarchyVisibility() { m_name = t.name, m_isVisible = true });
|
||||
}
|
||||
else
|
||||
{
|
||||
newList.Add(new GaiaHierarchyVisibility() { m_name = t.name, m_isVisible = false });
|
||||
}
|
||||
}
|
||||
//Add all remaining entries to carry over settings for objects which are currently not spawned in the hierarchy
|
||||
foreach (GaiaHierarchyVisibility ghv in m_visibilityEntries.Where(x => !newList.Exists(y=>y.m_name==x.m_name)))
|
||||
{
|
||||
newList.Add(ghv);
|
||||
}
|
||||
|
||||
m_visibilityEntries = newList;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes old entries from the visibility settings list that do not have a corresponding game object anymore.
|
||||
/// </summary>
|
||||
public void RemoveOldEntries()
|
||||
{
|
||||
for (int i=m_visibilityEntries.Count-1;i>=0;i--)
|
||||
{
|
||||
if (transform.Find(m_visibilityEntries[i].m_name) == null)
|
||||
{
|
||||
m_visibilityEntries.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed06b5e09f0b8204e99977f9c38b6bd5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class GaiaMessages
|
||||
{
|
||||
public string title;
|
||||
public string bodyContent;
|
||||
public string url;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8efe02a4c9274743951d49f5f7fe97c
|
||||
timeCreated: 1524195484
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,46 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that provides information about the current scene
|
||||
/// </summary>
|
||||
public class GaiaSceneInfo
|
||||
{
|
||||
public Bounds m_sceneBounds = new Bounds();
|
||||
public Vector3 m_centrePointOnTerrain = Vector3.zero;
|
||||
public float m_seaLevel = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Get current basic scene information
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static GaiaSceneInfo GetSceneInfo()
|
||||
{
|
||||
GaiaSceneInfo sceneInfo = new GaiaSceneInfo();
|
||||
|
||||
|
||||
//Get or create a session in order to get a sea level
|
||||
GaiaSessionManager sessionMgr = GaiaSessionManager.GetSessionManager();
|
||||
|
||||
//Get the sea level
|
||||
sceneInfo.m_seaLevel = sessionMgr.GetSeaLevel();
|
||||
|
||||
|
||||
//Not used anywhere - obsolete?
|
||||
//Terrain terrain = Gaia.TerrainHelper.GetActiveTerrain();
|
||||
|
||||
////Get the terrain bounds
|
||||
//Gaia.TerrainHelper.GetTerrainBounds(terrain, ref sceneInfo.m_sceneBounds);
|
||||
|
||||
|
||||
////Grab the central point on the terrain - handy for placing player etc
|
||||
//sceneInfo.m_centrePointOnTerrain = new Vector3(sceneInfo.m_sceneBounds.center.x, terrain.SampleHeight(sceneInfo.m_sceneBounds.center), sceneInfo.m_sceneBounds.center.z);
|
||||
|
||||
|
||||
return sceneInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bf997ab9590207479567ce0b1362b9d
|
||||
timeCreated: 1456015514
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public class GaiaScriptOrder : Attribute
|
||||
{
|
||||
public int Order;
|
||||
|
||||
public GaiaScriptOrder(int order)
|
||||
{
|
||||
Order = order;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f35eb7790f4be44c93b1f386a61fac9
|
||||
timeCreated: 1524564978
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,314 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper to allow unified access to splat prototype data across different unity terrain APIs (pre and post 2018.3)
|
||||
/// </summary>
|
||||
public struct GaiaSplatPrototype
|
||||
{
|
||||
public float metallic;
|
||||
public float normalScale;
|
||||
public Texture2D normalMap;
|
||||
public float smoothness;
|
||||
public Texture2D texture;
|
||||
public Vector2 tileOffset;
|
||||
public Vector2 tileSize;
|
||||
public Texture2D maskMap;
|
||||
public Vector4 diffuseRemapMin;
|
||||
public Vector4 diffuseRemapMax;
|
||||
public Vector4 maskMapRemapMin;
|
||||
public Vector4 maskMapRemapMax;
|
||||
public Color specularColor;
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
public GaiaSplatPrototype(TerrainLayer terrainLayer)
|
||||
{
|
||||
//Initialize empty
|
||||
metallic = 0f;
|
||||
normalScale = 1f;
|
||||
normalMap = null;
|
||||
maskMap = null;
|
||||
smoothness = 0f;
|
||||
texture = null;
|
||||
tileOffset = Vector2.zero;
|
||||
tileSize = Vector2.zero;
|
||||
diffuseRemapMin = Vector4.zero;
|
||||
diffuseRemapMax = Vector4.one;
|
||||
maskMapRemapMin = Vector4.zero;
|
||||
maskMapRemapMax = Vector4.one;
|
||||
specularColor = Color.white;
|
||||
|
||||
if (terrainLayer != null)
|
||||
{
|
||||
metallic = terrainLayer.metallic;
|
||||
normalScale = terrainLayer.normalScale;
|
||||
normalMap = terrainLayer.normalMapTexture;
|
||||
maskMap = terrainLayer.maskMapTexture;
|
||||
smoothness = terrainLayer.smoothness;
|
||||
texture = terrainLayer.diffuseTexture;
|
||||
tileOffset = terrainLayer.tileOffset;
|
||||
tileSize = terrainLayer.tileSize;
|
||||
diffuseRemapMin = terrainLayer.diffuseRemapMin;
|
||||
diffuseRemapMax = terrainLayer.diffuseRemapMax;
|
||||
maskMapRemapMin = terrainLayer.maskMapRemapMin;
|
||||
maskMapRemapMax = terrainLayer.maskMapRemapMax;
|
||||
specularColor = terrainLayer.specular;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the contained data as a TerrainLayer object.
|
||||
/// </summary>
|
||||
/// <returns>A TerrainLayer object.</returns>
|
||||
public TerrainLayer Convert()
|
||||
{
|
||||
return new TerrainLayer
|
||||
{
|
||||
metallic = metallic,
|
||||
normalScale = normalScale,
|
||||
normalMapTexture = normalMap,
|
||||
maskMapTexture = maskMap,
|
||||
smoothness = smoothness,
|
||||
diffuseTexture = texture,
|
||||
tileOffset = tileOffset,
|
||||
tileSize = tileSize,
|
||||
diffuseRemapMin = diffuseRemapMin,
|
||||
diffuseRemapMax = diffuseRemapMax,
|
||||
maskMapRemapMin = maskMapRemapMin,
|
||||
maskMapRemapMax = maskMapRemapMax,
|
||||
specular = specularColor
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
public GaiaSplatPrototype(SplatPrototype splatPrototype)
|
||||
{
|
||||
//Initialize empty
|
||||
metallic = 0f;
|
||||
normalMap = null;
|
||||
smoothness = 0f;
|
||||
texture = null;
|
||||
tileOffset = Vector2.zero;
|
||||
tileSize = Vector2.zero;
|
||||
|
||||
if (splatPrototype != null)
|
||||
{
|
||||
metallic = splatPrototype.metallic;
|
||||
normalMap = splatPrototype.normalMap;
|
||||
smoothness = splatPrototype.smoothness;
|
||||
texture = splatPrototype.texture;
|
||||
tileOffset = splatPrototype.tileOffset;
|
||||
tileSize = splatPrototype.tileSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the contained data as a SplatPrototype object.
|
||||
/// </summary>
|
||||
/// <returns>A SplatPrototype object.</returns>
|
||||
public SplatPrototype Convert()
|
||||
{
|
||||
return new SplatPrototype {
|
||||
metallic = metallic,
|
||||
normalMap = normalMap,
|
||||
smoothness = smoothness,
|
||||
texture = texture,
|
||||
tileOffset = tileOffset,
|
||||
tileSize = tileSize
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Gets all splat prototypes from a terrain. Uses the correct terrain API for pre and post Unity 2018.3.
|
||||
/// </summary>
|
||||
/// <param name="terrain">The terrain containing the splat prototype data.</param>
|
||||
/// <returns>Null if invalid terrain data. An empty GaiaSplatPrototype array if no splat prototypes in terrain data. A filled GaiaSplatPrototype array if splat prototypes present.</returns>
|
||||
public static GaiaSplatPrototype[] GetGaiaSplatPrototypes(Terrain terrain)
|
||||
{
|
||||
if (terrain == null || terrain.terrainData == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
TerrainData terrainData = terrain.terrainData;
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
if (terrainData.terrainLayers == null || terrainData.terrainLayers.Length == 0)
|
||||
{
|
||||
return new GaiaSplatPrototype[0];
|
||||
}
|
||||
|
||||
GaiaSplatPrototype[] splatPrototypes = new GaiaSplatPrototype[terrainData.terrainLayers.Length];
|
||||
|
||||
for (int i = 0; i < terrainData.terrainLayers.Length; i++)
|
||||
{
|
||||
splatPrototypes[i] = new GaiaSplatPrototype(terrainData.terrainLayers[i]);
|
||||
}
|
||||
return splatPrototypes;
|
||||
#else
|
||||
if (terrainData.splatPrototypes == null ||terrainData.splatPrototypes.Length == 0)
|
||||
{
|
||||
return new GaiaSplatPrototype[0];
|
||||
}
|
||||
|
||||
GaiaSplatPrototype[] splatPrototypes = new GaiaSplatPrototype[terrainData.splatPrototypes.Length];
|
||||
|
||||
for (int i = 0; i < terrainData.splatPrototypes.Length; i++)
|
||||
{
|
||||
splatPrototypes[i] = new GaiaSplatPrototype(terrainData.splatPrototypes[i]);
|
||||
}
|
||||
return splatPrototypes;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies an array of Gaia Splat prototypes to a terrain. Uses the correct terrain API for pre and post Unity 2018.3.
|
||||
/// </summary>
|
||||
/// <param name="terrain">The terrain to assign the splat prototypes to.</param>
|
||||
/// <param name="splats">Array of GaiaSplatPrototypes to assign to the terrain.</param>
|
||||
/// <param name="terrainName">The current Gaia profile. Used for terrain layer asset filenames.</param>
|
||||
public static void SetGaiaSplatPrototypes(Terrain terrain, GaiaSplatPrototype[] splats, string terrainName)
|
||||
{
|
||||
if (terrain != null && splats != null)
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
|
||||
terrain.terrainData.terrainLayers = CreateTerrainLayers(terrain.name, splats);
|
||||
|
||||
#else
|
||||
|
||||
SplatPrototype[] splatPrototypes = new SplatPrototype[splats.Length];
|
||||
|
||||
for (int i = 0; i < splats.Length; i++)
|
||||
{
|
||||
splatPrototypes[i] = splats[i].Convert();
|
||||
}
|
||||
terrain.terrainData.splatPrototypes = splatPrototypes;
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
public static TerrainLayer[] CreateTerrainLayers(string namePrefix, GaiaSplatPrototype[] splats)
|
||||
{
|
||||
TerrainLayer[] terrainLayers = new TerrainLayer[splats.Length];
|
||||
|
||||
for (int i = 0; i < splats.Length; i++)
|
||||
{
|
||||
terrainLayers[i] = splats[i].Convert();
|
||||
}
|
||||
|
||||
//completely remove all old splat prototypes first to prevent build-up of abandoned files
|
||||
RemoveTerrainLayerAssetFiles(namePrefix);
|
||||
|
||||
//Permanently save the new layers as asset files & get a reference, else they will not work properly in the terrain
|
||||
for (int i = 0; i < terrainLayers.Length; i++)
|
||||
{
|
||||
terrainLayers[i] = SaveTerrainLayerAsAsset(namePrefix, i.ToString(), terrainLayers[i]);
|
||||
}
|
||||
|
||||
return terrainLayers;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up terrain layer asset files matching a Gaia terrain, and returns them as an array.
|
||||
/// </summary>
|
||||
/// <param name="terrainName">The Gaia terrain name to look up terrain layer asset files for.</param>
|
||||
/// <returns></returns>
|
||||
// private static TerrainLayer[] LookupTerrainLayerAssetFiles(string terrainName)
|
||||
// {
|
||||
//#if UNITY_EDITOR
|
||||
|
||||
// string gaiaDirectory = "";
|
||||
// string terrainLayerDirectory = gaiaDirectory + "Profiles/TerrainLayers";
|
||||
// DirectoryInfo info = new DirectoryInfo(terrainLayerDirectory);
|
||||
// FileInfo[] fileInfo = info.GetFiles(terrainName + "*.asset");
|
||||
|
||||
// TerrainLayer[] returnArray = new TerrainLayer[fileInfo.Length];
|
||||
|
||||
// for (int i = 0; i < fileInfo.Length; i++)
|
||||
// {
|
||||
// returnArray[i] = (TerrainLayer)AssetDatabase.LoadAssetAtPath("Assets" + fileInfo[i].FullName.Substring(Application.dataPath.Length), typeof(TerrainLayer));
|
||||
// }
|
||||
// return returnArray;
|
||||
//#else
|
||||
// Debug.LogError("Runtime Gaia operation is not supported");
|
||||
// return new TerrainLayer[0];
|
||||
//#endif
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Saves a unity terrain layer as asset file and returns a reference to the newly created Terrain Layerfile.
|
||||
/// </summary>
|
||||
/// <param name="terrainName">The name of the current Gaia terrain (for the filename).</param>
|
||||
/// <param name="layerId">The layer ID of the layer that is to be saved (for the filename).</param>
|
||||
/// <param name="terrainLayer">The terrain layer object to save.</param>
|
||||
/// <returns>Reference to the created TerrainLayer</returns>
|
||||
public static TerrainLayer SaveTerrainLayerAsAsset(string terrainName, string layerId, TerrainLayer terrainLayer)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
GaiaSessionManager gsm = GaiaSessionManager.GetSessionManager();
|
||||
|
||||
//The combination of terrain name and layer id should be unique enough so that users don't overwrite layers between terrains.
|
||||
string path = GaiaDirectories.GetTerrainLayerPath(gsm.m_session) + "/" + terrainName + "_" + layerId + ".asset";
|
||||
|
||||
AssetDatabase.CreateAsset(terrainLayer, path);
|
||||
AssetDatabase.ImportAsset(path);
|
||||
|
||||
return AssetDatabase.LoadAssetAtPath<TerrainLayer>(path);
|
||||
|
||||
#else
|
||||
Debug.LogError("Runtime Gaia operation is not supported");
|
||||
return new TerrainLayer();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all Terrain Layer Asset Files for a given terrain
|
||||
/// </summary>
|
||||
/// <param name="terrainName"></param>
|
||||
private static void RemoveTerrainLayerAssetFiles(string terrainName)
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
string gaiaDirectory = "";
|
||||
string terrainLayerDirectory = gaiaDirectory + "Profiles/TerrainLayers";
|
||||
DirectoryInfo info = new DirectoryInfo(terrainLayerDirectory);
|
||||
//only read in files if the directory exists.
|
||||
//The save function will create the directory in case it is missing.
|
||||
if (info.Exists)
|
||||
{
|
||||
FileInfo[] fileInfo = info.GetFiles(terrainName + "*.asset");
|
||||
|
||||
for (int i = 0; i < fileInfo.Length; i++)
|
||||
{
|
||||
File.Delete(fileInfo[i].FullName);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("Runtime Gaia operation is not supported");
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0302eb1e7aa2c414eac26f4a3a0b1f7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Data structure to collect data about specific events that are called repeatedly while the stopwatch is running.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class GaiaStopWatchEvent
|
||||
{
|
||||
public string m_name;
|
||||
public string m_parent;
|
||||
public bool m_started;
|
||||
public int m_callCount;
|
||||
public long m_firstStartTimeStamp;
|
||||
public long m_lastStartTimeStamp;
|
||||
public long m_lastStopTimeStamp;
|
||||
public long m_durationPerCall;
|
||||
public long m_accumulatedTime;
|
||||
}
|
||||
|
||||
|
||||
//Simple static wrapper to access one Stopwatch instance across all Gaia
|
||||
//Can be used to measure time across multiple parts of the application
|
||||
//without having to deal with passing stopwatch instances around
|
||||
public static class GaiaStopwatch
|
||||
{
|
||||
#if GAIA_DEBUG
|
||||
public static Stopwatch m_stopwatch = new Stopwatch();
|
||||
public static GaiaStopWatchEvent m_currentEvent;
|
||||
static long m_lastLogElapsed = 0;
|
||||
public static bool m_isEnabled;
|
||||
public static long m_accumulatedYieldTime = 0;
|
||||
static List<GaiaStopWatchEvent> m_events = new List<GaiaStopWatchEvent>();
|
||||
#endif
|
||||
|
||||
private static void Start()
|
||||
{
|
||||
#if GAIA_DEBUG
|
||||
//Always start a new list of events to not overwrite previous data
|
||||
m_events = new List<GaiaStopWatchEvent>();
|
||||
m_stopwatch.Reset();
|
||||
m_stopwatch.Start();
|
||||
LogWithTime("Starting a new Gaia Stopwatch Log. All logged times in milliseconds.");
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void LogWithTime(string logText)
|
||||
{
|
||||
#if GAIA_DEBUG
|
||||
UnityEngine.Debug.Log(String.Format("{0:N0}",m_stopwatch.ElapsedMilliseconds.ToString()) + " | Diff: " + String.Format("{0:N0}", (m_stopwatch.ElapsedMilliseconds - m_lastLogElapsed).ToString()) + " | " + logText);
|
||||
m_lastLogElapsed = m_stopwatch.ElapsedMilliseconds;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void StartEvent(string name)
|
||||
{
|
||||
#if GAIA_DEBUG
|
||||
//Stopwatch not running yet? If enabled, we begin a new log now.
|
||||
if (!m_stopwatch.IsRunning)
|
||||
{
|
||||
if (m_isEnabled)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GaiaStopWatchEvent stopWatchEvent = m_events.Find(x => x.m_name == name);
|
||||
|
||||
if (stopWatchEvent != null)
|
||||
{
|
||||
if (!stopWatchEvent.m_started)
|
||||
{
|
||||
stopWatchEvent.m_lastStartTimeStamp = m_stopwatch.ElapsedMilliseconds;
|
||||
stopWatchEvent.m_started = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogWarning("Trying to start an event '" + name + "' with the Gaia Stopwatch that has already been started before!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Event does not exist yet, let's create it
|
||||
stopWatchEvent = new GaiaStopWatchEvent()
|
||||
{
|
||||
m_firstStartTimeStamp = m_stopwatch.ElapsedMilliseconds,
|
||||
m_lastStartTimeStamp = m_stopwatch.ElapsedMilliseconds,
|
||||
m_name = name,
|
||||
m_started = true,
|
||||
};
|
||||
|
||||
m_events.Add(stopWatchEvent);
|
||||
}
|
||||
LogWithTime("Start of Event: " + name + " (" + stopWatchEvent.m_callCount + ")");
|
||||
//assign parent if current Event not is null, otherwise this will become the first current event
|
||||
if (m_currentEvent!=null)
|
||||
{
|
||||
stopWatchEvent.m_parent = m_currentEvent.m_name;
|
||||
}
|
||||
m_currentEvent = stopWatchEvent;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void EndEvent(string name, bool warning =true)
|
||||
{
|
||||
#if GAIA_DEBUG
|
||||
if (!m_stopwatch.IsRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GaiaStopWatchEvent stopWatchEvent = m_events.Find(x => x.m_name == name && x.m_started==true);
|
||||
|
||||
if (stopWatchEvent != null)
|
||||
{
|
||||
stopWatchEvent.m_lastStopTimeStamp = m_stopwatch.ElapsedMilliseconds;
|
||||
stopWatchEvent.m_started = false;
|
||||
stopWatchEvent.m_callCount++;
|
||||
stopWatchEvent.m_accumulatedTime += stopWatchEvent.m_lastStopTimeStamp - stopWatchEvent.m_lastStartTimeStamp;
|
||||
stopWatchEvent.m_durationPerCall = stopWatchEvent.m_accumulatedTime / stopWatchEvent.m_callCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (warning)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning("Trying to stop an event '" + name + "' with the Gaia Stopwatch, but that event does not exist or is not running!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//End all child events that are still running
|
||||
var runningChildEvents = m_events.FindAll(x => x.m_parent == stopWatchEvent.m_name && x.m_started == true);
|
||||
if (runningChildEvents != null)
|
||||
{
|
||||
foreach (GaiaStopWatchEvent runningChildEvent in m_events.FindAll(x => x.m_parent == stopWatchEvent.m_name && x.m_started == true))
|
||||
{
|
||||
EndEvent(runningChildEvent.m_name);
|
||||
}
|
||||
}
|
||||
|
||||
//Return current event to parent, if any
|
||||
if (stopWatchEvent.m_parent != null)
|
||||
{
|
||||
m_currentEvent = m_events.Find(x => x.m_name == stopWatchEvent.m_parent);
|
||||
}
|
||||
LogWithTime("End of Event: " + name + " (" + stopWatchEvent.m_callCount + "), Total time accumulated for this Event: " + String.Format("{0:N0}",stopWatchEvent.m_accumulatedTime));
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void Stop(bool outputData = true)
|
||||
{
|
||||
#if GAIA_DEBUG
|
||||
if (!m_stopwatch.IsRunning || !m_isEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//end any running events
|
||||
foreach (GaiaStopWatchEvent stopWatchEvent in m_events.FindAll(x=>x.m_started==true))
|
||||
{
|
||||
EndEvent(stopWatchEvent.m_name);
|
||||
}
|
||||
m_currentEvent = null;
|
||||
m_lastLogElapsed = 0;
|
||||
m_stopwatch.Stop();
|
||||
m_isEnabled = false;
|
||||
LogWithTime("Stopping the Gaia Stopwatch Log.");
|
||||
if (outputData)
|
||||
{
|
||||
GameObject parentGO = GaiaUtils.GetStopwatchDataObject();
|
||||
GameObject stopWatchDataObject = new GameObject(string.Format("Gaia Stopwatch Run {0:yyyy-MM-dd--HH-mm-ss}", DateTime.Now));
|
||||
stopWatchDataObject.transform.parent = parentGO.transform;
|
||||
GaiaStopwatchDataset newDataset = stopWatchDataObject.AddComponent<GaiaStopwatchDataset>();
|
||||
newDataset.m_events = m_events;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da1942d806558424ba3439f2dc3fb4f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public class GaiaStopwatchControl : MonoBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66acc16b964c8194183c79c588f9156b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public class GaiaStopwatchDataset : MonoBehaviour
|
||||
{
|
||||
public List<GaiaStopWatchEvent> m_events = new List<GaiaStopWatchEvent>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c3bfbe289d88f342959bea20fc864f0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,137 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
#if UPPipeline
|
||||
using UnityEngine.Rendering.Universal;
|
||||
#endif
|
||||
using Gaia.Pipeline;
|
||||
|
||||
namespace Gaia.Pipeline.URP
|
||||
{
|
||||
public static class GaiaURPRuntimeUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures reflections to LWRP
|
||||
/// </summary>
|
||||
public static void ConfigureReflectionProbes()
|
||||
{
|
||||
ReflectionProbe[] reflectionProbes = Object.FindObjectsOfType<ReflectionProbe>();
|
||||
if (reflectionProbes != null)
|
||||
{
|
||||
foreach(ReflectionProbe probe in reflectionProbes)
|
||||
{
|
||||
if (probe.resolution > 512)
|
||||
{
|
||||
Debug.Log(probe.name + " This probes resolution is quite high and could cause performance issues in Lightweight Pipeline. Recommend lowing the resolution if you're targeting mobile platform");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Configures and setup the terrain
|
||||
/// </summary>
|
||||
/// <param name="profile"></param>
|
||||
public static void ConfigureTerrain(UnityPipelineProfile profile)
|
||||
{
|
||||
Terrain[] terrains = Terrain.activeTerrains;
|
||||
if (terrains != null)
|
||||
{
|
||||
foreach (Terrain terrain in terrains)
|
||||
{
|
||||
#if !UNITY_2019_2_OR_NEWER
|
||||
terrain.materialType = Terrain.MaterialType.Custom;
|
||||
#endif
|
||||
terrain.materialTemplate = profile.m_universalTerrainMaterial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UPPipeline
|
||||
/// <summary>
|
||||
/// Sets the shadow distance in URP
|
||||
/// </summary>
|
||||
/// <param name="pipelineAsset"></param>
|
||||
/// <param name="profileValues"></param>
|
||||
public static void SetShadowDistance(UniversalRenderPipelineAsset pipelineAsset, GaiaLightingProfileValues profileValues)
|
||||
{
|
||||
if (pipelineAsset == null || profileValues == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pipelineAsset.shadowDistance = profileValues.m_shadowDistance;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or creates UP camera data
|
||||
/// </summary>
|
||||
/// <param name="camera"></param>
|
||||
/// <returns></returns>
|
||||
public static UniversalAdditionalCameraData GetUPCameraData(Camera camera)
|
||||
{
|
||||
if (camera == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
UniversalAdditionalCameraData cameraData = camera.gameObject.GetComponent<UniversalAdditionalCameraData>();
|
||||
if (cameraData == null)
|
||||
{
|
||||
cameraData = camera.gameObject.AddComponent<UniversalAdditionalCameraData>();
|
||||
}
|
||||
|
||||
return cameraData;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears URP camera data in the scene
|
||||
/// </summary>
|
||||
/// <param name="cameraDatas"></param>
|
||||
public static void ClearUPCameraData(UniversalAdditionalCameraData[] cameraDatas)
|
||||
{
|
||||
if (cameraDatas.Length < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var data in cameraDatas)
|
||||
{
|
||||
GameObject.DestroyImmediate(data);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or creates UP Light data
|
||||
/// </summary>
|
||||
/// <param name="light"></param>
|
||||
/// <returns></returns>
|
||||
public static UniversalAdditionalLightData GetUPLightData(Light light)
|
||||
{
|
||||
if (light == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
UniversalAdditionalLightData lightData = light.GetComponent<UniversalAdditionalLightData>();
|
||||
if (lightData == null)
|
||||
{
|
||||
lightData = light.gameObject.AddComponent<UniversalAdditionalLightData>();
|
||||
}
|
||||
|
||||
return lightData;
|
||||
}
|
||||
/// <summary>
|
||||
/// Clears URP light data in the scene
|
||||
/// </summary>
|
||||
/// <param name="lightDatas"></param>
|
||||
public static void ClearUPLightData(UniversalAdditionalLightData[] lightDatas)
|
||||
{
|
||||
if (lightDatas.Length < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var data in lightDatas)
|
||||
{
|
||||
GameObject.DestroyImmediate(data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e2cb216b11cfaa498c7e34fbcf24ab6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1ffc01c7d3c997499fd87782c84bcf5
|
||||
timeCreated: 1537200478
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 663c87687fc4dac498e47b030ac7aa24
|
||||
timeCreated: 1431468661
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,269 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public struct MaskedMeshParamters
|
||||
{
|
||||
public UnityHeightMap Heightmap;
|
||||
public UnityHeightMap Maskmap;
|
||||
/// <summary>
|
||||
/// 0-1 below the threshold then are considered outside.
|
||||
/// </summary>
|
||||
public float MaskThreshold;
|
||||
/// <summary>
|
||||
/// terrain.terrainData.size
|
||||
/// </summary>
|
||||
public Vector3 MeshScale;
|
||||
/// <summary>
|
||||
/// //0, 1, 2, 3, 4 (full, half, quarter, eighth, sixteenth)
|
||||
/// </summary>
|
||||
public int MeshResolution;
|
||||
/// <summary>
|
||||
/// 0 = triangles, 1 = quads
|
||||
/// </summary>
|
||||
public int MeshType;
|
||||
/// <summary>
|
||||
/// CounterClockwise works since x in negated.
|
||||
/// </summary>
|
||||
public WindingOrder Winding;
|
||||
|
||||
public enum WindingOrder
|
||||
{
|
||||
Clockwise = 1,
|
||||
CounterClockwise = 2
|
||||
}
|
||||
|
||||
public MaskedMeshParamters(UnityHeightMap heightMap, UnityHeightMap maskMap, float maskThreshold, int meshResolution, Vector3 meshScale, int meshType, WindingOrder winding)
|
||||
{
|
||||
Heightmap = heightMap;
|
||||
Maskmap = maskMap;
|
||||
MaskThreshold = maskThreshold;
|
||||
MeshResolution = meshResolution;
|
||||
MeshScale = meshScale;
|
||||
MeshType = meshType;
|
||||
Winding = winding;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MaskedTerrainMesh
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates 2 Meshes based on a mask heightmap
|
||||
/// </summary>
|
||||
/// <param name="parms"></param>
|
||||
/// <param name="outsideMesh">The parts that are below the threshold.</param>
|
||||
/// <param name="insideMesh">The parts that are equal or above the threshold.</param>
|
||||
public static void CreateMaskedTerrainMeshes(MaskedMeshParamters parms, out MeshBuilder outsideMesh, out MeshBuilder insideMesh)
|
||||
{
|
||||
int heightmapResolution = parms.Heightmap.Width();
|
||||
outsideMesh = new MeshBuilder(1.0f / (float )heightmapResolution);
|
||||
insideMesh = new MeshBuilder(1.0f / (float)heightmapResolution);
|
||||
int tRes = 1 << parms.MeshResolution;
|
||||
|
||||
Vector3 meshScale = new Vector3(parms.MeshScale.x / (heightmapResolution - 1), parms.MeshScale.y, parms.MeshScale.z / (heightmapResolution - 1));
|
||||
bool clockwise = parms.Winding == MaskedMeshParamters.WindingOrder.Clockwise;
|
||||
|
||||
for (int y = 0; y < heightmapResolution - tRes; y += tRes)
|
||||
{
|
||||
float yNorm = (float )y / (float )heightmapResolution;
|
||||
float yNorm2 = (float)(y+tRes) / (float)heightmapResolution;
|
||||
|
||||
for (float x = 0; x < heightmapResolution - tRes; x += tRes)
|
||||
{
|
||||
float xNorm = (float)x / (float)heightmapResolution;
|
||||
float xNorm2 = (float)(x+tRes) / (float)heightmapResolution;
|
||||
|
||||
// Add a quad or 2 triangles to the main or masked mesh with lower left corner given
|
||||
|
||||
float h1 = parms.Heightmap[yNorm2, xNorm];
|
||||
float h2 = parms.Heightmap[yNorm2, xNorm2];
|
||||
float h3 = parms.Heightmap[yNorm, xNorm];
|
||||
float h4 = parms.Heightmap[yNorm, xNorm2];
|
||||
Vector3 v1 = Vector3.Scale(new Vector3( -x, h1, y+tRes), meshScale);
|
||||
Vector3 v2 = Vector3.Scale(new Vector3(-(x+tRes), h2, y+tRes), meshScale);
|
||||
Vector3 v3 = Vector3.Scale(new Vector3( -x, h3, y), meshScale);
|
||||
Vector3 v4 = Vector3.Scale(new Vector3(-(x+tRes), h4, y), meshScale);
|
||||
if (parms.Maskmap[xNorm, yNorm] < parms.MaskThreshold)
|
||||
{
|
||||
if (parms.MeshType == 0)
|
||||
{
|
||||
outsideMesh.AddTriangle(clockwise, v3, v1, v2);
|
||||
outsideMesh.AddTriangle(clockwise, v3, v2, v4);
|
||||
}
|
||||
else
|
||||
{
|
||||
outsideMesh.AddQuad(clockwise, v1, v2, v3, v4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parms.MeshType == 0)
|
||||
{
|
||||
insideMesh.AddTriangle(clockwise, v3, v1, v2);
|
||||
insideMesh.AddTriangle(clockwise, v3, v2, v4);
|
||||
}
|
||||
else
|
||||
{
|
||||
insideMesh.AddQuad(clockwise, v1, v2, v3, v4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class MeshBuilder
|
||||
{
|
||||
float m_uvScale = 1.0f;
|
||||
List<Vector3> m_vertices;
|
||||
List<Vector2> m_uvs;
|
||||
List<int> m_indices;
|
||||
Dictionary<Vector2, int> m_verticeToIndex;
|
||||
bool usingTriangles = true;
|
||||
|
||||
public List<Vector3> Vertices { get { return m_vertices; } }
|
||||
public List<Vector2> UVs { get { return m_uvs; } }
|
||||
public List<int> Indices { get { return m_indices; } }
|
||||
|
||||
public MeshBuilder(float uvScale)
|
||||
{
|
||||
m_uvScale = uvScale;
|
||||
m_vertices = new List<Vector3>();
|
||||
m_uvs = new List<Vector2>();
|
||||
m_indices = new List<int>();
|
||||
m_verticeToIndex = new Dictionary<Vector2, int>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a triangle to the mesh given 3 vertices.
|
||||
/// </summary>
|
||||
/// <param name="v1"></param>
|
||||
/// <param name="v2"></param>
|
||||
/// <param name="v3"></param>
|
||||
public void AddTriangle(bool clockwise, Vector3 v1, Vector3 v2, Vector3 v3)
|
||||
{
|
||||
if (clockwise)
|
||||
{
|
||||
m_indices.Add(VertexIndex(v1));
|
||||
m_indices.Add(VertexIndex(v2));
|
||||
m_indices.Add(VertexIndex(v3));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_indices.Add(VertexIndex(v3));
|
||||
m_indices.Add(VertexIndex(v2));
|
||||
m_indices.Add(VertexIndex(v1));
|
||||
}
|
||||
usingTriangles = true;
|
||||
}
|
||||
|
||||
public void AddQuad(bool clockwise, Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4)
|
||||
{
|
||||
if (clockwise)
|
||||
{
|
||||
m_indices.Add(VertexIndex(v1));
|
||||
m_indices.Add(VertexIndex(v2));
|
||||
m_indices.Add(VertexIndex(v4));
|
||||
m_indices.Add(VertexIndex(v3));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_indices.Add(VertexIndex(v1));
|
||||
m_indices.Add(VertexIndex(v3));
|
||||
m_indices.Add(VertexIndex(v4));
|
||||
m_indices.Add(VertexIndex(v2));
|
||||
}
|
||||
usingTriangles = false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the index of a vertex in the mesh.
|
||||
/// Adds the vertex if it does not already exist.
|
||||
/// </summary>
|
||||
/// <param name="vert">The Vector3 vertice to get the index for.</param>
|
||||
/// <returns>The index in to the m_vertices list of the vertice.</returns>
|
||||
int VertexIndex(Vector3 vert)
|
||||
{
|
||||
Vector2 v = new Vector2(vert.x, vert.z);
|
||||
if (!m_verticeToIndex.TryGetValue(v, out int vIndex))
|
||||
{
|
||||
vIndex = m_vertices.Count;
|
||||
m_verticeToIndex.Add(v, vIndex);
|
||||
m_vertices.Add(vert);
|
||||
v.x = -v.x;
|
||||
v *= m_uvScale;
|
||||
m_uvs.Add(v);
|
||||
}
|
||||
return vIndex;
|
||||
}
|
||||
|
||||
public void Save(string fileName)
|
||||
{
|
||||
// Export to .obj
|
||||
StreamWriter sw = new StreamWriter(fileName);
|
||||
try
|
||||
{
|
||||
sw.WriteLine("# Unity terrain OBJ File");
|
||||
|
||||
// Write vertices
|
||||
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
|
||||
|
||||
for (int i = 0; i < m_vertices.Count; i++)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("v ", 64);
|
||||
// StringBuilder stuff is done this way because it's faster than using the "{0} {1} {2}"etc. format
|
||||
// Which is important when you're exporting huge terrains.
|
||||
sb.Append(m_vertices[i].x.ToString()).Append(" ").
|
||||
Append(m_vertices[i].y.ToString()).Append(" ").
|
||||
Append(m_vertices[i].z.ToString());
|
||||
sw.WriteLine(sb);
|
||||
}
|
||||
// Write UVs
|
||||
for (int i = 0; i < m_uvs.Count; i++)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("vt ", 48);
|
||||
sb.Append(m_uvs[i].x.ToString()).Append(" ").
|
||||
Append(m_uvs[i].y.ToString());
|
||||
sw.WriteLine(sb);
|
||||
}
|
||||
if (usingTriangles)
|
||||
{
|
||||
// Write triangles
|
||||
for (int i = 0; i < m_indices.Count; i += 3)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("f ", 43);
|
||||
sb.Append(m_indices[i] + 1).Append("/").Append(m_indices[i] + 1).Append(" ").
|
||||
Append(m_indices[i + 1] + 1).Append("/").Append(m_indices[i + 1] + 1).Append(" ").
|
||||
Append(m_indices[i + 2] + 1).Append("/").Append(m_indices[i + 2] + 1);
|
||||
sw.WriteLine(sb);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write quads
|
||||
for (int i = 0; i < m_indices.Count; i += 4)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("f ", 64);
|
||||
sb.Append(m_indices[i] + 1).Append("/").Append(m_indices[i] + 1).Append(" ").
|
||||
Append(m_indices[i + 1] + 1).Append("/").Append(m_indices[i + 1] + 1).Append(" ").
|
||||
Append(m_indices[i + 2] + 1).Append("/").Append(m_indices[i + 2] + 1).Append(" ").
|
||||
Append(m_indices[i + 3] + 1).Append("/").Append(m_indices[i + 3] + 1);
|
||||
sw.WriteLine(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception err)
|
||||
{
|
||||
Debug.Log("Error saving file: " + err.Message);
|
||||
}
|
||||
sw.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d2fefeb705133849953cb8d91f4d516
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,439 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public struct Mathd
|
||||
{
|
||||
public const double PI = 3.141593d;
|
||||
public const double Infinity = double.PositiveInfinity;
|
||||
public const double NegativeInfinity = double.NegativeInfinity;
|
||||
public const double Deg2Rad = 0.01745329d;
|
||||
public const double Rad2Deg = 57.29578d;
|
||||
public const double Epsilon = 1.401298E-45d;
|
||||
|
||||
public static double Sin(double d)
|
||||
{
|
||||
return Math.Sin(d);
|
||||
}
|
||||
|
||||
public static double Cos(double d)
|
||||
{
|
||||
return Math.Cos(d);
|
||||
}
|
||||
|
||||
public static double Tan(double d)
|
||||
{
|
||||
return Math.Tan(d);
|
||||
}
|
||||
|
||||
public static double Asin(double d)
|
||||
{
|
||||
return Math.Asin(d);
|
||||
}
|
||||
|
||||
public static double Acos(double d)
|
||||
{
|
||||
return Math.Acos(d);
|
||||
}
|
||||
|
||||
public static double Atan(double d)
|
||||
{
|
||||
return Math.Atan(d);
|
||||
}
|
||||
|
||||
public static double Atan2(double y, double x)
|
||||
{
|
||||
return Math.Atan2(y, x);
|
||||
}
|
||||
|
||||
public static double Sqrt(double d)
|
||||
{
|
||||
return Math.Sqrt(d);
|
||||
}
|
||||
|
||||
public static double Abs(double d)
|
||||
{
|
||||
return Math.Abs(d);
|
||||
}
|
||||
|
||||
public static int Abs(int value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
public static double Min(double a, double b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
public static double Min(params double[] values)
|
||||
{
|
||||
int length = values.Length;
|
||||
if (length == 0)
|
||||
return 0.0d;
|
||||
double num = values[0];
|
||||
for (int index = 1; index < length; ++index)
|
||||
{
|
||||
if (values[index] < num)
|
||||
num = values[index];
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public static int Min(int a, int b)
|
||||
{
|
||||
if (a < b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
public static int Min(params int[] values)
|
||||
{
|
||||
int length = values.Length;
|
||||
if (length == 0)
|
||||
return 0;
|
||||
int num = values[0];
|
||||
for (int index = 1; index < length; ++index)
|
||||
{
|
||||
if (values[index] < num)
|
||||
num = values[index];
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public static double Max(double a, double b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
public static double Max(params double[] values)
|
||||
{
|
||||
int length = values.Length;
|
||||
if (length == 0)
|
||||
return 0d;
|
||||
double num = values[0];
|
||||
for (int index = 1; index < length; ++index)
|
||||
{
|
||||
if ((double)values[index] > (double)num)
|
||||
num = values[index];
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public static int Max(int a, int b)
|
||||
{
|
||||
if (a > b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
public static int Max(params int[] values)
|
||||
{
|
||||
int length = values.Length;
|
||||
if (length == 0)
|
||||
return 0;
|
||||
int num = values[0];
|
||||
for (int index = 1; index < length; ++index)
|
||||
{
|
||||
if (values[index] > num)
|
||||
num = values[index];
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
public static double Pow(double d, double p)
|
||||
{
|
||||
return Math.Pow(d, p);
|
||||
}
|
||||
|
||||
public static double Exp(double power)
|
||||
{
|
||||
return Math.Exp(power);
|
||||
}
|
||||
|
||||
public static double Log(double d, double p)
|
||||
{
|
||||
return Math.Log(d, p);
|
||||
}
|
||||
|
||||
public static double Log(double d)
|
||||
{
|
||||
return Math.Log(d);
|
||||
}
|
||||
|
||||
public static double Log10(double d)
|
||||
{
|
||||
return Math.Log10(d);
|
||||
}
|
||||
|
||||
public static double Ceil(double d)
|
||||
{
|
||||
return Math.Ceiling(d);
|
||||
}
|
||||
|
||||
public static double Floor(double d)
|
||||
{
|
||||
return Math.Floor(d);
|
||||
}
|
||||
|
||||
public static double Round(double d)
|
||||
{
|
||||
return Math.Round(d);
|
||||
}
|
||||
|
||||
public static int CeilToInt(double d)
|
||||
{
|
||||
return (int)Math.Ceiling(d);
|
||||
}
|
||||
|
||||
public static int FloorToInt(double d)
|
||||
{
|
||||
return (int)Math.Floor(d);
|
||||
}
|
||||
|
||||
public static int RoundToInt(double d)
|
||||
{
|
||||
return (int)Math.Round(d);
|
||||
}
|
||||
|
||||
public static double Sign(double d)
|
||||
{
|
||||
return d >= 0.0 ? 1d : -1d;
|
||||
}
|
||||
|
||||
public static double Clamp(double value, double min, double max)
|
||||
{
|
||||
if (value < min)
|
||||
value = min;
|
||||
else if (value > max)
|
||||
value = max;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static int Clamp(int value, int min, int max)
|
||||
{
|
||||
if (value < min)
|
||||
value = min;
|
||||
else if (value > max)
|
||||
value = max;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static double Clamp01(double value)
|
||||
{
|
||||
if (value < 0.0)
|
||||
return 0.0d;
|
||||
if (value > 1.0)
|
||||
return 1d;
|
||||
else
|
||||
return value;
|
||||
}
|
||||
|
||||
public static double Lerp(double from, double to, double t)
|
||||
{
|
||||
return from + (to - from) * Mathd.Clamp01(t);
|
||||
}
|
||||
|
||||
public static double LerpAngle(double a, double b, double t)
|
||||
{
|
||||
double num = Mathd.Repeat(b - a, 360d);
|
||||
if (num > 180.0d)
|
||||
num -= 360d;
|
||||
return a + num * Mathd.Clamp01(t);
|
||||
}
|
||||
|
||||
public static double MoveTowards(double current, double target, double maxDelta)
|
||||
{
|
||||
if (Mathd.Abs(target - current) <= maxDelta)
|
||||
return target;
|
||||
else
|
||||
return current + Mathd.Sign(target - current) * maxDelta;
|
||||
}
|
||||
|
||||
public static double MoveTowardsAngle(double current, double target, double maxDelta)
|
||||
{
|
||||
target = current + Mathd.DeltaAngle(current, target);
|
||||
return Mathd.MoveTowards(current, target, maxDelta);
|
||||
}
|
||||
|
||||
public static double SmoothStep(double from, double to, double t)
|
||||
{
|
||||
t = Mathd.Clamp01(t);
|
||||
t = (-2.0 * t * t * t + 3.0 * t * t);
|
||||
return to * t + from * (1.0 - t);
|
||||
}
|
||||
|
||||
public static double Gamma(double value, double absmax, double gamma)
|
||||
{
|
||||
bool flag = false;
|
||||
if (value < 0.0)
|
||||
flag = true;
|
||||
double num1 = Mathd.Abs(value);
|
||||
if (num1 > absmax)
|
||||
{
|
||||
if (flag)
|
||||
return -num1;
|
||||
else
|
||||
return num1;
|
||||
}
|
||||
else
|
||||
{
|
||||
double num2 = Mathd.Pow(num1 / absmax, gamma) * absmax;
|
||||
if (flag)
|
||||
return -num2;
|
||||
else
|
||||
return num2;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Approximately(double a, double b)
|
||||
{
|
||||
return Mathd.Abs(b - a) < Mathd.Max(1E-06d * Mathd.Max(Mathd.Abs(a), Mathd.Abs(b)), 1.121039E-44d);
|
||||
}
|
||||
|
||||
public static double SmoothDamp(double current, double target, ref double currentVelocity, double smoothTime, double maxSpeed)
|
||||
{
|
||||
double deltaTime = (double)UnityEngine.Time.deltaTime;
|
||||
return Mathd.SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
|
||||
}
|
||||
|
||||
public static double SmoothDamp(double current, double target, ref double currentVelocity, double smoothTime)
|
||||
{
|
||||
double deltaTime = UnityEngine.Time.deltaTime;
|
||||
double maxSpeed = double.PositiveInfinity;
|
||||
return Mathd.SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
|
||||
}
|
||||
|
||||
public static double SmoothDamp(double current, double target, ref double currentVelocity, double smoothTime, double maxSpeed, double deltaTime)
|
||||
{
|
||||
smoothTime = Mathd.Max(0.0001d, smoothTime);
|
||||
double num1 = 2d / smoothTime;
|
||||
double num2 = num1 * deltaTime;
|
||||
double num3 = (1.0d / (1.0d + num2 + 0.479999989271164d * num2 * num2 + 0.234999999403954d * num2 * num2 * num2));
|
||||
double num4 = current - target;
|
||||
double num5 = target;
|
||||
double max = maxSpeed * smoothTime;
|
||||
double num6 = Mathd.Clamp(num4, -max, max);
|
||||
target = current - num6;
|
||||
double num7 = (currentVelocity + num1 * num6) * deltaTime;
|
||||
currentVelocity = (currentVelocity - num1 * num7) * num3;
|
||||
double num8 = target + (num6 + num7) * num3;
|
||||
if (num5 - current > 0.0 == num8 > num5)
|
||||
{
|
||||
num8 = num5;
|
||||
currentVelocity = (num8 - num5) / deltaTime;
|
||||
}
|
||||
return num8;
|
||||
}
|
||||
|
||||
public static double SmoothDampAngle(double current, double target, ref double currentVelocity, double smoothTime, double maxSpeed)
|
||||
{
|
||||
double deltaTime = (double)Time.deltaTime;
|
||||
return Mathd.SmoothDampAngle(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
|
||||
}
|
||||
|
||||
public static double SmoothDampAngle(double current, double target, ref double currentVelocity, double smoothTime)
|
||||
{
|
||||
double deltaTime = (double)Time.deltaTime;
|
||||
double maxSpeed = double.PositiveInfinity;
|
||||
return Mathd.SmoothDampAngle(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
|
||||
}
|
||||
|
||||
public static double SmoothDampAngle(double current, double target, ref double currentVelocity, double smoothTime, double maxSpeed, double deltaTime)
|
||||
{
|
||||
target = current + Mathd.DeltaAngle(current, target);
|
||||
return Mathd.SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
|
||||
}
|
||||
|
||||
public static double Repeat(double t, double length)
|
||||
{
|
||||
return t - Mathd.Floor(t / length) * length;
|
||||
}
|
||||
|
||||
public static double PingPong(double t, double length)
|
||||
{
|
||||
t = Mathd.Repeat(t, length * 2d);
|
||||
return length - Mathd.Abs(t - length);
|
||||
}
|
||||
|
||||
public static double InverseLerp(double from, double to, double value)
|
||||
{
|
||||
if (from < to)
|
||||
{
|
||||
if (value < from)
|
||||
return 0d;
|
||||
if (value > to)
|
||||
return 1d;
|
||||
value -= from;
|
||||
value /= to - from;
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from <= to)
|
||||
return 0d;
|
||||
if (value < to)
|
||||
return 1d;
|
||||
if (value > from)
|
||||
return 0d;
|
||||
else
|
||||
return (1.0d - (value - to) / (from - to));
|
||||
}
|
||||
}
|
||||
|
||||
public static double DeltaAngle(double current, double target)
|
||||
{
|
||||
double num = Mathd.Repeat(target - current, 360d);
|
||||
if (num > 180.0d)
|
||||
num -= 360d;
|
||||
return num;
|
||||
}
|
||||
|
||||
//internal static bool LineIntersection(Vector2d p1, Vector2d p2, Vector2d p3, Vector2d p4, ref Vector2d result)
|
||||
//{
|
||||
// double num1 = p2.x - p1.x;
|
||||
// double num2 = p2.y - p1.y;
|
||||
// double num3 = p4.x - p3.x;
|
||||
// double num4 = p4.y - p3.y;
|
||||
// double num5 = num1 * num4 - num2 * num3;
|
||||
// if (num5 == 0.0d)
|
||||
// return false;
|
||||
// double num6 = p3.x - p1.x;
|
||||
// double num7 = p3.y - p1.y;
|
||||
// double num8 = (num6 * num4 - num7 * num3) / num5;
|
||||
// result = new Vector2d(p1.x + num8 * num1, p1.y + num8 * num2);
|
||||
// return true;
|
||||
//}
|
||||
|
||||
//internal static bool LineSegmentIntersection(Vector2d p1, Vector2d p2, Vector2d p3, Vector2d p4, ref Vector2d result)
|
||||
//{
|
||||
// double num1 = p2.x - p1.x;
|
||||
// double num2 = p2.y - p1.y;
|
||||
// double num3 = p4.x - p3.x;
|
||||
// double num4 = p4.y - p3.y;
|
||||
// double num5 = (num1 * num4 - num2 * num3);
|
||||
// if (num5 == 0.0d)
|
||||
// return false;
|
||||
// double num6 = p3.x - p1.x;
|
||||
// double num7 = p3.y - p1.y;
|
||||
// double num8 = (num6 * num4 - num7 * num3) / num5;
|
||||
// if (num8 < 0.0d || num8 > 1.0d)
|
||||
// return false;
|
||||
// double num9 = (num6 * num2 - num7 * num1) / num5;
|
||||
// if (num9 < 0.0d || num9 > 1.0d)
|
||||
// return false;
|
||||
// result = new Vector2d(p1.x + num8 * num1, p1.y + num8 * num2);
|
||||
// return true;
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb8c7213a91b1194abda2c0a2d18f136
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#if HDPipeline
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
#endif
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class to provide the functionality of performing an "orthographic bake" from anywhere and return a render texture as result.
|
||||
/// In an orthographic bake an orthographic camera is placed above the terrain pointing straight downwards to render the current view to a render texture.
|
||||
/// </summary>
|
||||
public class OrthographicBake
|
||||
{
|
||||
static Camera m_orthoCamera;
|
||||
public static RenderTexture m_tmpRenderTexture;
|
||||
private static List<Light> m_deactivatedLights = new List<Light>();
|
||||
private static GameObject m_bakeDirectionalLight;
|
||||
internal static int m_HDLODBiasOverride = 1;
|
||||
|
||||
public static Camera CreateOrthoCam(Vector3 position, float nearClipping, float farClipping, float size, LayerMask cullingMask)
|
||||
{
|
||||
//existing ortho cam? Try to recycle
|
||||
GameObject gameObject = GameObject.Find("OrthoCaptureCam");
|
||||
|
||||
if (gameObject == null)
|
||||
{
|
||||
gameObject = new GameObject("OrthoCaptureCam");
|
||||
}
|
||||
gameObject.transform.position = position;
|
||||
//facing straight downwards
|
||||
gameObject.transform.rotation = Quaternion.Euler(90f, 0f, 0f);
|
||||
|
||||
|
||||
//existing Camera? Try to recycle
|
||||
Camera cam = gameObject.GetComponent<Camera>();
|
||||
|
||||
if (cam == null)
|
||||
{
|
||||
cam = gameObject.AddComponent<Camera>();
|
||||
}
|
||||
|
||||
//setup camera the way we need it for the ortho bake - adjust everything to default to make sure there is no interference
|
||||
cam.clearFlags = CameraClearFlags.SolidColor;
|
||||
cam.backgroundColor = Color.black;
|
||||
cam.cullingMask = cullingMask;
|
||||
cam.orthographic = true;
|
||||
cam.orthographicSize = size;
|
||||
cam.nearClipPlane = nearClipping;
|
||||
cam.farClipPlane = farClipping;
|
||||
cam.rect = new Rect(0f, 0f, 1f, 1f);
|
||||
cam.depth = 0f;
|
||||
cam.renderingPath = RenderingPath.Forward; //Forward rendering required for orthographic
|
||||
cam.useOcclusionCulling = true;
|
||||
|
||||
#if HDPipeline
|
||||
HDAdditionalCameraData hdData = gameObject.GetComponent<HDAdditionalCameraData>();
|
||||
if (hdData == null)
|
||||
{
|
||||
hdData = cam.gameObject.AddComponent<UnityEngine.Rendering.HighDefinition.HDAdditionalCameraData>();
|
||||
}
|
||||
hdData.volumeLayerMask = 0;
|
||||
hdData.backgroundColorHDR = Color.black;
|
||||
hdData.clearColorMode = HDAdditionalCameraData.ClearColorMode.Color;
|
||||
|
||||
FrameSettings frameSettings = new FrameSettings();
|
||||
frameSettings.lodBiasMode = LODBiasMode.OverrideQualitySettings;
|
||||
frameSettings.lodBias = m_HDLODBiasOverride;
|
||||
hdData.customRenderingSettings = true;
|
||||
hdData.renderingPathCustomFrameSettings = frameSettings;
|
||||
hdData.renderingPathCustomFrameSettingsOverrideMask.mask[0] = true;
|
||||
hdData.renderingPathCustomFrameSettingsOverrideMask.mask[(int)FrameSettingsField.LODBiasMode] = true;
|
||||
hdData.renderingPathCustomFrameSettingsOverrideMask.mask[(int)FrameSettingsField.LODBias] = true;
|
||||
#endif
|
||||
|
||||
m_orthoCamera = cam;
|
||||
return cam;
|
||||
|
||||
}
|
||||
|
||||
public static void RemoveOrthoCam()
|
||||
{
|
||||
if (m_orthoCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_orthoCamera.targetTexture != null)
|
||||
{
|
||||
RenderTexture.ReleaseTemporary(m_orthoCamera.targetTexture);
|
||||
m_orthoCamera.targetTexture = null;
|
||||
}
|
||||
|
||||
GameObject.DestroyImmediate(m_orthoCamera.gameObject);
|
||||
}
|
||||
|
||||
public static void BakeTerrain(Terrain terrain, int Xresolution, int Yresolution, LayerMask cullingMask, string path = null)
|
||||
{
|
||||
CreateOrthoCam(terrain.GetPosition() + new Vector3(terrain.terrainData.size.x / 2f, 0f, terrain.terrainData.size.z / 2f), -(terrain.terrainData.size.y + 200f), 1f, terrain.terrainData.size.x / 2f, cullingMask);
|
||||
RenderTextureDescriptor rtDesc = new RenderTextureDescriptor();
|
||||
rtDesc.autoGenerateMips = true;
|
||||
rtDesc.bindMS = false;
|
||||
rtDesc.colorFormat = RenderTextureFormat.ARGB32;
|
||||
rtDesc.depthBufferBits = 24;
|
||||
rtDesc.dimension = UnityEngine.Rendering.TextureDimension.Tex2D;
|
||||
rtDesc.enableRandomWrite = false;
|
||||
//rtDesc.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R8_SRGB;
|
||||
rtDesc.height = Yresolution;
|
||||
rtDesc.memoryless = RenderTextureMemoryless.None;
|
||||
rtDesc.msaaSamples = 1;
|
||||
rtDesc.sRGB = true;
|
||||
rtDesc.shadowSamplingMode = UnityEngine.Rendering.ShadowSamplingMode.None;
|
||||
rtDesc.useDynamicScale = false;
|
||||
rtDesc.useMipMap = false;
|
||||
rtDesc.volumeDepth = 1;
|
||||
rtDesc.vrUsage = VRTextureUsage.None;
|
||||
rtDesc.width = Xresolution;
|
||||
m_tmpRenderTexture = RenderTexture.GetTemporary(rtDesc);
|
||||
if (path != null)
|
||||
{
|
||||
RenderToPng(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderToTemporary();
|
||||
}
|
||||
}
|
||||
|
||||
private static void RenderToTemporary()
|
||||
{
|
||||
if (m_orthoCamera == null)
|
||||
{
|
||||
Debug.LogError("Orthographic Bake: Camera does not exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
m_orthoCamera.targetTexture = m_tmpRenderTexture;
|
||||
m_orthoCamera.Render();
|
||||
//In the SRPs we get a flipped image when rendering from a camera to a render textures, need to flip it on the Y-axis for or purposes
|
||||
#if HDPipeline || UPPipeline
|
||||
Material flipMat = new Material(Shader.Find("Hidden/Gaia/FlipY"));
|
||||
flipMat.SetTexture("_InputTex", m_tmpRenderTexture);
|
||||
RenderTexture buffer = RenderTexture.GetTemporary(m_tmpRenderTexture.descriptor);
|
||||
Graphics.Blit(m_tmpRenderTexture, buffer, flipMat);
|
||||
Graphics.Blit(buffer, m_tmpRenderTexture);
|
||||
RenderTexture.ReleaseTemporary(buffer);
|
||||
#endif
|
||||
RenderTexture.active = m_tmpRenderTexture;
|
||||
}
|
||||
|
||||
private static void RenderToPng(string path)
|
||||
{
|
||||
RenderToTemporary();
|
||||
ImageProcessing.WriteRenderTexture(path, m_tmpRenderTexture, GaiaConstants.ImageFileType.Png, TextureFormat.RGBA32);
|
||||
CleanUpRenderTexture();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// switches off all active lights in the scene and stores the lights in a list to turn them back on later with LightsOn()
|
||||
/// </summary>
|
||||
public static void LightsOff()
|
||||
{
|
||||
m_deactivatedLights.Clear();
|
||||
var allLights = Resources.FindObjectsOfTypeAll<Light>();
|
||||
foreach (Light light in allLights)
|
||||
{
|
||||
if (light.isActiveAndEnabled)
|
||||
{
|
||||
light.enabled = false;
|
||||
m_deactivatedLights.Add(light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// turns all the lights on again that were disabled with LightsOff before
|
||||
/// </summary>
|
||||
public static void LightsOn()
|
||||
{
|
||||
foreach (Light light in m_deactivatedLights)
|
||||
{
|
||||
light.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void CleanUpRenderTexture()
|
||||
{
|
||||
m_orthoCamera.targetTexture = null;
|
||||
RenderTexture.active = null;
|
||||
RenderTexture.ReleaseTemporary(m_tmpRenderTexture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a directional light pointing straight downwards on the y-axis with the given intensity & color. Use this together with LightsOn & LightsOff to better control lighting during the scene.
|
||||
/// </summary>
|
||||
/// <param name="intensity">Intensity for the directional light.</param>
|
||||
/// <param name="color">Color for the directional light.</param>
|
||||
public static void CreateBakeDirectionalLight(float intensity, Color color)
|
||||
{
|
||||
GameObject lightGO = GameObject.Find(GaiaConstants.BakeDirectionalLight);
|
||||
if (lightGO == null)
|
||||
{
|
||||
lightGO = new GameObject(GaiaConstants.BakeDirectionalLight);
|
||||
}
|
||||
m_bakeDirectionalLight = lightGO;
|
||||
Light light = lightGO.GetComponent<Light>();
|
||||
if (light == null)
|
||||
{
|
||||
light = lightGO.AddComponent<Light>();
|
||||
}
|
||||
light.shadows = LightShadows.None;
|
||||
light.type = LightType.Directional;
|
||||
light.transform.rotation = Quaternion.Euler(90, 0, 0);
|
||||
light.intensity = intensity;
|
||||
light.color = color;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the bake directional light (Created with CreateBakeDirectionalLight()) from the scene again.
|
||||
/// </summary>
|
||||
public static void RemoveBakeDirectionalLight()
|
||||
{
|
||||
if (m_bakeDirectionalLight != null)
|
||||
{
|
||||
GameObject.DestroyImmediate(m_bakeDirectionalLight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe6f8166c7021494d849ef1f650dc9e4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
///// <summary>
|
||||
///// Priority definitions. The idea is to give the priority a human readable identification and control all priorities in a central location
|
||||
///// instead of 100s of places within the application. The priority of these items is defined by their position in this enum, first entry = lowest priority, last entry = highest priority.
|
||||
///// </summary>
|
||||
public enum ProgressBarPriority { TerrainLoading, MinMaxHeightCalculation, CreateBiomeTools, CreateSceneTools, BiomeRemoval, MultiTerrainAction, TerrainMeshExport, MaskMapExport, Stamping, Spawning, WorldCreation, GaiaGeospatial, Maintenance };
|
||||
|
||||
//public class ProgressBarPriority
|
||||
//{
|
||||
// public string m_name;
|
||||
// public int m_priority;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Static class to display an unified progress bar in Gaia. Allows to set a priority so that a progress bar for a longer, overarching process
|
||||
/// is not constantly interrupted by smaller processes, e.g. the world creation progress bar is not interrupted by progress bars for terrain loading.
|
||||
/// </summary>
|
||||
public static class ProgressBar
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// The current priority of the last progress bar that was shown.
|
||||
/// </summary>
|
||||
public static int m_currentPriority =0;
|
||||
/// <summary>
|
||||
/// The average duration in milliseconds to perform one of the progress bar steps.
|
||||
/// </summary>
|
||||
static long m_averageStepDuration = 0;
|
||||
/// <summary>
|
||||
/// The timestamp when the last step for this progress bar was completed before.
|
||||
/// </summary>
|
||||
static long m_lastStepTimeStamp = 0;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Shows a progress bar with a given priority.
|
||||
/// </summary>
|
||||
/// <param name="priorityName">An enum value that controls the priority of this progress bar. (See ProgressBar.cs for the definitions!)</param>
|
||||
/// <param name="title">The title for the progress bar window. Will be appended by step count and ETA if chosen.</param>
|
||||
/// <param name="info">The info text below the progress bar.</param>
|
||||
/// <param name="currentStep">The current step for the process that the progress bar represents. If the process can't be split into steps, put 0 in here.</param>
|
||||
/// <param name="totalSteps">The total amount of steps for the process that the progress bar represents. If the process can't be split into steps, put 0 in here.</param>
|
||||
/// <param name="displayETA">Whether you want an ETA (estimated time of arrival) to be displayed in the title</param>
|
||||
/// <param name="cancelable">Whether the progress bar should have a cancel button.</param>
|
||||
/// <returns>Returns true if the user clicked on the cancel button in the progress bar.</returns>
|
||||
public static bool Show(ProgressBarPriority priority, string title, string info, int currentStep = 0, int totalSteps = 0, bool displayETA = false, bool cancelable = false)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
int newPriority = 0;
|
||||
newPriority = (int)priority;
|
||||
|
||||
//New priority needs to be higher as current one, otherwise we won't interrupt the current progress bar
|
||||
if (newPriority < m_currentPriority)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newPriority != m_currentPriority)
|
||||
{
|
||||
m_currentPriority = newPriority;
|
||||
//new priority? reset the variables for ETA calculation as well
|
||||
m_averageStepDuration = 0;
|
||||
m_lastStepTimeStamp = 0;
|
||||
}
|
||||
if (totalSteps > 0)
|
||||
{
|
||||
title = string.Format(title + " - Step {0} of {1}", currentStep.ToString(), totalSteps.ToString());
|
||||
}
|
||||
|
||||
//ETA calculations
|
||||
if (m_lastStepTimeStamp > 0 && currentStep > 0)
|
||||
{
|
||||
m_averageStepDuration = (m_averageStepDuration * (currentStep -1) + (GaiaUtils.GetUnixTimestamp() - m_lastStepTimeStamp)) / (long)currentStep;
|
||||
}
|
||||
m_lastStepTimeStamp = GaiaUtils.GetUnixTimestamp();
|
||||
|
||||
if (displayETA && currentStep >=1)
|
||||
{
|
||||
title += ", ETA: " + TimeSpan.FromMilliseconds(m_averageStepDuration * (totalSteps -currentStep)).ToString(@"hh\:mm\:ss");
|
||||
}
|
||||
|
||||
//Progress calculations
|
||||
float progress = 0.5f;
|
||||
if (totalSteps > 0)
|
||||
{
|
||||
progress = (float)currentStep / (float)totalSteps;
|
||||
}
|
||||
|
||||
if (cancelable)
|
||||
{
|
||||
if (EditorUtility.DisplayCancelableProgressBar(title, info, progress))
|
||||
{
|
||||
//cancel was pressed, make sure the process bar is being cleared in any case.
|
||||
m_currentPriority = 0;
|
||||
m_averageStepDuration = 0;
|
||||
m_lastStepTimeStamp = 0;
|
||||
EditorUtility.ClearProgressBar();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayProgressBar(title, info, progress);
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current progress bar, if the given name is current priority or higher.
|
||||
/// </summary>
|
||||
public static void Clear(ProgressBarPriority priority)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
//Get the priority of the given name
|
||||
int newPriority = 0;
|
||||
newPriority = (int)priority;
|
||||
|
||||
//Progress bar with lower priority may not clear the current one
|
||||
if (newPriority < m_currentPriority)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentPriority = 0;
|
||||
m_averageStepDuration = 0;
|
||||
m_lastStepTimeStamp = 0;
|
||||
EditorUtility.ClearProgressBar();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1a59128bd0bfe4499e26400f0a9beea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,420 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// A region quadtree implementation used for fast lookup in a two dimensional world.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// The type to store inside the tree.
|
||||
/// </typeparam>
|
||||
/// <remarks>
|
||||
/// This implementation is not thread-safe.
|
||||
/// </remarks>
|
||||
public class Quadtree<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum number of nodes per tree.
|
||||
/// </summary>
|
||||
private readonly int nodeCapacity = 32;
|
||||
|
||||
/// <summary>
|
||||
/// The nodes inside this region.
|
||||
/// </summary>
|
||||
private readonly List<QuadtreeNode> nodes;
|
||||
|
||||
/// <summary>
|
||||
/// The child trees inside this region.
|
||||
/// </summary>
|
||||
private Quadtree<T>[] children;
|
||||
|
||||
/// <summary>
|
||||
/// The boundaries of this region.
|
||||
/// </summary>
|
||||
private Rect boundaries;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of values inside this tree.
|
||||
/// </summary>
|
||||
public int Count
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:Quadtree`1"/> class.
|
||||
/// </summary>
|
||||
/// <param name="boundaries">
|
||||
/// The boundaries of the region.
|
||||
/// </param>
|
||||
/// <param name="nodeCapacity">
|
||||
/// The maximum number of nodes per tree.
|
||||
/// If the amount of nodes exceeds the tree will be subdivided into 4 sub trees.
|
||||
/// A value of 32 seems fine in terms of insert and remove speed.
|
||||
/// A value greater than 32 improves insert speed but slows down remove speed.
|
||||
/// </param>
|
||||
public Quadtree(Rect boundaries, int nodeCapacity = 32)
|
||||
{
|
||||
this.boundaries = boundaries;
|
||||
this.nodeCapacity = nodeCapacity;
|
||||
|
||||
this.nodes = new List<QuadtreeNode>(nodeCapacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a value into the region.
|
||||
/// </summary>
|
||||
/// <param name="x">
|
||||
/// The X component of the value's position.
|
||||
/// </param>
|
||||
/// <param name="y">
|
||||
/// The y component of the value's position.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The value to insert.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the value was inserted into the region;
|
||||
/// false if the value's position was outside the region.
|
||||
/// </returns>
|
||||
public bool Insert(float x, float y, T value)
|
||||
{
|
||||
var position = new Vector2(x, y);
|
||||
var node = new QuadtreeNode(position, value);
|
||||
return this.Insert(node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a value into the region.
|
||||
/// </summary>
|
||||
/// <param name="position">
|
||||
/// The position of the value.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The value to insert.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the value was inserted into the region;
|
||||
/// false if the value's position was outside the region.
|
||||
/// </returns>
|
||||
public bool Insert(Vector2 position, T value)
|
||||
{
|
||||
var node = new QuadtreeNode(position, value);
|
||||
return this.Insert(node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a node into the region.
|
||||
/// </summary>
|
||||
/// <param name="node">
|
||||
/// The node to insert.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the node was inserted into the region;
|
||||
/// false if the position of the node was outside the region.
|
||||
/// </returns>
|
||||
private bool Insert(QuadtreeNode node)
|
||||
{
|
||||
if (!this.boundaries.Contains(node.Position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.children != null)
|
||||
{
|
||||
Quadtree<T> child;
|
||||
if (node.Position.y < this.children[2].boundaries.yMin)
|
||||
{
|
||||
if (node.Position.x < this.children[1].boundaries.xMin)
|
||||
{
|
||||
child = this.children[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
child = this.children[1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Position.x < this.children[1].boundaries.xMin)
|
||||
{
|
||||
child = this.children[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
child = this.children[3];
|
||||
}
|
||||
}
|
||||
|
||||
if (child.Insert(node))
|
||||
{
|
||||
this.Count++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.nodes.Count < this.nodeCapacity)
|
||||
{
|
||||
this.nodes.Add(node);
|
||||
this.Count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
this.Subdivide();
|
||||
return this.Insert(node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the values that are within the specified <paramref name="range"/>.
|
||||
/// </summary>
|
||||
/// <param name="range">
|
||||
/// A rectangle representing the region to query.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Any value found inside the specified <paramref name="range"/>.
|
||||
/// </returns>
|
||||
public IEnumerable<T> Find(Rect range)
|
||||
{
|
||||
if (this.Count == 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var rangexMax = range.xMax;
|
||||
var rangexMin = range.xMin;
|
||||
var rangeyMax = range.yMax;
|
||||
var rangeyMin = range.yMin;
|
||||
if (!(
|
||||
this.boundaries.xMin < rangexMax &&
|
||||
this.boundaries.xMax > rangexMin &&
|
||||
this.boundaries.yMin < rangeyMax &&
|
||||
this.boundaries.yMax > rangeyMin
|
||||
))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
||||
if (this.children == null)
|
||||
{
|
||||
for (var index = 0; index < this.nodes.Count; index++)
|
||||
{
|
||||
var node = this.nodes[index];
|
||||
if (
|
||||
node.Position.x >= rangexMin &&
|
||||
node.Position.x <= rangexMax &&
|
||||
node.Position.y >= rangeyMin &&
|
||||
node.Position.y <= rangeyMax
|
||||
)
|
||||
{
|
||||
yield return node.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var index = 0; index < this.children.Length; index++)
|
||||
{
|
||||
var child = this.children[index];
|
||||
|
||||
foreach (var value in child.Find(range))
|
||||
{
|
||||
yield return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a value from the region.
|
||||
/// </summary>
|
||||
/// <param name="x">
|
||||
/// The X component of the value's position.
|
||||
/// </param>
|
||||
/// <param name="z">
|
||||
/// The Z component of the value's position.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The value to remove.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the value was removed from the region;
|
||||
/// false if the value's position was outside the region.
|
||||
/// </returns>
|
||||
public bool Remove(float x, float z, T value)
|
||||
{
|
||||
return this.Remove(new Vector2(x, z), value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a value from the region.
|
||||
/// </summary>
|
||||
/// <param name="position">
|
||||
/// The position of the value.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The value to remove.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// true if the value was removed from the region;
|
||||
/// false if the value's position was outside the region.
|
||||
/// </returns>
|
||||
public bool Remove(Vector2 position, T value)
|
||||
{
|
||||
if (this.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.boundaries.Contains(position))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.children != null)
|
||||
{
|
||||
var isRemoved = false;
|
||||
|
||||
Quadtree<T> child;
|
||||
if (position.y < this.children[2].boundaries.yMin)
|
||||
{
|
||||
if (position.x < this.children[1].boundaries.xMin)
|
||||
{
|
||||
child = this.children[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
child = this.children[1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (position.x < this.children[1].boundaries.xMin)
|
||||
{
|
||||
child = this.children[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
child = this.children[3];
|
||||
}
|
||||
}
|
||||
|
||||
if (child.Remove(position, value))
|
||||
{
|
||||
isRemoved = true;
|
||||
this.Count--;
|
||||
}
|
||||
|
||||
if (this.Count <= this.nodeCapacity)
|
||||
{
|
||||
this.Combine();
|
||||
}
|
||||
|
||||
return isRemoved;
|
||||
}
|
||||
|
||||
for (var index = 0; index < this.nodes.Count; index++)
|
||||
{
|
||||
var node = this.nodes[index];
|
||||
if (node.Position.Equals(position))
|
||||
{
|
||||
this.nodes.RemoveAt(index);
|
||||
this.Count--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the region into 4 new subregions and moves the existing values into the new subregions.
|
||||
/// </summary>
|
||||
private void Subdivide()
|
||||
{
|
||||
this.children = new Quadtree<T>[4];
|
||||
|
||||
var width = this.boundaries.width * 0.5f;
|
||||
var height = this.boundaries.height * 0.5f;
|
||||
|
||||
for (var index = 0; index < this.children.Length; index++)
|
||||
{
|
||||
var boundaries = new Rect(
|
||||
this.boundaries.xMin + width * (index % 2),
|
||||
this.boundaries.yMin + height * (index / 2),
|
||||
width,
|
||||
height
|
||||
);
|
||||
|
||||
this.children[index] = new Quadtree<T>(boundaries);
|
||||
}
|
||||
|
||||
this.Count = 0;
|
||||
|
||||
for (var index = 0; index < this.nodes.Count; index++)
|
||||
{
|
||||
var node = this.nodes[index];
|
||||
this.Insert(node);
|
||||
}
|
||||
|
||||
this.nodes.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Joins the contents of the children into this region and remove the child regions.
|
||||
/// </summary>
|
||||
private void Combine()
|
||||
{
|
||||
for (var index = 0; index < this.children.Length; index++)
|
||||
{
|
||||
var child = this.children[index];
|
||||
this.nodes.AddRange(child.nodes);
|
||||
}
|
||||
|
||||
this.children = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A single node inside a quadtree used for keeping values and their position.
|
||||
/// </summary>
|
||||
private class QuadtreeNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the position of the value.
|
||||
/// </summary>
|
||||
public Vector2 Position
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value.
|
||||
/// </summary>
|
||||
public T Value
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:QuadtreeNode"/> class.
|
||||
/// </summary>
|
||||
/// <param name="position">
|
||||
/// The position of the value.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The value.
|
||||
/// </param>
|
||||
public QuadtreeNode(Vector2 position, T value)
|
||||
{
|
||||
this.Position = position;
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27077e1b87d083e42b61f8207d1ef0e6
|
||||
timeCreated: 1439366413
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,160 @@
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// A class to scale textures - works on ARGB32, RGB24 and Alpha8 textures that are marked readable
|
||||
/// Sourced from : http://wiki.unity3d.com/index.php/TextureScale
|
||||
/// </summary>
|
||||
public class ScaleTexture
|
||||
{
|
||||
public class ThreadData
|
||||
{
|
||||
public int start;
|
||||
public int end;
|
||||
public ThreadData(int s, int e)
|
||||
{
|
||||
start = s;
|
||||
end = e;
|
||||
}
|
||||
}
|
||||
|
||||
private static Color[] texColors;
|
||||
private static Color[] newColors;
|
||||
private static int w;
|
||||
private static float ratioX;
|
||||
private static float ratioY;
|
||||
private static int w2;
|
||||
private static int finishCount;
|
||||
private static Mutex mutex;
|
||||
|
||||
public static void Point(Texture2D tex, int newWidth, int newHeight)
|
||||
{
|
||||
ThreadedScale(tex, newWidth, newHeight, false);
|
||||
}
|
||||
|
||||
public static void Bilinear(Texture2D tex, int newWidth, int newHeight)
|
||||
{
|
||||
ThreadedScale(tex, newWidth, newHeight, true);
|
||||
}
|
||||
|
||||
private static void ThreadedScale(Texture2D tex, int newWidth, int newHeight, bool useBilinear)
|
||||
{
|
||||
texColors = tex.GetPixels();
|
||||
newColors = new Color[newWidth * newHeight];
|
||||
if (useBilinear)
|
||||
{
|
||||
ratioX = 1.0f / ((float)newWidth / (tex.width - 1));
|
||||
ratioY = 1.0f / ((float)newHeight / (tex.height - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
ratioX = ((float)tex.width) / newWidth;
|
||||
ratioY = ((float)tex.height) / newHeight;
|
||||
}
|
||||
w = tex.width;
|
||||
w2 = newWidth;
|
||||
var cores = Mathf.Min(SystemInfo.processorCount, newHeight);
|
||||
var slice = newHeight / cores;
|
||||
|
||||
finishCount = 0;
|
||||
if (mutex == null)
|
||||
{
|
||||
mutex = new Mutex(false);
|
||||
}
|
||||
if (cores > 1)
|
||||
{
|
||||
int i = 0;
|
||||
ThreadData threadData;
|
||||
for (i = 0; i < cores - 1; i++)
|
||||
{
|
||||
threadData = new ThreadData(slice * i, slice * (i + 1));
|
||||
ParameterizedThreadStart ts = useBilinear ? new ParameterizedThreadStart(BilinearScale) : new ParameterizedThreadStart(PointScale);
|
||||
Thread thread = new Thread(ts);
|
||||
thread.Start(threadData);
|
||||
}
|
||||
threadData = new ThreadData(slice * i, newHeight);
|
||||
if (useBilinear)
|
||||
{
|
||||
BilinearScale(threadData);
|
||||
}
|
||||
else
|
||||
{
|
||||
PointScale(threadData);
|
||||
}
|
||||
while (finishCount < cores)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadData threadData = new ThreadData(0, newHeight);
|
||||
if (useBilinear)
|
||||
{
|
||||
BilinearScale(threadData);
|
||||
}
|
||||
else
|
||||
{
|
||||
PointScale(threadData);
|
||||
}
|
||||
}
|
||||
|
||||
tex.Resize(newWidth, newHeight);
|
||||
tex.SetPixels(newColors);
|
||||
tex.Apply();
|
||||
}
|
||||
|
||||
public static void BilinearScale(System.Object obj)
|
||||
{
|
||||
ThreadData threadData = (ThreadData)obj;
|
||||
for (var y = threadData.start; y < threadData.end; y++)
|
||||
{
|
||||
int yFloor = (int)Mathf.Floor(y * ratioY);
|
||||
var y1 = yFloor * w;
|
||||
var y2 = (yFloor + 1) * w;
|
||||
var yw = y * w2;
|
||||
|
||||
for (var x = 0; x < w2; x++)
|
||||
{
|
||||
int xFloor = (int)Mathf.Floor(x * ratioX);
|
||||
var xLerp = x * ratioX - xFloor;
|
||||
newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor + 1], xLerp),
|
||||
ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor + 1], xLerp),
|
||||
y * ratioY - yFloor);
|
||||
}
|
||||
}
|
||||
|
||||
mutex.WaitOne();
|
||||
finishCount++;
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
public static void PointScale(System.Object obj)
|
||||
{
|
||||
ThreadData threadData = (ThreadData)obj;
|
||||
for (var y = threadData.start; y < threadData.end; y++)
|
||||
{
|
||||
var thisY = (int)(ratioY * y) * w;
|
||||
var yw = y * w2;
|
||||
for (var x = 0; x < w2; x++)
|
||||
{
|
||||
newColors[yw + x] = texColors[(int)(thisY + ratioX * x)];
|
||||
}
|
||||
}
|
||||
|
||||
mutex.WaitOne();
|
||||
finishCount++;
|
||||
mutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
private static Color ColorLerpUnclamped(Color c1, Color c2, float value)
|
||||
{
|
||||
return new Color(c1.r + (c2.r - c1.r) * value,
|
||||
c1.g + (c2.g - c1.g) * value,
|
||||
c1.b + (c2.b - c1.b) * value,
|
||||
c1.a + (c2.a - c1.a) * value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4ab85728042bdf4bb0a679a6cf6e648
|
||||
timeCreated: 1455748984
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.GlobalIllumination;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public class SimpleCameraLayerCulling : MonoBehaviour
|
||||
{
|
||||
[HideInInspector]
|
||||
public GaiaSceneCullingProfile m_profile;
|
||||
|
||||
public bool m_applyToGameCamera;
|
||||
public Light m_directionalLight;
|
||||
public bool m_applyToSceneCamera;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (m_profile == null)
|
||||
{
|
||||
GaiaSettings gaiaSettings = GaiaUtils.GetGaiaSettings();
|
||||
m_profile = ScriptableObject.CreateInstance<GaiaSceneCullingProfile>();
|
||||
m_profile.UpdateCulling(gaiaSettings);
|
||||
m_profile.UpdateShadow();
|
||||
}
|
||||
|
||||
ApplyToGameCamera();
|
||||
}
|
||||
|
||||
public void ApplyToGameCamera()
|
||||
{
|
||||
if (m_applyToGameCamera)
|
||||
{
|
||||
Camera cam = GetComponent<Camera>();
|
||||
if (cam != null)
|
||||
{
|
||||
cam.layerCullDistances = m_profile.m_layerDistances;
|
||||
}
|
||||
ApplyToDirectionalLight();
|
||||
}
|
||||
else
|
||||
{
|
||||
float[] layerCulls = new float[32];
|
||||
for (int i = 0; i < layerCulls.Length; i++)
|
||||
{
|
||||
layerCulls[i] = 0f;
|
||||
}
|
||||
Camera cam = GetComponent<Camera>();
|
||||
if (cam != null)
|
||||
{
|
||||
cam.layerCullDistances = layerCulls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyToDirectionalLight()
|
||||
{
|
||||
if (m_directionalLight == null)
|
||||
{
|
||||
GameObject lightGO = GameObject.Find("Directional Light");
|
||||
if (lightGO != null)
|
||||
{
|
||||
m_directionalLight = lightGO.GetComponent<Light>();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_directionalLight != null)
|
||||
{
|
||||
m_directionalLight.layerShadowCullDistances = m_profile.m_shadowLayerDistances;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetDirectionalLight()
|
||||
{
|
||||
if (!m_applyToGameCamera && !m_applyToSceneCamera)
|
||||
{
|
||||
if (m_directionalLight == null)
|
||||
{
|
||||
GameObject lightGO = GameObject.Find("Directional Light");
|
||||
if (lightGO != null)
|
||||
{
|
||||
m_directionalLight = lightGO.GetComponent<Light>();
|
||||
}
|
||||
|
||||
if (m_directionalLight != null)
|
||||
{
|
||||
|
||||
float[] layers = new float[32];
|
||||
for (int i = 0; i < layers.Length; i++)
|
||||
{
|
||||
layers[i] = 0f;
|
||||
}
|
||||
m_directionalLight.layerShadowCullDistances = layers;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2189c0bafe64f942beb09bd4969353b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,299 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is an implementation of the algorithm SimplexNoise.
|
||||
/// The implementation is based on the java implementation by Stefan Gustavson
|
||||
/// presented in "Simplex noise demystified". Due to the use of a permutation
|
||||
/// instead of random numbers the same input results always in the same output.
|
||||
/// It is used as a feeder noise source for the other noise types.
|
||||
/// </summary>
|
||||
|
||||
public class SimplexNoiseGenerator
|
||||
{
|
||||
public static byte[] perm = new byte[512] { 151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
|
||||
151,160,137,91,90,15,
|
||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 1D simplex noise
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <returns></returns>
|
||||
public static float Generate(float x)
|
||||
{
|
||||
int i0 = FastFloor(x);
|
||||
int i1 = i0 + 1;
|
||||
float x0 = x - i0;
|
||||
float x1 = x0 - 1.0f;
|
||||
|
||||
float n0, n1;
|
||||
|
||||
float t0 = 1.0f - x0 * x0;
|
||||
t0 *= t0;
|
||||
n0 = t0 * t0 * Grad(perm[i0 & 0xff], x0);
|
||||
|
||||
float t1 = 1.0f - x1 * x1;
|
||||
t1 *= t1;
|
||||
n1 = t1 * t1 * Grad(perm[i1 & 0xff], x1);
|
||||
// The maximum value of this noise is 8*(3/4)^4 = 2.53125
|
||||
// A factor of 0.395 scales to fit exactly within [-1,1]
|
||||
return 0.395f * (n0 + n1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2D simplex noise
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns></returns>
|
||||
public static float Generate(float x, float y)
|
||||
{
|
||||
const float F2 = 0.366025403f; // F2 = 0.5*(sqrt(3.0)-1.0)
|
||||
const float G2 = 0.211324865f; // G2 = (3.0-Math.sqrt(3.0))/6.0
|
||||
|
||||
float n0, n1, n2; // Noise contributions from the three corners
|
||||
|
||||
// Skew the input space to determine which simplex cell we're in
|
||||
float s = (x + y) * F2; // Hairy factor for 2D
|
||||
float xs = x + s;
|
||||
float ys = y + s;
|
||||
int i = FastFloor(xs);
|
||||
int j = FastFloor(ys);
|
||||
|
||||
float t = (float)(i + j) * G2;
|
||||
float X0 = i - t; // Unskew the cell origin back to (x,y) space
|
||||
float Y0 = j - t;
|
||||
float x0 = x - X0; // The x,y distances from the cell origin
|
||||
float y0 = y - Y0;
|
||||
|
||||
// For the 2D case, the simplex shape is an equilateral triangle.
|
||||
// Determine which simplex we are in.
|
||||
int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
|
||||
if (x0 > y0) { i1 = 1; j1 = 0; } // lower triangle, XY order: (0,0)->(1,0)->(1,1)
|
||||
else { i1 = 0; j1 = 1; } // upper triangle, YX order: (0,0)->(0,1)->(1,1)
|
||||
|
||||
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
|
||||
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
|
||||
// c = (3-sqrt(3))/6
|
||||
|
||||
float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
|
||||
float y1 = y0 - j1 + G2;
|
||||
float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords
|
||||
float y2 = y0 - 1.0f + 2.0f * G2;
|
||||
|
||||
// Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
|
||||
int ii = i % 256;
|
||||
int jj = j % 256;
|
||||
|
||||
// Calculate the contribution from the three corners
|
||||
float t0 = 0.5f - x0 * x0 - y0 * y0;
|
||||
if (t0 < 0.0f) n0 = 0.0f;
|
||||
else
|
||||
{
|
||||
t0 *= t0;
|
||||
n0 = t0 * t0 * Grad(perm[ii + perm[jj]], x0, y0);
|
||||
}
|
||||
|
||||
float t1 = 0.5f - x1 * x1 - y1 * y1;
|
||||
if (t1 < 0.0f) n1 = 0.0f;
|
||||
else
|
||||
{
|
||||
t1 *= t1;
|
||||
n1 = t1 * t1 * Grad(perm[ii + i1 + perm[jj + j1]], x1, y1);
|
||||
}
|
||||
|
||||
float t2 = 0.5f - x2 * x2 - y2 * y2;
|
||||
if (t2 < 0.0f) n2 = 0.0f;
|
||||
else
|
||||
{
|
||||
t2 *= t2;
|
||||
n2 = t2 * t2 * Grad(perm[ii + 1 + perm[jj + 1]], x2, y2);
|
||||
}
|
||||
|
||||
// Add contributions from each corner to get the final noise value.
|
||||
// The result is scaled to return values in the interval [-1,1].
|
||||
return 40.0f * (n0 + n1 + n2); // TODO: The scale factor is preliminary!
|
||||
}
|
||||
|
||||
|
||||
public static float Generate(float x, float y, float z)
|
||||
{
|
||||
// Simple skewing factors for the 3D case
|
||||
const float F3 = 0.333333333f;
|
||||
const float G3 = 0.166666667f;
|
||||
|
||||
float n0, n1, n2, n3; // Noise contributions from the four corners
|
||||
|
||||
// Skew the input space to determine which simplex cell we're in
|
||||
float s = (x + y + z) * F3; // Very nice and simple skew factor for 3D
|
||||
float xs = x + s;
|
||||
float ys = y + s;
|
||||
float zs = z + s;
|
||||
int i = FastFloor(xs);
|
||||
int j = FastFloor(ys);
|
||||
int k = FastFloor(zs);
|
||||
|
||||
float t = (float)(i + j + k) * G3;
|
||||
float X0 = i - t; // Unskew the cell origin back to (x,y,z) space
|
||||
float Y0 = j - t;
|
||||
float Z0 = k - t;
|
||||
float x0 = x - X0; // The x,y,z distances from the cell origin
|
||||
float y0 = y - Y0;
|
||||
float z0 = z - Z0;
|
||||
|
||||
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
|
||||
// Determine which simplex we are in.
|
||||
int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
|
||||
int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
|
||||
|
||||
/* This code would benefit from a backport from the GLSL version! */
|
||||
if (x0 >= y0)
|
||||
{
|
||||
if (y0 >= z0)
|
||||
{ i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // X Y Z order
|
||||
else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } // X Z Y order
|
||||
else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } // Z X Y order
|
||||
}
|
||||
else
|
||||
{ // x0<y0
|
||||
if (y0 < z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } // Z Y X order
|
||||
else if (x0 < z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } // Y Z X order
|
||||
else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // Y X Z order
|
||||
}
|
||||
|
||||
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
|
||||
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
|
||||
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
|
||||
// c = 1/6.
|
||||
|
||||
float x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
|
||||
float y1 = y0 - j1 + G3;
|
||||
float z1 = z0 - k1 + G3;
|
||||
float x2 = x0 - i2 + 2.0f * G3; // Offsets for third corner in (x,y,z) coords
|
||||
float y2 = y0 - j2 + 2.0f * G3;
|
||||
float z2 = z0 - k2 + 2.0f * G3;
|
||||
float x3 = x0 - 1.0f + 3.0f * G3; // Offsets for last corner in (x,y,z) coords
|
||||
float y3 = y0 - 1.0f + 3.0f * G3;
|
||||
float z3 = z0 - 1.0f + 3.0f * G3;
|
||||
|
||||
// Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
|
||||
int ii = Mod(i, 256);
|
||||
int jj = Mod(j, 256);
|
||||
int kk = Mod(k, 256);
|
||||
|
||||
// Calculate the contribution from the four corners
|
||||
float t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0;
|
||||
if (t0 < 0.0f) n0 = 0.0f;
|
||||
else
|
||||
{
|
||||
t0 *= t0;
|
||||
n0 = t0 * t0 * Grad(perm[ii + perm[jj + perm[kk]]], x0, y0, z0);
|
||||
}
|
||||
|
||||
float t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1;
|
||||
if (t1 < 0.0f) n1 = 0.0f;
|
||||
else
|
||||
{
|
||||
t1 *= t1;
|
||||
n1 = t1 * t1 * Grad(perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]], x1, y1, z1);
|
||||
}
|
||||
|
||||
float t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2;
|
||||
if (t2 < 0.0f) n2 = 0.0f;
|
||||
else
|
||||
{
|
||||
t2 *= t2;
|
||||
n2 = t2 * t2 * Grad(perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]], x2, y2, z2);
|
||||
}
|
||||
|
||||
float t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3;
|
||||
if (t3 < 0.0f) n3 = 0.0f;
|
||||
else
|
||||
{
|
||||
t3 *= t3;
|
||||
n3 = t3 * t3 * Grad(perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]], x3, y3, z3);
|
||||
}
|
||||
|
||||
// Add contributions from each corner to get the final noise value.
|
||||
// The result is scaled to stay just inside [-1,1]
|
||||
return 32.0f * (n0 + n1 + n2 + n3); // TODO: The scale factor is preliminary!
|
||||
}
|
||||
|
||||
private static int FastFloor(float x)
|
||||
{
|
||||
return (x > 0) ? ((int)x) : (((int)x) - 1);
|
||||
}
|
||||
|
||||
private static int Mod(int x, int m)
|
||||
{
|
||||
int a = x % m;
|
||||
return a < 0 ? a + m : a;
|
||||
}
|
||||
|
||||
private static float Grad(int hash, float x)
|
||||
{
|
||||
int h = hash & 15;
|
||||
float grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0
|
||||
if ((h & 8) != 0) grad = -grad; // Set a random sign for the gradient
|
||||
return (grad * x); // Multiply the gradient with the distance
|
||||
}
|
||||
|
||||
private static float Grad(int hash, float x, float y)
|
||||
{
|
||||
int h = hash & 7; // Convert low 3 bits of hash code
|
||||
float u = h < 4 ? x : y; // into 8 simple gradient directions,
|
||||
float v = h < 4 ? y : x; // and compute the dot product with (x,y).
|
||||
return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -2.0f * v : 2.0f * v);
|
||||
}
|
||||
|
||||
private static float Grad(int hash, float x, float y, float z)
|
||||
{
|
||||
int h = hash & 15; // Convert low 4 bits of hash code into 12 simple
|
||||
float u = h < 8 ? x : y; // gradient directions, and compute dot product.
|
||||
float v = h < 4 ? y : h == 12 || h == 14 ? x : z; // Fix repeats at h = 12 to 15
|
||||
return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v);
|
||||
}
|
||||
|
||||
private static float Grad(int hash, float x, float y, float z, float t)
|
||||
{
|
||||
int h = hash & 31; // Convert low 5 bits of hash code into 32 simple
|
||||
float u = h < 24 ? x : y; // gradient directions, and compute dot product.
|
||||
float v = h < 16 ? y : z;
|
||||
float w = h < 8 ? z : t;
|
||||
return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v) + ((h & 4) != 0 ? -w : w);
|
||||
}
|
||||
|
||||
public static float GetNormalisedValue(float x, float y)
|
||||
{
|
||||
return Mathf.Clamp((Generate(x, y) + 1f) / 2f, 0f, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 574460a5bcd566347bb1844f74d19300
|
||||
timeCreated: 1449267572
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,94 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Be aware this will not prevent a non singleton constructor such as `T myT = new T();`
|
||||
/// To prevent that, add `protected T () {}` to your singleton class.
|
||||
///
|
||||
/// As a note, this is made as MonoBehaviour because we need Coroutines.
|
||||
/// Sourced from http://wiki.unity3d.com/index.php/Singleton
|
||||
///
|
||||
/// public class Manager : Singleton<Manager>
|
||||
/// {
|
||||
/// protected Manager() { } // guarantee this will be always a singleton only - can't use the constructor!
|
||||
/// public string myGlobalVar = "whatever";
|
||||
/// }
|
||||
/// public class MyClass : MonoBehaviour {
|
||||
/// void Awake () {
|
||||
/// Debug.Log(Manager.Instance.myGlobalVar);
|
||||
/// }
|
||||
/// }
|
||||
/// </summary>
|
||||
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
|
||||
{
|
||||
private static T _instance;
|
||||
|
||||
private static object _lock = new object();
|
||||
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (applicationIsQuitting)
|
||||
{
|
||||
Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
|
||||
"' already destroyed on application quit." +
|
||||
" Won't create again - returning null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = (T)FindObjectOfType(typeof(T));
|
||||
|
||||
if (FindObjectsOfType(typeof(T)).Length > 1)
|
||||
{
|
||||
Debug.LogError("[Singleton] Something went really wrong " +
|
||||
" - there should never be more than 1 singleton!" +
|
||||
" Reopenning the scene might fix it.");
|
||||
return _instance;
|
||||
}
|
||||
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject singleton = new GameObject();
|
||||
_instance = singleton.AddComponent<T>();
|
||||
singleton.name = "(singleton) " + typeof(T).ToString();
|
||||
|
||||
DontDestroyOnLoad(singleton);
|
||||
|
||||
Debug.Log("[Singleton] An instance of " + typeof(T) +
|
||||
" is needed in the scene, so '" + singleton +
|
||||
"' was created with DontDestroyOnLoad.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[Singleton] Using instance already created: " +
|
||||
_instance.gameObject.name);
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool applicationIsQuitting = false;
|
||||
/// <summary>
|
||||
/// When Unity quits, it destroys objects in a random order.
|
||||
/// In principle, a Singleton is only destroyed when application quits.
|
||||
/// If any script calls Instance after it have been destroyed,
|
||||
/// it will create a buggy ghost object that will stay on the Editor scene
|
||||
/// even after stopping playing the Application. Really bad!
|
||||
/// So, this was made to be sure we're not creating that buggy ghost object.
|
||||
/// </summary>
|
||||
public void OnDestroy()
|
||||
{
|
||||
applicationIsQuitting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea2bc9865e296ae4cb582fd21f53267b
|
||||
timeCreated: 1433625748
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public static class SpawnProgressBar
|
||||
{
|
||||
static string m_title;
|
||||
static string m_subTitle;
|
||||
static float m_totalProgress;
|
||||
static float m_currentSpawnRuleProgress;
|
||||
static int m_totalSpawnRulesCompleted;
|
||||
static int m_totalSpawnRuleCount;
|
||||
static int m_spawnerRulesCompleted;
|
||||
static int m_spawnerRuleCount;
|
||||
|
||||
public static bool UpdateProgressBar(string spawnerName, int totalSpawnRuleCount, int totalSpawnRulesCompleted, int spawnerRuleCount, int spawnerRulesCompleted)
|
||||
{
|
||||
//m_title = string.Format("Spawning: {0} of {1} Rules Total", totalSpawnRulesCompleted.ToString(), m_totalSpawnRuleCount.ToString());
|
||||
m_title = "Spawning";
|
||||
m_subTitle = string.Format(spawnerName + " {0} of {1} Rules", spawnerRulesCompleted.ToString(), spawnerRuleCount.ToString());
|
||||
m_totalSpawnRulesCompleted = totalSpawnRulesCompleted;
|
||||
m_totalSpawnRuleCount = totalSpawnRuleCount;
|
||||
m_spawnerRulesCompleted = spawnerRulesCompleted;
|
||||
m_spawnerRuleCount = spawnerRuleCount;
|
||||
m_currentSpawnRuleProgress = 0;
|
||||
|
||||
return ProgressBar.Show(ProgressBarPriority.Spawning, m_title, m_subTitle, m_totalSpawnRulesCompleted, m_totalSpawnRuleCount,true,true);
|
||||
}
|
||||
|
||||
public static bool UpdateSpawnRuleProgress(float progress)
|
||||
{
|
||||
m_currentSpawnRuleProgress = progress;
|
||||
#if UNITY_EDITOR
|
||||
return ProgressBar.Show(ProgressBarPriority.Spawning, m_title, m_subTitle, m_totalSpawnRulesCompleted, m_totalSpawnRuleCount, true, true);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void ClearProgressBar()
|
||||
{
|
||||
ProgressBar.Clear(ProgressBarPriority.Spawning);
|
||||
}
|
||||
|
||||
private static float CalculateProgress()
|
||||
{
|
||||
return Mathf.InverseLerp(0, m_totalSpawnRuleCount, (float)m_totalSpawnRulesCompleted + m_currentSpawnRuleProgress);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a59ac7cb6d5bac449868c3b747ddca9c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,160 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class TerrainDetailOverwrite : MonoBehaviour
|
||||
{
|
||||
#region Public Variables
|
||||
|
||||
public GaiaConstants.TerrainDetailQuality m_detailQuality { get; set; }
|
||||
public int m_detailDistance { get; set; }
|
||||
public float m_detailDensity { get; set; }
|
||||
public Terrain m_terrain { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Variables
|
||||
|
||||
private bool m_applyTerrainChanges = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Startup
|
||||
|
||||
/// <summary>
|
||||
/// Apply on enable
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
if (m_terrain == null)
|
||||
{
|
||||
m_terrain = gameObject.GetComponent<Terrain>();
|
||||
}
|
||||
|
||||
m_detailDistance = (int)m_terrain.detailObjectDistance;
|
||||
m_detailDensity = m_terrain.detailObjectDensity;
|
||||
|
||||
GetResolutionPatches();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Updates
|
||||
|
||||
/// <summary>
|
||||
/// Applies detail distance settings if global then it'll apply to all instances
|
||||
/// </summary>
|
||||
/// <param name="isGlobal"></param>
|
||||
public void ApplySettings(bool isGlobal)
|
||||
{
|
||||
if (isGlobal)
|
||||
{
|
||||
TerrainDetailOverwrite[] detailOverwrites = FindObjectsOfType<TerrainDetailOverwrite>();
|
||||
List<Terrain> terains = new List<Terrain>();
|
||||
if (detailOverwrites.Length > 0)
|
||||
{
|
||||
foreach (TerrainDetailOverwrite detailOverwrite in detailOverwrites)
|
||||
{
|
||||
detailOverwrite.m_detailDistance = m_detailDistance;
|
||||
detailOverwrite.m_detailDensity = m_detailDensity;
|
||||
terains.Add(detailOverwrite.GetComponent<Terrain>());
|
||||
}
|
||||
|
||||
foreach (Terrain terrain in terains)
|
||||
{
|
||||
if (terrain.detailObjectDistance != m_detailDistance)
|
||||
{
|
||||
m_applyTerrainChanges = true;
|
||||
terrain.detailObjectDistance = m_detailDistance;
|
||||
}
|
||||
|
||||
if (terrain.detailObjectDensity != m_detailDensity)
|
||||
{
|
||||
m_applyTerrainChanges = true;
|
||||
terrain.detailObjectDensity = m_detailDensity;
|
||||
}
|
||||
|
||||
if (m_applyTerrainChanges)
|
||||
{
|
||||
terrain.Flush();
|
||||
m_applyTerrainChanges = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_terrain == null)
|
||||
{
|
||||
m_terrain = gameObject.GetComponent<Terrain>();
|
||||
}
|
||||
|
||||
if (m_terrain != null)
|
||||
{
|
||||
if (m_terrain.detailObjectDistance != m_detailDistance)
|
||||
{
|
||||
m_applyTerrainChanges = true;
|
||||
m_terrain.detailObjectDistance = m_detailDistance;
|
||||
}
|
||||
|
||||
if (m_terrain.detailObjectDensity != m_detailDensity)
|
||||
{
|
||||
m_applyTerrainChanges = true;
|
||||
m_terrain.detailObjectDensity = m_detailDensity;
|
||||
}
|
||||
|
||||
if (m_applyTerrainChanges)
|
||||
{
|
||||
m_terrain.Flush();
|
||||
m_applyTerrainChanges = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the detail patch resolution
|
||||
/// </summary>
|
||||
public void GetResolutionPatches()
|
||||
{
|
||||
if (m_terrain == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_terrain.terrainData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_terrain.terrainData.detailResolutionPerPatch == 2)
|
||||
{
|
||||
m_detailQuality = GaiaConstants.TerrainDetailQuality.Ultra2;
|
||||
}
|
||||
else if (m_terrain.terrainData.detailResolutionPerPatch == 4)
|
||||
{
|
||||
m_detailQuality = GaiaConstants.TerrainDetailQuality.VeryHigh4;
|
||||
}
|
||||
else if (m_terrain.terrainData.detailResolutionPerPatch == 8)
|
||||
{
|
||||
m_detailQuality = GaiaConstants.TerrainDetailQuality.High8;
|
||||
}
|
||||
else if (m_terrain.terrainData.detailResolutionPerPatch == 16)
|
||||
{
|
||||
m_detailQuality = GaiaConstants.TerrainDetailQuality.Medium16;
|
||||
}
|
||||
else if (m_terrain.terrainData.detailResolutionPerPatch == 32)
|
||||
{
|
||||
m_detailQuality = GaiaConstants.TerrainDetailQuality.Low32;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_detailQuality = GaiaConstants.TerrainDetailQuality.VeryLow64;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 966db0f861b7d6f49a523cc0c4089382
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,882 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using static Gaia.GaiaConstants;
|
||||
using System.Security.AccessControl;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// Terrain utility functions
|
||||
/// </summary>
|
||||
public class TerrainHelper : MonoBehaviour
|
||||
{
|
||||
[Range(1, 5), Tooltip("Number of smoothing interations to run. Can be run multiple times.")]
|
||||
public int m_smoothIterations = 1;
|
||||
|
||||
|
||||
|
||||
//Knock ourselves out if we happen to be left there in play mode
|
||||
void Awake()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flatten all the active terrains
|
||||
/// </summary>
|
||||
public static void Flatten()
|
||||
{
|
||||
FlattenTerrain(Terrain.activeTerrains);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flatten the terrain passed in
|
||||
/// </summary>
|
||||
/// <param name="terrain">Terrain to be flattened</param>
|
||||
public static void FlattenTerrain(Terrain terrain)
|
||||
{
|
||||
float[,] heights = new float[terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution];
|
||||
terrain.terrainData.SetHeights(0, 0, heights);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flatten all the terrains passed in
|
||||
/// </summary>
|
||||
/// <param name="terrains">Terrains to be flattened</param>
|
||||
public static void FlattenTerrain(Terrain[] terrains)
|
||||
{
|
||||
foreach (Terrain terrain in terrains)
|
||||
{
|
||||
float[,] heights = new float[terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution];
|
||||
terrain.terrainData.SetHeights(0, 0, heights);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stitch the terrains together with unity set neighbors calls
|
||||
/// </summary>
|
||||
public static void Stitch()
|
||||
{
|
||||
StitchTerrains(Terrain.activeTerrains);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stitch the terrains together - wont align them although should update this to support that as well.
|
||||
/// </summary>
|
||||
/// <param name="terrains">Array of terrains to organise as neighbors</param>
|
||||
public static void StitchTerrains(Terrain[] terrains)
|
||||
{
|
||||
Terrain right = null;
|
||||
Terrain left = null;
|
||||
Terrain bottom = null;
|
||||
Terrain top = null;
|
||||
|
||||
foreach (Terrain terrain in terrains)
|
||||
{
|
||||
right = null;
|
||||
left = null;
|
||||
bottom = null;
|
||||
top = null;
|
||||
|
||||
foreach (Terrain neighbor in terrains)
|
||||
{
|
||||
//Check to see if neighbor is above or below
|
||||
if (neighbor.transform.position.x == terrain.transform.position.x)
|
||||
{
|
||||
if ((neighbor.transform.position.z + neighbor.terrainData.size.z) == terrain.transform.position.z)
|
||||
{
|
||||
top = neighbor;
|
||||
}
|
||||
else if ((terrain.transform.position.z + terrain.terrainData.size.z) == neighbor.transform.position.z)
|
||||
{
|
||||
bottom = neighbor;
|
||||
}
|
||||
}
|
||||
else if (neighbor.transform.position.z == terrain.transform.position.z)
|
||||
{
|
||||
if ((neighbor.transform.position.x + neighbor.terrainData.size.z) == terrain.transform.position.z)
|
||||
{
|
||||
left = neighbor;
|
||||
}
|
||||
else if ((terrain.transform.position.x + terrain.terrainData.size.x) == neighbor.transform.position.x)
|
||||
{
|
||||
right = neighbor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
terrain.SetNeighbors(left, top, right, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smooth the active terrain - needs to be extended to all and to handle edges
|
||||
/// </summary>
|
||||
/// <param name="iterations">Number of smoothing iterations</param>
|
||||
public void Smooth()
|
||||
{
|
||||
Smooth(m_smoothIterations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smooth the active terrain - needs to be extended to all and to handle edges
|
||||
/// </summary>
|
||||
/// <param name="iterations">Number of smoothing iterations</param>
|
||||
public static void Smooth(int iterations)
|
||||
{
|
||||
UnityHeightMap hm = new UnityHeightMap(Terrain.activeTerrain);
|
||||
hm.Smooth(iterations);
|
||||
hm.SaveToTerrain(Terrain.activeTerrain);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the vector of the centre of the active terrain, and flush to ground level if asked to
|
||||
/// </summary>
|
||||
/// <param name="flushToGround">If true set it flush to the ground</param>
|
||||
/// <returns>Vector3.zero if no terrain, otherwise the centre of it</returns>
|
||||
public static Vector3 GetActiveTerrainCenter(bool flushToGround = true)
|
||||
{
|
||||
Bounds b = new Bounds();
|
||||
Terrain t = GetActiveTerrain();
|
||||
if (GetTerrainBounds(t, ref b))
|
||||
{
|
||||
if (flushToGround == true)
|
||||
{
|
||||
return new Vector3(b.center.x, t.SampleHeight(b.center), b.center.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
return b.center;
|
||||
}
|
||||
}
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the world map terrain from the scene
|
||||
/// </summary>
|
||||
/// <returns>The world map terrain</returns>
|
||||
public static Terrain GetWorldMapTerrain()
|
||||
{
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
if (TerrainHelper.IsWorldMapTerrain(t))
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
//still no world map terrain? might be a deactivated GameObject, check those as well
|
||||
GameObject worldMapGO = GaiaUtils.FindObjectDeactivated(GaiaConstants.worldMapTerrainPrefix + "_", false);
|
||||
if (worldMapGO != null)
|
||||
{
|
||||
Terrain t = worldMapGO.GetComponent<Terrain>();
|
||||
if (t != null)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get any active terrain - pref active terrain
|
||||
/// </summary>
|
||||
/// <returns>Any active terrain or null</returns>
|
||||
public static Terrain GetActiveTerrain()
|
||||
{
|
||||
//Grab active terrain if we can
|
||||
Terrain terrain = Terrain.activeTerrain;
|
||||
if (terrain != null && terrain.isActiveAndEnabled)
|
||||
{
|
||||
return terrain;
|
||||
}
|
||||
|
||||
//Then check rest of terrains
|
||||
for (int idx = 0; idx < Terrain.activeTerrains.Length; idx++)
|
||||
{
|
||||
terrain = Terrain.activeTerrains[idx];
|
||||
if (terrain != null && terrain.isActiveAndEnabled)
|
||||
{
|
||||
return terrain;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the layer mask of the active terrain, or default if there isnt one
|
||||
/// </summary>
|
||||
/// <returns>Layermask of activer terrain or default if there isnt one</returns>
|
||||
public static LayerMask GetActiveTerrainLayer()
|
||||
{
|
||||
LayerMask layer = new LayerMask();
|
||||
Terrain terrain = GetActiveTerrain();
|
||||
if (terrain != null)
|
||||
{
|
||||
layer.value = 1 << terrain.gameObject.layer;
|
||||
return layer;
|
||||
}
|
||||
layer.value = 1 << LayerMask.NameToLayer("Default");
|
||||
return layer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the layer mask of the active terrain, or default if there isnt one
|
||||
/// </summary>
|
||||
/// <returns>Layermask of activer terrain or default if there isnt one</returns>
|
||||
public static LayerMask GetActiveTerrainLayerAsInt()
|
||||
{
|
||||
LayerMask layerValue = GetActiveTerrainLayer().value;
|
||||
for (int layerIdx = 0; layerIdx < 32; layerIdx++)
|
||||
{
|
||||
if (layerValue == (1 << layerIdx))
|
||||
{
|
||||
return layerIdx;
|
||||
}
|
||||
}
|
||||
return LayerMask.NameToLayer("Default");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of active terrain tiles in this scene
|
||||
/// </summary>
|
||||
/// <returns>Number of terrains in the scene</returns>
|
||||
public static int GetActiveTerrainCount()
|
||||
{
|
||||
if (GaiaUtils.HasDynamicLoadedTerrains())
|
||||
{
|
||||
//with terrain loading, we can simply count the loaded scenes, those should be the active terrains
|
||||
return TerrainLoaderManager.TerrainScenes.Where(x => x.m_regularLoadState == LoadState.Loaded).Count() + TerrainLoaderManager.TerrainScenes.Where(x => x.m_impostorLoadState == LoadState.Loaded).Count();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//For non-terrain loading we need to take a look at what we can find in the scene
|
||||
//Regular terrains
|
||||
Terrain terrain;
|
||||
int terrainCount = 0;
|
||||
for (int idx = 0; idx < Terrain.activeTerrains.Length; idx++)
|
||||
{
|
||||
terrain = Terrain.activeTerrains[idx];
|
||||
if (terrain != null && terrain.isActiveAndEnabled)
|
||||
{
|
||||
terrainCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//Mesh Terrains from a terrain export
|
||||
GameObject exportContainer = GaiaUtils.GetTerrainExportObject(false);
|
||||
if (exportContainer != null)
|
||||
{
|
||||
//Iterate through the objects in here, if it is active and the name checks out we can assume it is a mesh terrain.
|
||||
foreach (Transform t in exportContainer.transform)
|
||||
{
|
||||
if (t.gameObject.GetComponent<MeshRenderer>() != null)
|
||||
{
|
||||
if (t.gameObject.activeInHierarchy && (t.name.StartsWith(GaiaConstants.MeshTerrainName) || t.name.StartsWith(GaiaConstants.MeshTerrainLODGroupPrefix)))
|
||||
{
|
||||
terrainCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return terrainCount;
|
||||
}
|
||||
}
|
||||
#if GAIA_PRO_PRESENT
|
||||
/// <summary>
|
||||
/// Get the terrain scene that matches this location, otherwise return null
|
||||
/// </summary>
|
||||
/// <param name="locationWU">Location to check in world units</param>
|
||||
/// <returns>Terrain here or null</returns>
|
||||
public static TerrainScene GetDynamicLoadedTerrain(Vector3 locationWU, GaiaSessionManager gsm = null)
|
||||
{
|
||||
if (gsm == null)
|
||||
{
|
||||
gsm = GaiaSessionManager.GetSessionManager(false);
|
||||
}
|
||||
|
||||
foreach (TerrainScene terrainScene in TerrainLoaderManager.TerrainScenes)
|
||||
{
|
||||
if (terrainScene.m_bounds.min.x <= locationWU.x && terrainScene.m_bounds.min.z <= locationWU.z && terrainScene.m_bounds.max.x >= locationWU.x && terrainScene.m_bounds.max.z >= locationWU.z)
|
||||
{
|
||||
return terrainScene;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Returns the Quaternion rotation from the active terrain normal
|
||||
/// </summary>
|
||||
/// <param name="terrain"></param>
|
||||
/// <param name="playerObj"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector3 GetRotationFromTerrainNormal(Terrain terrain, GameObject playerObj)
|
||||
{
|
||||
if (terrain != null && playerObj != null)
|
||||
{
|
||||
float scalarX = (playerObj.transform.position.x - terrain.transform.position.x) / (float)terrain.terrainData.size.x;
|
||||
float scalarZ = (playerObj.transform.position.z - terrain.transform.position.z) / (float)terrain.terrainData.size.z;
|
||||
Vector3 interpolatedNormal = terrain.terrainData.GetInterpolatedNormal(scalarX, scalarZ);
|
||||
Quaternion quaternion = Quaternion.FromToRotation(Vector3.up, interpolatedNormal) * playerObj.transform.rotation;
|
||||
return quaternion.eulerAngles;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Vector3.zero;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Get the terrain that matches this location, otherwise return null
|
||||
/// </summary>
|
||||
/// <param name="locationWU">Location to check in world units</param>
|
||||
/// <returns>Terrain here or null</returns>
|
||||
public static Terrain GetTerrain(Vector3 locationWU, bool selectWorldMapTerrains = false)
|
||||
{
|
||||
Terrain terrain;
|
||||
Vector3 terrainMin = new Vector3();
|
||||
Vector3 terrainMax = new Vector3();
|
||||
|
||||
//First check active terrain - most likely already selected
|
||||
terrain = Terrain.activeTerrain;
|
||||
if (terrain != null && terrain.terrainData !=null &&(selectWorldMapTerrains == TerrainHelper.IsWorldMapTerrain(terrain)))
|
||||
{
|
||||
terrainMin = terrain.GetPosition();
|
||||
terrainMax = terrainMin + terrain.terrainData.size;
|
||||
if (locationWU.x >= terrainMin.x && locationWU.x <= terrainMax.x)
|
||||
{
|
||||
if (locationWU.z >= terrainMin.z && locationWU.z <= terrainMax.z)
|
||||
{
|
||||
return terrain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Then check rest of terrains
|
||||
Terrain closestTerrain = null;
|
||||
float closestDistance = float.MaxValue;
|
||||
for (int idx = 0; idx < Terrain.activeTerrains.Length; idx++)
|
||||
{
|
||||
terrain = Terrain.activeTerrains[idx];
|
||||
if (terrain.terrainData==null || (selectWorldMapTerrains != TerrainHelper.IsWorldMapTerrain(terrain)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
terrainMin = terrain.GetPosition();
|
||||
terrainMax = terrainMin + terrain.terrainData.size;
|
||||
|
||||
if (locationWU.x >= terrainMin.x && locationWU.x <= terrainMax.x)
|
||||
{
|
||||
if (locationWU.z >= terrainMin.z && locationWU.z <= terrainMax.z)
|
||||
{
|
||||
return terrain;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestTerrain == null || Vector3.Distance(terrain.transform.position, locationWU) < closestDistance)
|
||||
{
|
||||
closestTerrain = terrain;
|
||||
}
|
||||
}
|
||||
return closestTerrain;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the bounds of the space encapsulated by the supplied terrain
|
||||
/// </summary>
|
||||
/// <param name="terrain">Terrain to get bounds for</param>
|
||||
/// <param name="bounds">Bounds to update</param>
|
||||
/// <returns>True if we got some terrain bounds</returns>
|
||||
public static bool GetTerrainBounds(Terrain terrain, ref Bounds bounds)
|
||||
{
|
||||
if (terrain == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bounds.center = terrain.transform.position;
|
||||
bounds.size = terrain.terrainData.size;
|
||||
bounds.center += bounds.extents;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the bounds of the terrain at this location or fail with a null
|
||||
/// </summary>
|
||||
/// <param name="locationWU">Location to check and get terrain for</param>
|
||||
/// <returns>Bounds of selected terrain or null if invalid for some reason</returns>
|
||||
public static bool GetTerrainBounds(ref BoundsDouble bounds, bool activeTerrainsOnly = false)
|
||||
{
|
||||
//Terrain terrain = GetTerrain(locationWU);
|
||||
//if (terrain == null)
|
||||
//{
|
||||
// return false;
|
||||
//}
|
||||
//bounds.center = terrain.transform.position;
|
||||
//bounds.size = terrain.terrainData.size;
|
||||
//bounds.center += bounds.extents;
|
||||
|
||||
Vector3Double accumulatedCenter = new Vector3Double();
|
||||
|
||||
//Do we use dynamic loaded terrains in the scene?
|
||||
if (GaiaUtils.HasDynamicLoadedTerrains() && !activeTerrainsOnly)
|
||||
{
|
||||
#if GAIA_PRO_PRESENT
|
||||
//we do have dynamic terrains -> calculate the bounds according to the terrain scene data in the session
|
||||
GaiaSessionManager gsm = GaiaSessionManager.GetSessionManager(false);
|
||||
|
||||
foreach (TerrainScene t in TerrainLoaderManager.TerrainScenes)
|
||||
{
|
||||
accumulatedCenter += t.m_bounds.center;
|
||||
}
|
||||
|
||||
bounds.center = accumulatedCenter / TerrainLoaderManager.TerrainScenes.Count;
|
||||
|
||||
foreach (TerrainScene t in TerrainLoaderManager.TerrainScenes)
|
||||
{
|
||||
bounds.Encapsulate(t.m_bounds);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//no placeholder -> calculate bounds according to the active terrains in the scene
|
||||
if (Terrain.activeTerrains.Length > 0)
|
||||
{
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
if (!TerrainHelper.IsWorldMapTerrain(t))
|
||||
{
|
||||
if (t.terrainData != null)
|
||||
{
|
||||
accumulatedCenter += new Vector3Double(t.transform.position) + new Vector3Double(t.terrainData.bounds.extents);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Terrain " + t.name + " in the scene is missing the terrain data object!");
|
||||
}
|
||||
}
|
||||
}
|
||||
bounds.center = accumulatedCenter / Terrain.activeTerrains.Length;
|
||||
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
if (!TerrainHelper.IsWorldMapTerrain(t))
|
||||
{
|
||||
if (t.terrainData != null)
|
||||
{
|
||||
Bounds newBounds = new Bounds();
|
||||
newBounds.center = t.transform.position;
|
||||
newBounds.size = t.terrainData.size;
|
||||
newBounds.center += t.terrainData.bounds.extents;
|
||||
bounds.Encapsulate(newBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bounds = new BoundsDouble(Vector3Double.zero, Vector3Double.zero);
|
||||
//No active terrains? There might be mesh terrains we can use then
|
||||
GameObject meshTerrainExportObject = GaiaUtils.GetTerrainExportObject(false);
|
||||
if (meshTerrainExportObject != null)
|
||||
{
|
||||
foreach (Transform t in meshTerrainExportObject.transform)
|
||||
{
|
||||
MeshRenderer mr = t.GetComponent<MeshRenderer>();
|
||||
if (mr != null)
|
||||
{
|
||||
bounds.Encapsulate(mr.bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a random location on the terrain supplied
|
||||
/// </summary>
|
||||
/// <param name="terrain">Terrain to check</param>
|
||||
/// <param name="start">Start locaton</param>
|
||||
/// <param name="radius">Radius to hunt in</param>
|
||||
/// <returns></returns>
|
||||
public static Vector3 GetRandomPositionOnTerrain(Terrain terrain, Vector3 start, float radius)
|
||||
{
|
||||
Vector3 newLocation;
|
||||
Vector3 terrainMin = terrain.GetPosition();
|
||||
Vector3 terrainMax = terrainMin + terrain.terrainData.size;
|
||||
while (true)
|
||||
{
|
||||
//Get a new location
|
||||
newLocation = UnityEngine.Random.insideUnitSphere * radius;
|
||||
newLocation = start + newLocation;
|
||||
//Make sure the new location is within the terrain bounds
|
||||
if (newLocation.x >= terrainMin.x && newLocation.x <= terrainMax.x)
|
||||
{
|
||||
if (newLocation.z >= terrainMin.z && newLocation.z <= terrainMax.z)
|
||||
{
|
||||
//Update it to be on the terrain surface
|
||||
newLocation.y = terrain.SampleHeight(newLocation);
|
||||
return newLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the bounds of a terrain in world space (The bounds in the terrainData object is in local space of the terrain itself)
|
||||
/// </summary>
|
||||
/// <param name="t">The terrain to get the bounds in world space for.</param>
|
||||
/// <returns></returns>
|
||||
public static Bounds GetWorldSpaceBounds(Terrain t)
|
||||
{
|
||||
Bounds worldSpaceBounds = t.terrainData.bounds;
|
||||
worldSpaceBounds.center = new Vector3(worldSpaceBounds.center.x + t.transform.position.x, worldSpaceBounds.center.y + t.transform.position.y, worldSpaceBounds.center.z + t.transform.position.z);
|
||||
return worldSpaceBounds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all the trees on all the terrains
|
||||
/// </summary>
|
||||
public static void ClearSpawns(SpawnerResourceType resourceType, ClearSpawnFor clearSpawnFor, ClearSpawnFrom clearSpawnFrom, List<string> terrainNames = null, Spawner spawner = null)
|
||||
{
|
||||
if (terrainNames == null)
|
||||
{
|
||||
if (clearSpawnFor == ClearSpawnFor.AllTerrains)
|
||||
{
|
||||
if (GaiaUtils.HasDynamicLoadedTerrains())
|
||||
{
|
||||
GaiaSessionManager sessionManager = GaiaSessionManager.GetSessionManager();
|
||||
terrainNames = TerrainLoaderManager.TerrainScenes.Select(x => x.GetTerrainName()).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
terrainNames = Terrain.activeTerrains.Select(x => x.name).ToList();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
terrainNames = new List<string> { spawner.GetCurrentTerrain().name };
|
||||
}
|
||||
}
|
||||
|
||||
string progressBarTitle = "Clearing...";
|
||||
|
||||
Action<Terrain> act = null;
|
||||
switch (resourceType)
|
||||
{
|
||||
case SpawnerResourceType.TerrainTexture:
|
||||
progressBarTitle = "Clearing Textures";
|
||||
//Not supported, should not be required
|
||||
throw new NotSupportedException("Clearing of Textures is currently not supported via the terrain helper");
|
||||
case SpawnerResourceType.TerrainDetail:
|
||||
progressBarTitle = "Clearing Terrain Details";
|
||||
act = (t) => ClearDetailsOnSingleTerrain(t, spawner, clearSpawnFrom);
|
||||
break;
|
||||
case SpawnerResourceType.TerrainTree:
|
||||
progressBarTitle = "Clearing Trees";
|
||||
act = (t) => ClearTreesOnSingleTerrain(t, spawner, clearSpawnFrom);
|
||||
break;
|
||||
case SpawnerResourceType.GameObject:
|
||||
progressBarTitle = "Clearing Game Objects";
|
||||
act = (t) => ClearGameObjectsOnSingleTerrain(t, spawner, clearSpawnFrom);
|
||||
break;
|
||||
case SpawnerResourceType.Probe:
|
||||
progressBarTitle = "Clearing Probes";
|
||||
act = (t) => ClearGameObjectsOnSingleTerrain(t, spawner, clearSpawnFrom);
|
||||
break;
|
||||
case SpawnerResourceType.SpawnExtension:
|
||||
progressBarTitle = "Clearing Spawn Extensions";
|
||||
act = (t) => ClearSpawnExtensionsOnSingleTerrain(t, spawner, clearSpawnFrom);
|
||||
break;
|
||||
case SpawnerResourceType.StampDistribution:
|
||||
//Not supported, should not be required
|
||||
throw new NotSupportedException("Clearing of Stamps is currently not supported via the terrain helper");
|
||||
}
|
||||
|
||||
if (GaiaUtils.HasDynamicLoadedTerrains())
|
||||
{
|
||||
GaiaUtils.CallFunctionOnDynamicLoadedTerrains(act, true, terrainNames);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int idx = 0; idx < terrainNames.Count; idx++)
|
||||
{
|
||||
ProgressBar.Show(ProgressBarPriority.Spawning ,progressBarTitle, progressBarTitle, idx + 1, terrainNames.Count(), true);
|
||||
|
||||
GameObject go = GameObject.Find(terrainNames[idx]);
|
||||
if (go != null)
|
||||
{
|
||||
Terrain terrain = go.GetComponent<Terrain>();
|
||||
act(terrain);
|
||||
}
|
||||
ProgressBar.Clear(ProgressBarPriority.Spawning);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ClearTreesOnSingleTerrain(Terrain terrain, Spawner spawner, ClearSpawnFrom clearSpawnFrom)
|
||||
{
|
||||
if (spawner == null || clearSpawnFrom == ClearSpawnFrom.AnySource)
|
||||
{
|
||||
//No tree prototypes passed in => we delete any tree from any source
|
||||
terrain.terrainData.treeInstances = new TreeInstance[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
//We need to get the correct prototype Ids for this terrain only
|
||||
//Prototype Ids might be different from terrain to terrain, depending on when / how the prototype was added
|
||||
List<int> treePrototypeIds = new List<int>();
|
||||
foreach (SpawnRule sr in spawner.m_settings.m_spawnerRules)
|
||||
{
|
||||
if (sr.m_resourceType == GaiaConstants.SpawnerResourceType.TerrainTree)
|
||||
{
|
||||
int treePrototypeIndex = spawner.m_settings.m_resources.PrototypeIdxInTerrain(sr.m_resourceType, sr.m_resourceIdx, terrain);
|
||||
if (treePrototypeIndex != -1)
|
||||
{
|
||||
treePrototypeIds.Add(treePrototypeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
//Reapply the tree instances on this terrain, but leave all "to be deleted" ids out via the where clause
|
||||
terrain.terrainData.SetTreeInstances(terrain.terrainData.treeInstances.Where(x => !treePrototypeIds.Contains(x.prototypeIndex)).ToArray(), true);
|
||||
|
||||
}
|
||||
terrain.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all the details (grass) on all the terrains
|
||||
/// </summary>
|
||||
private static void ClearDetailsOnSingleTerrain(Terrain terrain, Spawner spawner, ClearSpawnFrom clearSpawnFrom)
|
||||
{
|
||||
int[,] details = new int[terrain.terrainData.detailWidth, terrain.terrainData.detailHeight];
|
||||
|
||||
if (spawner == null || clearSpawnFrom == ClearSpawnFrom.AnySource)
|
||||
{
|
||||
|
||||
for (int dtlIdx = 0; dtlIdx < terrain.terrainData.detailPrototypes.Length; dtlIdx++)
|
||||
{
|
||||
terrain.terrainData.SetDetailLayer(0, 0, dtlIdx, details);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//We need to get the correct prototype Ids for this terrain only
|
||||
//Prototype Ids might be different from terrain to terrain, depending on when / how the prototype was added
|
||||
List<int> detailPrototypeIds = new List<int>();
|
||||
foreach (SpawnRule sr in spawner.m_settings.m_spawnerRules)
|
||||
{
|
||||
if (sr.m_resourceType == GaiaConstants.SpawnerResourceType.TerrainDetail)
|
||||
{
|
||||
int detailPrototypeIndex = spawner.m_settings.m_resources.PrototypeIdxInTerrain(sr.m_resourceType, sr.m_resourceIdx, terrain);
|
||||
if (detailPrototypeIndex != -1)
|
||||
{
|
||||
detailPrototypeIds.Add(detailPrototypeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int dtlIdx = 0; dtlIdx < detailPrototypeIds.Count; dtlIdx++)
|
||||
{
|
||||
terrain.terrainData.SetDetailLayer(0, 0, detailPrototypeIds[dtlIdx], details);
|
||||
}
|
||||
}
|
||||
terrain.Flush();
|
||||
}
|
||||
|
||||
|
||||
private static void ClearGameObjectsOnSingleTerrain(Terrain terrain, Spawner spawner, ClearSpawnFrom clearSpawnFrom)
|
||||
{
|
||||
Spawner[] allAffectedSpawners;
|
||||
|
||||
if (clearSpawnFrom == ClearSpawnFrom.OnlyThisSpawner)
|
||||
{
|
||||
allAffectedSpawners = new Spawner[1] { spawner };
|
||||
}
|
||||
else
|
||||
{
|
||||
allAffectedSpawners = Resources.FindObjectsOfTypeAll<Spawner>();
|
||||
}
|
||||
|
||||
foreach (Spawner sp in allAffectedSpawners)
|
||||
{
|
||||
foreach (SpawnRule sr in sp.m_settings.m_spawnerRules.Where(x=>x.m_resourceType == SpawnerResourceType.GameObject || x.m_resourceType == SpawnerResourceType.SpawnExtension || x.m_resourceType == SpawnerResourceType.Probe))
|
||||
Spawner.ClearGameObjectsForRule(sp, sr, false, terrain);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ClearSpawnExtensionsOnSingleTerrain(Terrain terrain, Spawner spawner, ClearSpawnFrom clearSpawnFrom)
|
||||
{
|
||||
Spawner[] allAffectedSpawners;
|
||||
|
||||
if (clearSpawnFrom == ClearSpawnFrom.OnlyThisSpawner)
|
||||
{
|
||||
allAffectedSpawners = new Spawner[1] { spawner };
|
||||
}
|
||||
else
|
||||
{
|
||||
allAffectedSpawners = Resources.FindObjectsOfTypeAll<Spawner>();
|
||||
}
|
||||
|
||||
foreach (Spawner sp in allAffectedSpawners)
|
||||
{
|
||||
foreach (SpawnRule sr in sp.m_settings.m_spawnerRules)
|
||||
{
|
||||
sp.ClearSpawnExtensionsForRule(sr);
|
||||
Spawner.ClearGameObjectsForRule(sp, sr, false, terrain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the range from the terrain
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static float GetRangeFromTerrain()
|
||||
{
|
||||
Terrain t = Gaia.TerrainHelper.GetActiveTerrain();
|
||||
if (t != null)
|
||||
{
|
||||
return Mathf.Max(t.terrainData.size.x, t.terrainData.size.z) / 2f;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this terrain is a world map terrain.
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsWorldMapTerrain(Terrain t)
|
||||
{
|
||||
return t.name.StartsWith(GaiaConstants.worldMapTerrainPrefix);
|
||||
}
|
||||
|
||||
public static bool IsWorldMapTerrain(TerrainData td)
|
||||
{
|
||||
return td.name.StartsWith(GaiaConstants.worldMapTerrainPrefix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns terrain names of terrains that intersect with the given bounds object
|
||||
/// </summary>
|
||||
/// <param name="bounds">A bounds object to check against the terrains. Needs to be in absolute world space position, mind the current origin offset!</param>
|
||||
/// <returns></returns>
|
||||
public static string[] GetTerrainsIntersectingBounds(BoundsDouble bounds)
|
||||
{
|
||||
//Reduce the bounds size a bit to prevent selecting terrains that are perfectly aligned with the bounds border
|
||||
//-this leads to too many terrains being logged as affected by an operation otherwise.
|
||||
Bounds intersectingBounds = new BoundsDouble();
|
||||
intersectingBounds.center = bounds.center;
|
||||
intersectingBounds.size = bounds.size - new Vector3Double(0.001f, 0.001f, 0.001f);
|
||||
|
||||
if (GaiaUtils.HasDynamicLoadedTerrains())
|
||||
{
|
||||
GaiaSessionManager sessionManager = GaiaSessionManager.GetSessionManager();
|
||||
if (sessionManager == null)
|
||||
{
|
||||
Debug.LogError("Trying to get terrains that intersect with bounds, but there is no session manager in scene.");
|
||||
return null;
|
||||
}
|
||||
return TerrainLoaderManager.TerrainScenes.Where(x => x.m_bounds.Intersects(intersectingBounds)).Select(x => x.GetTerrainName()).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
List<string> affectedTerrainNames = new List<string>();
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
if (intersectingBounds.Intersects(TerrainHelper.GetWorldSpaceBounds(t)))
|
||||
{
|
||||
affectedTerrainNames.Add(t.name);
|
||||
}
|
||||
}
|
||||
return affectedTerrainNames.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static TerrainLayer GetLayerFromPrototype(ResourceProtoTexture proto)
|
||||
{
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
foreach (TerrainLayer layer in t.terrainData.terrainLayers)
|
||||
{
|
||||
if (proto != null && layer != null)
|
||||
{
|
||||
if (proto.m_texture != null && layer.diffuseTexture != null)
|
||||
{
|
||||
if (PWCommon4.Utils.IsSameTexture(proto.m_texture, layer.diffuseTexture, false) == true)
|
||||
{
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int GetTreePrototypeIDFromSpawnRule(SpawnRule sr, Terrain terrain)
|
||||
{
|
||||
Spawner spawner = CollisionMask.m_allTreeSpawners.FirstOrDefault(x => x.m_settings.m_spawnerRules.Contains(sr));
|
||||
if (spawner != null)
|
||||
{
|
||||
GameObject treePrefabInRule = spawner.m_settings.m_resources.m_treePrototypes[sr.m_resourceIdx].m_desktopPrefab;
|
||||
for (int i = 0; i < terrain.terrainData.treePrototypes.Length; i++)
|
||||
{
|
||||
TreePrototype tp = terrain.terrainData.treePrototypes[i];
|
||||
if (tp.prefab == treePrefabInRule)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static Vector3 GetWorldCenter(bool sampleHeight = false)
|
||||
{
|
||||
BoundsDouble bounds = new BoundsDouble();
|
||||
GetTerrainBounds(ref bounds);
|
||||
|
||||
if (sampleHeight)
|
||||
{
|
||||
Terrain t = GetTerrain(bounds.center);
|
||||
if (t != null)
|
||||
{
|
||||
Vector3 centerOnTerrain = t.transform.position + new Vector3(t.terrainData.size.x / 2f, 0f, t.terrainData.size.z / 2f);
|
||||
float height = t.SampleHeight(centerOnTerrain);
|
||||
return new Vector3(centerOnTerrain.x, height, centerOnTerrain.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
//No terrain? The user might be using mesh terrains then. Send out a raycast at the center to determine height
|
||||
RaycastHit raycastHit = new RaycastHit();
|
||||
if (Physics.Raycast(new Vector3Double(bounds.center.x, 1000000f, bounds.center.z), Vector3.down, out raycastHit))
|
||||
{
|
||||
return raycastHit.point;
|
||||
}
|
||||
else
|
||||
{
|
||||
return bounds.center;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Vector3((float)bounds.center.x, (float)bounds.center.y, (float)bounds.center.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65b4f5f18fae3634bb0c3fb3587134b1
|
||||
timeCreated: 1431461511
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
|
||||
public class TimedInstance : System.Diagnostics.Stopwatch
|
||||
{
|
||||
//Timer frequency - will depend on systems its on
|
||||
public long nanosecPerTick = (1000L*1000L*1000L) / Frequency;
|
||||
|
||||
//Name of the instance
|
||||
public string m_name;
|
||||
|
||||
//Number of iterations
|
||||
public int m_iterations = 0;
|
||||
|
||||
public TimedInstance(string name, bool start = true)
|
||||
: base()
|
||||
{
|
||||
m_name = name;
|
||||
if (start)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
new public void Start()
|
||||
{
|
||||
m_iterations++;
|
||||
base.Start();
|
||||
}
|
||||
|
||||
new public void Reset()
|
||||
{
|
||||
m_iterations = 0;
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
public void IncIterations()
|
||||
{
|
||||
m_iterations++;
|
||||
}
|
||||
|
||||
public float GetAvgMs()
|
||||
{
|
||||
return ((float)ElapsedMilliseconds / (float)m_iterations);
|
||||
}
|
||||
|
||||
public float GetAvgS()
|
||||
{
|
||||
return (((float)ElapsedMilliseconds / (float)m_iterations)) / 1000f;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
// the overall frame time and frames per second:
|
||||
return string.Format("{0}: Avg: {1:0.000}s Last: {1:0.000}s", m_name, GetAvgMs() / 1000f, ElapsedMilliseconds / 1000f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 382616d819c3f134f946e0351c2dfc7a
|
||||
timeCreated: 1431938377
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,348 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// Unity integration extension to the heightmap class
|
||||
/// </summary>
|
||||
public class UnityHeightMap : HeightMap
|
||||
{
|
||||
public Bounds m_boundsWU = new Bounds();
|
||||
|
||||
/// <summary>
|
||||
/// Create a unity heightmap
|
||||
/// </summary>
|
||||
public UnityHeightMap() : base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a unity heightmap by loading from a source file
|
||||
/// </summary>
|
||||
/// <param name="path">Paht of file to load</param>
|
||||
public UnityHeightMap(string path) : base(path)
|
||||
{
|
||||
m_boundsWU.size = new Vector3(m_widthX, 0f, m_depthZ);
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a unity heightmap by loading a TextAsset
|
||||
/// </summary>
|
||||
/// <param name="source">The text asset to be loaded</param>
|
||||
public UnityHeightMap(TextAsset source) : base(source.bytes)
|
||||
{
|
||||
m_boundsWU.size = new Vector3(m_widthX, 0f, m_depthZ);
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a unity heightmap by replicating a source file
|
||||
/// </summary>
|
||||
/// <param name="source">Source heightmap</param>
|
||||
public UnityHeightMap(UnityHeightMap source) : base(source)
|
||||
{
|
||||
m_boundsWU = source.m_boundsWU;
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create from terrain
|
||||
/// </summary>
|
||||
/// <param name="terrain"></param>
|
||||
public UnityHeightMap(Terrain terrain) : base()
|
||||
{
|
||||
LoadFromTerrain(terrain);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a heightmap by reading in and processing an image file
|
||||
/// </summary>
|
||||
/// <param name="bounds">Bounds in world units</param>
|
||||
/// <param name="sourceFile">Source file</param>
|
||||
/// <param name="width">Width</param>
|
||||
/// <param name="depth">Depth</param>
|
||||
public UnityHeightMap(Bounds bounds, string sourceFile) : base(sourceFile)
|
||||
{
|
||||
m_boundsWU = bounds;
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Gaia.UnityHeightMap"/> class from a texture.
|
||||
/// </summary>
|
||||
/// <param name="texture">Texture.</param>
|
||||
public UnityHeightMap(Texture2D texture, GaiaConstants.ImageChannel channel = GaiaConstants.ImageChannel.R) : base()
|
||||
{
|
||||
LoadFromTexture2D(texture, channel);
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get bounds in world units
|
||||
/// </summary>
|
||||
/// <returns>Terrain bounds in world units</returns>
|
||||
public Bounds GetBoundsWU()
|
||||
{
|
||||
return m_boundsWU;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get position in world units
|
||||
/// </summary>
|
||||
/// <returns>Position in world units</returns>
|
||||
public Vector3 GetPositionWU()
|
||||
{
|
||||
Vector3 pos = m_boundsWU.center - m_boundsWU.extents;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the bounds in world units
|
||||
/// </summary>
|
||||
/// <param name="bounds"></param>
|
||||
public void SetBoundsWU(Bounds bounds)
|
||||
{
|
||||
m_boundsWU = bounds;
|
||||
m_isDirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the position in world units
|
||||
/// </summary>
|
||||
/// <param name="position"></param>
|
||||
public void SetPositionWU(Vector3 position)
|
||||
{
|
||||
m_boundsWU.center = position;
|
||||
m_isDirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load this height map from the supplied terrain
|
||||
/// </summary>
|
||||
/// <param name="terrain">Terrain to load</param>
|
||||
public void LoadFromTerrain(Terrain terrain)
|
||||
{
|
||||
Reset();
|
||||
m_boundsWU.center = terrain.transform.position;
|
||||
m_boundsWU.size = terrain.terrainData.size;
|
||||
m_boundsWU.center += m_boundsWU.extents;
|
||||
m_widthX = terrain.terrainData.heightmapResolution;
|
||||
m_depthZ = terrain.terrainData.heightmapResolution;
|
||||
m_widthInvX = 1f / (float)(m_widthX);
|
||||
m_depthInvZ = 1f / (float)(m_depthZ);
|
||||
m_heights = terrain.terrainData.GetHeights(0, 0, m_widthX, m_depthZ);
|
||||
m_isPowerOf2 = Gaia.GaiaUtils.Math_IsPowerOf2(m_widthX) && Gaia.GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the supplied terrain with the content of this heightmap - will scale if necessary
|
||||
/// </summary>
|
||||
/// <param name="terrain">Terrain to uppdate</param>
|
||||
public void SaveToTerrain(Terrain terrain)
|
||||
{
|
||||
if (terrain == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Get terrain stats
|
||||
int terWidth = terrain.terrainData.heightmapResolution;
|
||||
int terDepth = terrain.terrainData.heightmapResolution;
|
||||
|
||||
//Direct one to one mapping
|
||||
if (m_widthX == terWidth && m_depthZ == terDepth)
|
||||
{
|
||||
terrain.terrainData.SetHeights(0, 0, m_heights);
|
||||
m_isDirty = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//Build new array and scale it to the size of the terrain
|
||||
float[,] heights = new float[terWidth, terDepth];
|
||||
for (int x = 0; x < terWidth; x++)
|
||||
{
|
||||
for (int z = 0; z < terDepth; z++)
|
||||
{
|
||||
heights[x,z] = this[((float)x / (float)terWidth), ((float)z / (float)terDepth)];
|
||||
}
|
||||
}
|
||||
|
||||
//And apply it
|
||||
terrain.terrainData.SetHeights(0, 0, heights);
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
public void LoadFromTexture2D(Texture2D texture, GaiaConstants.ImageChannel channel)
|
||||
{
|
||||
//Check if it is readable - if not then make it readable
|
||||
Gaia.GaiaUtils.MakeTextureReadable(texture);
|
||||
|
||||
//Make sure its not compressed
|
||||
Gaia.GaiaUtils.MakeTextureUncompressed(texture);
|
||||
|
||||
//And load
|
||||
m_widthX = texture.width;
|
||||
m_depthZ = texture.height;
|
||||
m_widthInvX = 1f / (float)(m_widthX);
|
||||
m_depthInvZ = 1f / (float)(m_depthZ);
|
||||
m_heights = new float[m_widthX, m_depthZ];
|
||||
m_isPowerOf2 = Gaia.GaiaUtils.Math_IsPowerOf2(m_widthX) && Gaia.GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
||||
|
||||
if (channel == GaiaConstants.ImageChannel.R)
|
||||
{
|
||||
for (int x = 0; x < m_widthX; x++)
|
||||
{
|
||||
for (int z = 0; z < m_depthZ; z++)
|
||||
{
|
||||
m_heights[x, z] = texture.GetPixel(x, z).r;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (channel == GaiaConstants.ImageChannel.G)
|
||||
{
|
||||
for (int x = 0; x < m_widthX; x++)
|
||||
{
|
||||
for (int z = 0; z < m_depthZ; z++)
|
||||
{
|
||||
m_heights[x, z] = texture.GetPixel(x, z).g;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (channel == GaiaConstants.ImageChannel.B)
|
||||
{
|
||||
for (int x = 0; x < m_widthX; x++)
|
||||
{
|
||||
for (int z = 0; z < m_depthZ; z++)
|
||||
{
|
||||
m_heights[x, z] = texture.GetPixel(x, z).b;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = 0; x < m_widthX; x++)
|
||||
{
|
||||
for (int z = 0; z < m_depthZ; z++)
|
||||
{
|
||||
m_heights[x, z] = texture.GetPixel(x, z).a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read heightmap from the supplied RAW file supplied as a text asset
|
||||
/// </summary>
|
||||
/// <returns>True on success</returns>
|
||||
public void ReadRawFromTextAsset(TextAsset asset)
|
||||
{
|
||||
using (Stream s = new MemoryStream(asset.bytes))
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(s))
|
||||
{
|
||||
m_widthX = m_depthZ = Mathf.CeilToInt(Mathf.Sqrt(s.Length / 2));
|
||||
m_widthInvX = 1f / (float)(m_widthX);
|
||||
m_depthInvZ = 1f / (float)(m_depthZ);
|
||||
m_heights = new float[m_widthX, m_depthZ];
|
||||
m_isPowerOf2 = Gaia.GaiaUtils.Math_IsPowerOf2(m_widthX) && Gaia.GaiaUtils.Math_IsPowerOf2(m_depthZ);
|
||||
for (int hmX = 0; hmX < m_widthX; hmX++)
|
||||
{
|
||||
for (int hmZ = 0; hmZ < m_depthZ; hmZ++)
|
||||
{
|
||||
m_heights[hmX, hmZ] = (float)br.ReadUInt16() / 65535.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
s.Close();
|
||||
}
|
||||
m_isDirty = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a heightmap that only contains the single color channel info of the original map
|
||||
/// </summary>
|
||||
/// <param name="channel">The color channel to return</param>
|
||||
/// <returns></returns>
|
||||
public UnityHeightMap GetColorChannelHeightMap()
|
||||
{
|
||||
UnityHeightMap returnMap = new UnityHeightMap(this);
|
||||
for (int hmX = 0; hmX < m_widthX; hmX++)
|
||||
{
|
||||
for (int hmZ = 0; hmZ < m_depthZ; hmZ++)
|
||||
{
|
||||
returnMap.m_heights[hmX, hmZ] = this.m_heights[hmX, hmZ] / 3f;
|
||||
}
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the normals for the heightmap
|
||||
/// </summary>
|
||||
/// <returns>Normals for the heightmap</returns>
|
||||
public Texture2D CalculateNormals()
|
||||
{
|
||||
float terrainHeight = m_widthX / 2f;
|
||||
int width = m_widthX;
|
||||
int height = m_depthZ;
|
||||
|
||||
float ux = 1.0f / (width - 1.0f);
|
||||
float uy = 1.0f / (height - 1.0f);
|
||||
|
||||
float scaleX = terrainHeight / (float)m_widthX;
|
||||
float scaleY = terrainHeight / (float)m_depthZ;
|
||||
|
||||
float[] heights = Heights1D();
|
||||
|
||||
Texture2D normalMap = new Texture2D(width, height, TextureFormat.RGBAFloat, false, true);
|
||||
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int xp1 = (x == width - 1) ? x : x + 1;
|
||||
int xn1 = (x == 0) ? x : x - 1;
|
||||
|
||||
int yp1 = (y == height - 1) ? y : y + 1;
|
||||
int yn1 = (y == 0) ? y : y - 1;
|
||||
|
||||
float l = heights[xn1 + y * width] * scaleX;
|
||||
float r = heights[xp1 + y * width] * scaleX;
|
||||
|
||||
float b = heights[x + yn1 * width] * scaleY;
|
||||
float t = heights[x + yp1 * width] * scaleY;
|
||||
|
||||
float dx = (r - l) / (2.0f * ux);
|
||||
float dy = (t - b) / (2.0f * uy);
|
||||
|
||||
Vector3 normal;
|
||||
normal.x = -dx;
|
||||
normal.y = -dy;
|
||||
normal.z = 1;
|
||||
normal.Normalize();
|
||||
|
||||
Color pixel;
|
||||
pixel.r = normal.x * 0.5f + 0.5f;
|
||||
pixel.g = normal.y * 0.5f + 0.5f;
|
||||
pixel.b = normal.z;
|
||||
pixel.a = 1.0f;
|
||||
|
||||
normalMap.SetPixel(x, y, pixel);
|
||||
}
|
||||
|
||||
}
|
||||
normalMap.Apply();
|
||||
return normalMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bf722c900d572b47a99eac7b07783fc
|
||||
timeCreated: 1431471224
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,166 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Gaia.Pipeline
|
||||
{
|
||||
public enum GaiaPackageVersion { Unity2019_1, Unity2019_2, Unity2019_3, Unity2019_4, Unity2020_1, Unity2020_2, Unity2020_3, Unity2020_4, Unity2021_1, Unity2021_2, Unity2021_3, Unity2021_4, Unity2022_1, Unity2022_2, Unity2022_3, Unity2022_4, Unity2023_1 }
|
||||
|
||||
/// <summary>
|
||||
/// Mapping between Unity Version and Renderpipeline Asset Filename
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class UnityVersionPipelineAsset
|
||||
{
|
||||
public GaiaPackageVersion m_unityVersion;
|
||||
public string m_pipelineAssetName;
|
||||
public string m_minURPVersion = "5.7.2";
|
||||
public string m_maxURPVersion = "5.13.0";
|
||||
public string m_minHDRPVersion = "5.7.2";
|
||||
public string m_maxHDRPVersion = "5.13.0";
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class GaiaPackageSettings
|
||||
{
|
||||
[Header("Global Settings")]
|
||||
public string m_version = "Add Unity Version... Example: 2019.1, 2019.2";
|
||||
public bool m_isSupported = true;
|
||||
public GaiaPackageVersion m_unityVersion = GaiaPackageVersion.Unity2019_1;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Data structure to configure different Shader configurations for different rendering pipelines. Each entry is based on a shader in the built-in pipeline and
|
||||
/// its replacement shader in the URP and HDRP pipeline.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ShaderMappingEntry
|
||||
{
|
||||
//public string m_name;
|
||||
//public bool m_supportUnitypackages = false;
|
||||
public string m_builtInShaderName;
|
||||
//public string m_builtInMaterialUnitypackage;
|
||||
public string m_URPReplacementShaderName;
|
||||
//public string m_URPMaterialUnitypackage;
|
||||
public string m_HDRPReplacementShaderName;
|
||||
//public string m_HDRPMaterialUnitypackage;
|
||||
//[HideInInspector]
|
||||
//public bool m_floatChecksFoldedOut = false;
|
||||
//public List<ShaderFloatCheck> m_floatChecks = new List<ShaderFloatCheck>();
|
||||
//[HideInInspector]
|
||||
//public bool m_materialsFoldedOut = false;
|
||||
//public List<Material> m_materials;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data structure to configure keyword updates in a shader based on a float value in the material
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ShaderFloatCheck
|
||||
{
|
||||
public string m_floatValue;
|
||||
public string m_shaderKeyWord;
|
||||
}
|
||||
|
||||
public class UnityPipelineProfile : ScriptableObject
|
||||
{
|
||||
[Header("Global Settings")]
|
||||
public GaiaConstants.EnvironmentRenderer m_activePipelineInstalled = GaiaConstants.EnvironmentRenderer.BuiltIn;
|
||||
public GaiaSettings m_gaiaSettings;
|
||||
[HideInInspector]
|
||||
public bool m_editorUpdates = false;
|
||||
[HideInInspector]
|
||||
public bool m_pipelineSwitchUpdates = false;
|
||||
|
||||
[Header("Material Settings")]
|
||||
public Material m_underwaterHorizonMaterial;
|
||||
|
||||
[Header("Built-In Render Pipeline")]
|
||||
public string m_builtInHorizonObjectShader = "Standard";
|
||||
public Material m_builtInTerrainMaterial;
|
||||
public bool m_BuiltInAutoConfigureWater = true;
|
||||
|
||||
[Header("Universal Render Pipeline")]
|
||||
//public string m_universalPipelineProfile = "Procedural Worlds Universal Pipeline";
|
||||
public List<UnityVersionPipelineAsset> m_universalPipelineProfiles = new List<UnityVersionPipelineAsset>();
|
||||
public string m_universalScriptDefine = "UPPipeline";
|
||||
public string m_universalHorizonObjectShader = "Universal Render Pipeline/Lit";
|
||||
public Material m_universalTerrainMaterial;
|
||||
public bool m_setUPPipelineProfile = true;
|
||||
public bool m_UPAutoConfigureTerrain = true;
|
||||
public bool m_UPAutoConfigureWater = true;
|
||||
public bool m_UPAutoConfigureCamera = true;
|
||||
public bool m_UPAutoConfigureProbes = true;
|
||||
public bool m_UPAutoConfigureLighting = true;
|
||||
public bool m_UPAutoConfigureBiomePostFX = true;
|
||||
|
||||
//[Header("Lightweight Render Pipeline")]
|
||||
//public string m_lightweightPipelineProfile = "Procedural Worlds Lightweight Pipeline Profile";
|
||||
[HideInInspector]
|
||||
public List<UnityVersionPipelineAsset> m_lightweightPipelineProfiles = new List<UnityVersionPipelineAsset>();
|
||||
[HideInInspector]
|
||||
public string m_lightweightScriptDefine = "LWPipeline";
|
||||
[HideInInspector]
|
||||
public string m_lightweightHorizonObjectShader = "Lightweight Render Pipeline/Lit";
|
||||
[HideInInspector]
|
||||
public Material m_lightweightTerrainMaterial;
|
||||
[HideInInspector]
|
||||
public bool m_setLWPipelineProfile = true;
|
||||
[HideInInspector]
|
||||
public bool m_LWAutoConfigureTerrain = true;
|
||||
[HideInInspector]
|
||||
public bool m_LWAutoConfigureWater = true;
|
||||
[HideInInspector]
|
||||
public bool m_LWAutoConfigureCamera = true;
|
||||
[HideInInspector]
|
||||
public bool m_LWAutoConfigureProbes = true;
|
||||
[HideInInspector]
|
||||
public bool m_LWAutoConfigureLighting = true;
|
||||
|
||||
[Header("High Definition Render Pipeline")]
|
||||
//public string m_highDefinitionPipelineProfile = "Procedural Worlds HDRenderPipelineAsset";
|
||||
public List<UnityVersionPipelineAsset> m_highDefinitionPipelineProfiles = new List<UnityVersionPipelineAsset>();
|
||||
public string m_highDefinitionScriptDefine = "HDPipeline";
|
||||
public string m_highDefinitionHorizonObjectShader = "HDRP/Lit";
|
||||
public Material m_highDefinitionTerrainMaterial;
|
||||
public string m_HDVolumeObjectName = "HD Environment Volume";
|
||||
public string m_HDPostVolumeObjectName = "HD Post Processing Environment Volume";
|
||||
public string m_HDDefaultPostProcessing = "Default HDRP Post Processing Profile";
|
||||
public string m_HDDefaultSceneLighting = "Default Volume Profile";
|
||||
public string m_2019_3HDDefaultSceneLighting = "Default Volume Profile";
|
||||
public string m_HDSceneLighting = "HD Volume Profile";
|
||||
public string m_2019_3HDSceneLighting = "HD Volume Profile";
|
||||
public bool m_setHDPipelineProfile = true;
|
||||
public bool m_HDAutoConfigureTerrain = true;
|
||||
public bool m_HDAutoConfigureWater = true;
|
||||
public bool m_HDAutoConfigureCamera = true;
|
||||
public bool m_HDAutoConfigureProbes = true;
|
||||
public bool m_HDAutoConfigureLighting = true;
|
||||
public bool m_HDDisableTerrainDetails = true;
|
||||
public bool m_HDAutoConfigureBiomePostFX = true;
|
||||
|
||||
[Header("Package Settings")]
|
||||
//Material Library entries will be drawn from the editor script since they use extra buttons etc.
|
||||
[HideInInspector]
|
||||
public ShaderMappingEntry[] m_ShaderMappingLibrary = new ShaderMappingEntry[0];
|
||||
//public Material[] m_vegetationMaterialLibrary;
|
||||
//public Material[] m_waterMaterialLibrary;
|
||||
public GaiaPackageSettings[] m_packageSetupSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Create Gaia Lighting Profile asset
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[MenuItem("Assets/Create/Procedural Worlds/Gaia/Unity Pipeline Profile")]
|
||||
public static void CreateSkyProfiles()
|
||||
{
|
||||
UnityPipelineProfile asset = ScriptableObject.CreateInstance<UnityPipelineProfile>();
|
||||
AssetDatabase.CreateAsset(asset, "Assets/Unity Pipeline Profile.asset");
|
||||
AssetDatabase.SaveAssets();
|
||||
EditorUtility.FocusProjectWindow();
|
||||
Selection.activeObject = asset;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8adaa3bf704c76242af3ea9696646ba5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: dffcb73693a3ab445abdc7e1ad4b8bb3, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56ac9487819ec73439baa699c7c33c13
|
||||
timeCreated: 1540935180
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,302 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public struct Vector2Double
|
||||
{
|
||||
public const double kEpsilon = 1E-05d;
|
||||
public double x;
|
||||
public double y;
|
||||
|
||||
public double this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return this.x;
|
||||
case 1:
|
||||
return this.y;
|
||||
default:
|
||||
throw new IndexOutOfRangeException("Invalid Vector2d index!");
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
this.x = value;
|
||||
break;
|
||||
case 1:
|
||||
this.y = value;
|
||||
break;
|
||||
default:
|
||||
throw new IndexOutOfRangeException("Invalid Vector2d index!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2Double normalized
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector2Double vector2d = new Vector2Double(this.x, this.y);
|
||||
vector2d.Normalize();
|
||||
return vector2d;
|
||||
}
|
||||
}
|
||||
|
||||
public double magnitude
|
||||
{
|
||||
get
|
||||
{
|
||||
return Mathd.Sqrt(this.x * this.x + this.y * this.y);
|
||||
}
|
||||
}
|
||||
|
||||
public double sqrMagnitude
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.x * this.x + this.y * this.y;
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector2Double zero
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector2Double(0.0d, 0.0d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector2Double one
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector2Double(1d, 1d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector2Double up
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector2Double(0.0d, 1d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector2Double right
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector2Double(1d, 0.0d);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2Double(double x, double y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public static implicit operator Vector2Double(Vector3Double v)
|
||||
{
|
||||
return new Vector2Double(v.x, v.y);
|
||||
}
|
||||
|
||||
public static implicit operator Vector3Double(Vector2Double v)
|
||||
{
|
||||
return new Vector3Double(v.x, v.y, 0.0d);
|
||||
}
|
||||
|
||||
public static implicit operator Vector2Double(Vector2 v2)
|
||||
{
|
||||
return new Vector2Double((double)v2.x, (double)v2.y);
|
||||
}
|
||||
|
||||
|
||||
public static implicit operator Vector2(Vector2Double v2)
|
||||
{
|
||||
return new Vector2((float)v2.x, (float)v2.y);
|
||||
}
|
||||
|
||||
|
||||
public static Vector2Double operator +(Vector2Double a, Vector2Double b)
|
||||
{
|
||||
return new Vector2Double(a.x + b.x, a.y + b.y);
|
||||
}
|
||||
|
||||
public static Vector2Double operator -(Vector2Double a, Vector2Double b)
|
||||
{
|
||||
return new Vector2Double(a.x - b.x, a.y - b.y);
|
||||
}
|
||||
|
||||
public static Vector2Double operator -(Vector2Double a)
|
||||
{
|
||||
return new Vector2Double(-a.x, -a.y);
|
||||
}
|
||||
|
||||
public static Vector2Double operator *(Vector2Double a, double d)
|
||||
{
|
||||
return new Vector2Double(a.x * d, a.y * d);
|
||||
}
|
||||
|
||||
public static Vector2Double operator *(float d, Vector2Double a)
|
||||
{
|
||||
return new Vector2Double(a.x * d, a.y * d);
|
||||
}
|
||||
|
||||
public static Vector2Double operator /(Vector2Double a, double d)
|
||||
{
|
||||
return new Vector2Double(a.x / d, a.y / d);
|
||||
}
|
||||
|
||||
public static bool operator ==(Vector2Double lhs, Vector2Double rhs)
|
||||
{
|
||||
return Vector2Double.SqrMagnitude(lhs - rhs) < 0.0 / 1.0;
|
||||
}
|
||||
|
||||
public static bool operator !=(Vector2Double lhs, Vector2Double rhs)
|
||||
{
|
||||
return (double)Vector2Double.SqrMagnitude(lhs - rhs) >= 0.0 / 1.0;
|
||||
}
|
||||
|
||||
public void Set(double new_x, double new_y)
|
||||
{
|
||||
this.x = new_x;
|
||||
this.y = new_y;
|
||||
}
|
||||
|
||||
public static Vector2Double Lerp(Vector2Double from, Vector2Double to, double t)
|
||||
{
|
||||
t = Mathd.Clamp01(t);
|
||||
return new Vector2Double(from.x + (to.x - from.x) * t, from.y + (to.y - from.y) * t);
|
||||
}
|
||||
|
||||
public static Vector2Double MoveTowards(Vector2Double current, Vector2Double target, double maxDistanceDelta)
|
||||
{
|
||||
Vector2Double vector2 = target - current;
|
||||
double magnitude = vector2.magnitude;
|
||||
if (magnitude <= maxDistanceDelta || magnitude == 0.0d)
|
||||
return target;
|
||||
else
|
||||
return current + vector2 / magnitude * maxDistanceDelta;
|
||||
}
|
||||
|
||||
public static Vector2Double Scale(Vector2Double a, Vector2Double b)
|
||||
{
|
||||
return new Vector2Double(a.x * b.x, a.y * b.y);
|
||||
}
|
||||
|
||||
public void Scale(Vector2Double scale)
|
||||
{
|
||||
this.x *= scale.x;
|
||||
this.y *= scale.y;
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
double magnitude = this.magnitude;
|
||||
if (magnitude > 9.99999974737875E-06)
|
||||
this = this / magnitude;
|
||||
else
|
||||
this = Vector2Double.zero;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
/*
|
||||
string fmt = "({0:D1}, {1:D1})";
|
||||
object[] objArray = new object[2];
|
||||
int index1 = 0;
|
||||
// ISSUE: variable of a boxed type
|
||||
__Boxed<double> local1 = (ValueType) this.x;
|
||||
objArray[index1] = (object) local1;
|
||||
int index2 = 1;
|
||||
// ISSUE: variable of a boxed type
|
||||
__Boxed<double> local2 = (ValueType) this.y;
|
||||
objArray[index2] = (object) local2;
|
||||
*/
|
||||
return "not implemented";
|
||||
}
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
/* TODO:
|
||||
string fmt = "({0}, {1})";
|
||||
object[] objArray = new object[2];
|
||||
int index1 = 0;
|
||||
string str1 = this.x.ToString(format);
|
||||
objArray[index1] = (object) str1;
|
||||
int index2 = 1;
|
||||
string str2 = this.y.ToString(format);
|
||||
objArray[index2] = (object) str2;
|
||||
*/
|
||||
return "not implemented";
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.x.GetHashCode() ^ this.y.GetHashCode() << 2;
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (!(other is Vector2Double))
|
||||
return false;
|
||||
Vector2Double vector2d = (Vector2Double)other;
|
||||
if (this.x.Equals(vector2d.x))
|
||||
return this.y.Equals(vector2d.y);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static double Dot(Vector2Double lhs, Vector2Double rhs)
|
||||
{
|
||||
return lhs.x * rhs.x + lhs.y * rhs.y;
|
||||
}
|
||||
|
||||
public static double Angle(Vector2Double from, Vector2Double to)
|
||||
{
|
||||
return Mathd.Acos(Mathd.Clamp(Vector2Double.Dot(from.normalized, to.normalized), -1d, 1d)) * 57.29578d;
|
||||
}
|
||||
|
||||
public static double Distance(Vector2Double a, Vector2Double b)
|
||||
{
|
||||
return (a - b).magnitude;
|
||||
}
|
||||
|
||||
public static Vector2Double ClampMagnitude(Vector2Double vector, double maxLength)
|
||||
{
|
||||
if (vector.sqrMagnitude > maxLength * maxLength)
|
||||
return vector.normalized * maxLength;
|
||||
else
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static double SqrMagnitude(Vector2Double a)
|
||||
{
|
||||
return (a.x * a.x + a.y * a.y);
|
||||
}
|
||||
|
||||
public double SqrMagnitude()
|
||||
{
|
||||
return (this.x * this.x + this.y * this.y);
|
||||
}
|
||||
|
||||
public static Vector2Double Min(Vector2Double lhs, Vector2Double rhs)
|
||||
{
|
||||
return new Vector2Double(Mathd.Min(lhs.x, rhs.x), Mathd.Min(lhs.y, rhs.y));
|
||||
}
|
||||
|
||||
public static Vector2Double Max(Vector2Double lhs, Vector2Double rhs)
|
||||
{
|
||||
return new Vector2Double(Mathd.Max(lhs.x, rhs.x), Mathd.Max(lhs.y, rhs.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b53e6d9e5852bf643ab222994e4d049a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,451 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct Vector3Double
|
||||
{
|
||||
public const float kEpsilon = 1E-05f;
|
||||
public double x;
|
||||
public double y;
|
||||
public double z;
|
||||
|
||||
public double this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return this.x;
|
||||
case 1:
|
||||
return this.y;
|
||||
case 2:
|
||||
return this.z;
|
||||
default:
|
||||
throw new IndexOutOfRangeException("Invalid index!");
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
this.x = value;
|
||||
break;
|
||||
case 1:
|
||||
this.y = value;
|
||||
break;
|
||||
case 2:
|
||||
this.z = value;
|
||||
break;
|
||||
default:
|
||||
throw new IndexOutOfRangeException("Invalid Vector3Double index!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3Double normalized
|
||||
{
|
||||
get
|
||||
{
|
||||
return Vector3Double.Normalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public double magnitude
|
||||
{
|
||||
get
|
||||
{
|
||||
return Math.Sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||
}
|
||||
}
|
||||
|
||||
public double sqrMagnitude
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.x * this.x + this.y * this.y + this.z * this.z;
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Double zero
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(0d, 0d, 0d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Double one
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(1d, 1d, 1d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Double forward
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(0d, 0d, 1d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Double back
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(0d, 0d, -1d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Double up
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(0d, 1d, 0d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Double down
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(0d, -1d, 0d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Double left
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(-1d, 0d, 0d);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3Double right
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(1d, 0d, 0d);
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Use Vector3Double.forward instead.")]
|
||||
public static Vector3Double fwd
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Double(0d, 0d, 1d);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3Double(double x, double y, double z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vector3Double(float x, float y, float z)
|
||||
{
|
||||
this.x = (double)x;
|
||||
this.y = (double)y;
|
||||
this.z = (double)z;
|
||||
}
|
||||
|
||||
public Vector3Double(Vector3 v3)
|
||||
{
|
||||
this.x = (double)v3.x;
|
||||
this.y = (double)v3.y;
|
||||
this.z = (double)v3.z;
|
||||
}
|
||||
|
||||
public static implicit operator Vector3Double(Vector3 v3)
|
||||
{
|
||||
return new Vector3Double((double)v3.x, (double)v3.y, (double)v3.z);
|
||||
}
|
||||
|
||||
|
||||
public static implicit operator Vector3(Vector3Double v3)
|
||||
{
|
||||
return new Vector3((float)v3.x, (float)v3.y, (float)v3.z);
|
||||
}
|
||||
|
||||
public Vector3Double(double x, double y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = 0d;
|
||||
}
|
||||
|
||||
public static Vector3Double operator +(Vector3Double a, Vector3Double b)
|
||||
{
|
||||
return new Vector3Double(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
}
|
||||
|
||||
public static Vector3Double operator -(Vector3Double a, Vector3Double b)
|
||||
{
|
||||
return new Vector3Double(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
}
|
||||
|
||||
public static Vector3Double operator -(Vector3Double a)
|
||||
{
|
||||
return new Vector3Double(-a.x, -a.y, -a.z);
|
||||
}
|
||||
|
||||
public static Vector3Double operator *(Vector3Double a, double d)
|
||||
{
|
||||
return new Vector3Double(a.x * d, a.y * d, a.z * d);
|
||||
}
|
||||
|
||||
public static Vector3Double operator *(double d, Vector3Double a)
|
||||
{
|
||||
return new Vector3Double(a.x * d, a.y * d, a.z * d);
|
||||
}
|
||||
|
||||
public static Vector3Double operator /(Vector3Double a, double d)
|
||||
{
|
||||
return new Vector3Double(a.x / d, a.y / d, a.z / d);
|
||||
}
|
||||
|
||||
public static bool operator ==(Vector3Double lhs, Vector3Double rhs)
|
||||
{
|
||||
return (double)Vector3Double.SqrMagnitude(lhs - rhs) < 0.0 / 1.0;
|
||||
}
|
||||
|
||||
public static bool operator !=(Vector3Double lhs, Vector3Double rhs)
|
||||
{
|
||||
return (double)Vector3Double.SqrMagnitude(lhs - rhs) >= 0.0 / 1.0;
|
||||
}
|
||||
|
||||
//public static explicit operator Vector3(Vector3Double vector3d)
|
||||
//{
|
||||
// return new Vector3((float)vector3d.x, (float)vector3d.y, (float)vector3d.z);
|
||||
//}
|
||||
|
||||
public static Vector3Double Lerp(Vector3Double from, Vector3Double to, double t)
|
||||
{
|
||||
t = Mathd.Clamp01(t);
|
||||
return new Vector3Double(from.x + (to.x - from.x) * t, from.y + (to.y - from.y) * t, from.z + (to.z - from.z) * t);
|
||||
}
|
||||
|
||||
public static Vector3Double Slerp(Vector3Double from, Vector3Double to, double t)
|
||||
{
|
||||
Vector3 v3 = Vector3.Slerp((Vector3)from, (Vector3)to, (float)t);
|
||||
return new Vector3Double(v3);
|
||||
}
|
||||
|
||||
public static void OrthoNormalize(ref Vector3Double normal, ref Vector3Double tangent)
|
||||
{
|
||||
Vector3 v3normal = new Vector3();
|
||||
Vector3 v3tangent = new Vector3();
|
||||
v3normal = (Vector3)normal;
|
||||
v3tangent = (Vector3)tangent;
|
||||
Vector3.OrthoNormalize(ref v3normal, ref v3tangent);
|
||||
normal = new Vector3Double(v3normal);
|
||||
tangent = new Vector3Double(v3tangent);
|
||||
}
|
||||
|
||||
public static void OrthoNormalize(ref Vector3Double normal, ref Vector3Double tangent, ref Vector3Double binormal)
|
||||
{
|
||||
Vector3 v3normal = new Vector3();
|
||||
Vector3 v3tangent = new Vector3();
|
||||
Vector3 v3binormal = new Vector3();
|
||||
v3normal = (Vector3)normal;
|
||||
v3tangent = (Vector3)tangent;
|
||||
v3binormal = (Vector3)binormal;
|
||||
Vector3.OrthoNormalize(ref v3normal, ref v3tangent, ref v3binormal);
|
||||
normal = new Vector3Double(v3normal);
|
||||
tangent = new Vector3Double(v3tangent);
|
||||
binormal = new Vector3Double(v3binormal);
|
||||
}
|
||||
|
||||
public static Vector3Double MoveTowards(Vector3Double current, Vector3Double target, double maxDistanceDelta)
|
||||
{
|
||||
Vector3Double vector3 = target - current;
|
||||
double magnitude = vector3.magnitude;
|
||||
if (magnitude <= maxDistanceDelta || magnitude == 0.0d)
|
||||
return target;
|
||||
else
|
||||
return current + vector3 / magnitude * maxDistanceDelta;
|
||||
}
|
||||
|
||||
public static Vector3Double RotateTowards(Vector3Double current, Vector3Double target, double maxRadiansDelta, double maxMagnitudeDelta)
|
||||
{
|
||||
Vector3 v3 = Vector3.RotateTowards((Vector3)current, (Vector3)target, (float)maxRadiansDelta, (float)maxMagnitudeDelta);
|
||||
return new Vector3Double(v3);
|
||||
}
|
||||
|
||||
public static Vector3Double SmoothDamp(Vector3Double current, Vector3Double target, ref Vector3Double currentVelocity, double smoothTime, double maxSpeed)
|
||||
{
|
||||
double deltaTime = (double)Time.deltaTime;
|
||||
return Vector3Double.SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
|
||||
}
|
||||
|
||||
public static Vector3Double SmoothDamp(Vector3Double current, Vector3Double target, ref Vector3Double currentVelocity, double smoothTime)
|
||||
{
|
||||
double deltaTime = (double)Time.deltaTime;
|
||||
double maxSpeed = double.PositiveInfinity;
|
||||
return Vector3Double.SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
|
||||
}
|
||||
|
||||
public static Vector3Double SmoothDamp(Vector3Double current, Vector3Double target, ref Vector3Double currentVelocity, double smoothTime, double maxSpeed, double deltaTime)
|
||||
{
|
||||
smoothTime = Mathd.Max(0.0001d, smoothTime);
|
||||
double num1 = 2d / smoothTime;
|
||||
double num2 = num1 * deltaTime;
|
||||
double num3 = (1.0d / (1.0d + num2 + 0.479999989271164d * num2 * num2 + 0.234999999403954d * num2 * num2 * num2));
|
||||
Vector3Double vector = current - target;
|
||||
Vector3Double vector3_1 = target;
|
||||
double maxLength = maxSpeed * smoothTime;
|
||||
Vector3Double vector3_2 = Vector3Double.ClampMagnitude(vector, maxLength);
|
||||
target = current - vector3_2;
|
||||
Vector3Double vector3_3 = (currentVelocity + num1 * vector3_2) * deltaTime;
|
||||
currentVelocity = (currentVelocity - num1 * vector3_3) * num3;
|
||||
Vector3Double vector3_4 = target + (vector3_2 + vector3_3) * num3;
|
||||
if (Vector3Double.Dot(vector3_1 - current, vector3_4 - vector3_1) > 0.0)
|
||||
{
|
||||
vector3_4 = vector3_1;
|
||||
currentVelocity = (vector3_4 - vector3_1) / deltaTime;
|
||||
}
|
||||
return vector3_4;
|
||||
}
|
||||
|
||||
public void Set(double new_x, double new_y, double new_z)
|
||||
{
|
||||
this.x = new_x;
|
||||
this.y = new_y;
|
||||
this.z = new_z;
|
||||
}
|
||||
|
||||
public static Vector3Double Scale(Vector3Double a, Vector3Double b)
|
||||
{
|
||||
return new Vector3Double(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||
}
|
||||
|
||||
public void Scale(Vector3Double scale)
|
||||
{
|
||||
this.x *= scale.x;
|
||||
this.y *= scale.y;
|
||||
this.z *= scale.z;
|
||||
}
|
||||
|
||||
public static Vector3Double Cross(Vector3Double lhs, Vector3Double rhs)
|
||||
{
|
||||
return new Vector3Double(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.x.GetHashCode() ^ this.y.GetHashCode() << 2 ^ this.z.GetHashCode() >> 2;
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (!(other is Vector3Double))
|
||||
return false;
|
||||
Vector3Double vector3d = (Vector3Double)other;
|
||||
if (this.x.Equals(vector3d.x) && this.y.Equals(vector3d.y))
|
||||
return this.z.Equals(vector3d.z);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Vector3Double Reflect(Vector3Double inDirection, Vector3Double inNormal)
|
||||
{
|
||||
return -2d * Vector3Double.Dot(inNormal, inDirection) * inNormal + inDirection;
|
||||
}
|
||||
|
||||
public static Vector3Double Normalize(Vector3Double value)
|
||||
{
|
||||
double num = Vector3Double.Magnitude(value);
|
||||
if (num > 9.99999974737875E-06)
|
||||
return value / num;
|
||||
else
|
||||
return Vector3Double.zero;
|
||||
}
|
||||
|
||||
//public void Normalize()
|
||||
//{
|
||||
// double num = Vector3Double.Magnitude(this);
|
||||
// if (num > 9.99999974737875E-06)
|
||||
// this = this / num;
|
||||
// else
|
||||
// this = Vector3Double.zero;
|
||||
//}
|
||||
// TODO : fix formatting
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + this.x + " - " + this.y + " - " + this.z + ")";
|
||||
}
|
||||
|
||||
public static double Dot(Vector3Double lhs, Vector3Double rhs)
|
||||
{
|
||||
return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
|
||||
}
|
||||
|
||||
public static Vector3Double Project(Vector3Double vector, Vector3Double onNormal)
|
||||
{
|
||||
double num = Vector3Double.Dot(onNormal, onNormal);
|
||||
if (num < 1.40129846432482E-45d)
|
||||
return Vector3Double.zero;
|
||||
else
|
||||
return onNormal * Vector3Double.Dot(vector, onNormal) / num;
|
||||
}
|
||||
|
||||
public static Vector3Double Exclude(Vector3Double excludeThis, Vector3Double fromThat)
|
||||
{
|
||||
return fromThat - Vector3Double.Project(fromThat, excludeThis);
|
||||
}
|
||||
|
||||
public static double Angle(Vector3Double from, Vector3Double to)
|
||||
{
|
||||
return Mathd.Acos(Mathd.Clamp(Vector3Double.Dot(from.normalized, to.normalized), -1d, 1d)) * 57.29578d;
|
||||
}
|
||||
|
||||
public static double Distance(Vector3Double a, Vector3Double b)
|
||||
{
|
||||
Vector3Double vector3d = new Vector3Double(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
return Math.Sqrt(vector3d.x * vector3d.x + vector3d.y * vector3d.y + vector3d.z * vector3d.z);
|
||||
}
|
||||
|
||||
public static Vector3Double ClampMagnitude(Vector3Double vector, double maxLength)
|
||||
{
|
||||
if (vector.sqrMagnitude > maxLength * maxLength)
|
||||
return vector.normalized * maxLength;
|
||||
else
|
||||
return vector;
|
||||
}
|
||||
|
||||
public static double Magnitude(Vector3Double a)
|
||||
{
|
||||
return Math.Sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
|
||||
}
|
||||
|
||||
public static double SqrMagnitude(Vector3Double a)
|
||||
{
|
||||
return a.x * a.x + a.y * a.y + a.z * a.z;
|
||||
}
|
||||
|
||||
public static Vector3Double Min(Vector3Double lhs, Vector3Double rhs)
|
||||
{
|
||||
return new Vector3Double(Mathd.Min(lhs.x, rhs.x), Mathd.Min(lhs.y, rhs.y), Mathd.Min(lhs.z, rhs.z));
|
||||
}
|
||||
|
||||
public static Vector3Double Max(Vector3Double lhs, Vector3Double rhs)
|
||||
{
|
||||
return new Vector3Double(Mathd.Max(lhs.x, rhs.x), Mathd.Max(lhs.y, rhs.y), Mathd.Max(lhs.z, rhs.z));
|
||||
}
|
||||
|
||||
[Obsolete("Use Vector3Double.Angle instead. AngleBetween uses radians instead of degrees and was deprecated for this reason")]
|
||||
public static double AngleBetween(Vector3Double from, Vector3Double to)
|
||||
{
|
||||
return Mathd.Acos(Mathd.Clamp(Vector3Double.Dot(from.normalized, to.normalized), -1d, 1d));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 840339ed449418e4fa6cfe7d2695955b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,161 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public class WaterFlowMap
|
||||
{
|
||||
public float m_dropletVolume = 0.3f; //How much water is deposited in each droplet
|
||||
public float m_dropletAbsorbtionRate = 0.05f; //The amount of water absorbed by the terrain as the droplet traverses it
|
||||
public int m_waterflowSmoothIterations = 1; //The number of post process smooth iterations to apply
|
||||
private UnityHeightMap m_heightMap;
|
||||
private HeightMap m_waterFlowMap;
|
||||
|
||||
/// <summary>
|
||||
/// Create a waterflow map from the terrain
|
||||
/// </summary>
|
||||
/// <param name="terrain">Terrain to create the waterflow map from</param>
|
||||
public void CreateWaterFlowMap(Terrain terrain)
|
||||
{
|
||||
m_heightMap = new UnityHeightMap(terrain);
|
||||
int width = m_heightMap.Width();
|
||||
int depth = m_heightMap.Depth();
|
||||
m_waterFlowMap = new HeightMap(width, depth);
|
||||
|
||||
//Avoid edges for now
|
||||
for (int x = 1; x < (width - 1); x++)
|
||||
{
|
||||
for (int z = 1; z < (depth - 1); z++)
|
||||
{
|
||||
TraceWaterFlow(x, z, width, depth);
|
||||
}
|
||||
}
|
||||
|
||||
//Flip it so it matches the terrain
|
||||
m_waterFlowMap.Flip();
|
||||
|
||||
//Smooth the water map
|
||||
m_waterFlowMap.Smooth(m_waterflowSmoothIterations);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trace the water flow of one droplet
|
||||
/// </summary>
|
||||
/// <param name="startX"></param>
|
||||
/// <param name="startZ"></param>
|
||||
/// <param name="width"></param>
|
||||
/// <param name="height"></param>
|
||||
void TraceWaterFlow(int startX, int startZ, int width, int height)
|
||||
{
|
||||
float dropletVolume = m_dropletVolume;
|
||||
int x = startX;
|
||||
int z = startZ;
|
||||
float currHeight, nextHeight;
|
||||
int nX, nZ, testX, testZ, nextX, nextZ;
|
||||
|
||||
while (dropletVolume > 0f)
|
||||
{
|
||||
m_waterFlowMap[x, z] += m_dropletAbsorbtionRate;
|
||||
dropletVolume -= m_dropletAbsorbtionRate;
|
||||
|
||||
//Work out next place to flow to
|
||||
nextHeight = currHeight = m_heightMap[x, z];
|
||||
nextX = x;
|
||||
nextZ = z;
|
||||
|
||||
//Search around the droplet for the next lowest height
|
||||
for (nX = -1; nX < 2; nX++)
|
||||
{
|
||||
for (nZ = -1; nZ < 2; nZ++)
|
||||
{
|
||||
testX = x + nX;
|
||||
testZ = z + nZ;
|
||||
if ((testX >= 0) && (testX < width)) //Check valid xcoordinate
|
||||
{
|
||||
if ((testZ >= 0) && (testZ < height))
|
||||
{
|
||||
if (m_heightMap[testX, testZ] < nextHeight)
|
||||
{
|
||||
nextX = testX;
|
||||
nextZ = testZ;
|
||||
nextHeight = m_heightMap[testX, testZ];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If same height, then pool - pooling affects the underlying height by raising it
|
||||
if (currHeight == nextHeight)
|
||||
{
|
||||
m_heightMap[x, z] += m_dropletAbsorbtionRate;
|
||||
}
|
||||
|
||||
//Otherwise move onto next location
|
||||
else
|
||||
{
|
||||
x = nextX;
|
||||
z = nextZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export the water map to the supplied path
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public void ExportWaterMapToPath(string path)
|
||||
{
|
||||
Gaia.GaiaUtils.CompressToSingleChannelFileImage(m_waterFlowMap.Heights(), path, Gaia.GaiaConstants.fmtHmTextureFormat, true, false);
|
||||
}
|
||||
|
||||
/*
|
||||
void AdjustTerrainTexture(int mountainIdx, int flowIdx, float[,] waterMap)
|
||||
{
|
||||
Terrain terrain = Terrain.activeTerrain;
|
||||
int waterMapSize = waterMap.GetLength(0);
|
||||
int splatSize = terrain.terrainData.alphamapResolution;
|
||||
int splatChannels = terrain.terrainData.splatPrototypes.Length;
|
||||
float[, ,] splatMaps = terrain.terrainData.GetAlphamaps(0, 0, splatSize, splatSize);
|
||||
|
||||
//Check mountain index
|
||||
if (mountainIdx < 0 || mountainIdx >= splatChannels)
|
||||
{
|
||||
Debug.LogError(string.Format("Invalid mountain index {0} in {1} terrain", mountainIdx, splatChannels));
|
||||
return;
|
||||
}
|
||||
|
||||
//Check flow index
|
||||
if (flowIdx < 0 || flowIdx >= splatChannels)
|
||||
{
|
||||
Debug.LogError(string.Format("Invalid flow index {0} in {1} terrain", flowIdx, splatChannels));
|
||||
return;
|
||||
}
|
||||
|
||||
//Some handy params
|
||||
Debug.Log(string.Format("Splat size {0}, water map size {1}", splatSize, waterMapSize));
|
||||
float scaleFactor = (float)(waterMapSize - 1f) / (float)splatSize;
|
||||
float waterStrength, adjustment;
|
||||
|
||||
//Apply the effect of water to mountains - this will give striations
|
||||
for (int x = 0; x < splatSize; x++)
|
||||
{
|
||||
for (int z = 0; z < splatSize; z++)
|
||||
{
|
||||
waterStrength = waterMap[(int)(x * scaleFactor), (int)(z * scaleFactor)];
|
||||
if (waterStrength > 1f)
|
||||
{
|
||||
waterStrength = 1f;
|
||||
}
|
||||
|
||||
adjustment = waterStrength * splatMaps[x, z, mountainIdx];
|
||||
splatMaps[x, z, mountainIdx] -= adjustment;
|
||||
splatMaps[x, z, flowIdx] += adjustment;
|
||||
}
|
||||
}
|
||||
|
||||
terrain.terrainData.SetAlphamaps(0, 0, splatMaps);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d7d1bbb786dac1439f1ebbc39bc6c87
|
||||
timeCreated: 1454539898
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,159 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple and fast random number generator which can reset to a specific iteration
|
||||
/// </summary>
|
||||
public class XorshiftPlus
|
||||
{
|
||||
//Initialiser magic values
|
||||
private const ulong m_A_Init = 181353;
|
||||
private const ulong m_B_Init = 7;
|
||||
|
||||
//Seed
|
||||
public int m_seed;
|
||||
|
||||
//State
|
||||
public ulong m_stateA, m_stateB;
|
||||
|
||||
/// <summary>
|
||||
/// Contruct and initialise the RNG
|
||||
/// </summary>
|
||||
/// <param name="seed"></param>
|
||||
public XorshiftPlus(int seed = 1)
|
||||
{
|
||||
m_seed = seed;
|
||||
if (m_seed == 0)
|
||||
{
|
||||
m_seed = 1;
|
||||
}
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset it to its initial state with the existing seed
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
m_stateA = m_A_Init * (uint)m_seed;
|
||||
m_stateB = m_B_Init * (uint)m_seed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restet it to a new state with a new seed
|
||||
/// </summary>
|
||||
/// <param name="seed">New seed</param>
|
||||
public void Reset(int seed)
|
||||
{
|
||||
m_seed = seed;
|
||||
if (m_seed == 0)
|
||||
{
|
||||
m_seed = 1;
|
||||
}
|
||||
Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset it to the stade defined by the state variables passed in
|
||||
/// </summary>
|
||||
public void Reset(ulong stateA, ulong stateB)
|
||||
{
|
||||
Debug.Log("Resetting RNG State " + stateA + " " + stateB);
|
||||
m_stateA = stateA;
|
||||
m_stateB = stateB;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the current state for serialisation
|
||||
/// </summary>
|
||||
/// <param name="seed">Seed</param>
|
||||
/// <param name="stateA">State A</param>
|
||||
/// <param name="stateB">State B</param>
|
||||
public void GetState(out int seed, out ulong stateA, out ulong stateB)
|
||||
{
|
||||
seed = m_seed;
|
||||
stateA = m_stateA;
|
||||
stateB = m_stateB;
|
||||
}
|
||||
|
||||
//Check here for wrapper functions
|
||||
//https://github.com/tucano/UnityRandom/blob/master/lib/MersenneTwister.cs
|
||||
|
||||
/// <summary>
|
||||
/// Get the next value
|
||||
/// </summary>
|
||||
/// <returns>A value between zero and one inclusive</returns>
|
||||
public float Next()
|
||||
{
|
||||
ulong x = m_stateA;
|
||||
ulong y = m_stateB;
|
||||
m_stateA = y;
|
||||
x ^= x << 23;
|
||||
x ^= x >> 17;
|
||||
x ^= y ^ (y >> 26);
|
||||
m_stateB = x;
|
||||
return (float)(x + y) / (float)ulong.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the next int
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int NextInt()
|
||||
{
|
||||
return (int)(Next() * int.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the next value and scale it between the min and max values supplied inclusive
|
||||
/// </summary>
|
||||
/// <param name="min">Minimum value</param>
|
||||
/// <param name="max">Maximum value</param>
|
||||
/// <returns>Next value scaled beteen the range supplied</returns>
|
||||
public float Next(float min, float max)
|
||||
{
|
||||
//float xx = min + (Next() * (max - min));
|
||||
//Debug.Log(string.Format("{0:0.0000}", xx));
|
||||
//return xx;
|
||||
|
||||
return min + (Next() * (max - min));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the next value and scale it between the min and max values supplied inclusive
|
||||
/// </summary>
|
||||
/// <param name="min">Minimum value</param>
|
||||
/// <param name="max">Maximum value</param>
|
||||
/// <returns>Next value scaled beteen the range supplied</returns>
|
||||
public int Next(int min, int max)
|
||||
{
|
||||
if (min == max)
|
||||
{
|
||||
return min;
|
||||
}
|
||||
return (int)Next((float)min, (float)max+0.999f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the next value as a vector
|
||||
/// </summary>
|
||||
/// <returns>Next value as a vector in ranges 0..1</returns>
|
||||
public Vector3 NextVector()
|
||||
{
|
||||
return new Vector3(Next(), Next(), Next());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the next value as a vector
|
||||
/// </summary>
|
||||
/// <param name="min">Minimum value</param>
|
||||
/// <param name="max">Maximum value</param>
|
||||
/// <returns></returns>
|
||||
public Vector3 NextVector(float min, float max)
|
||||
{
|
||||
return new Vector3(Next(min, max), Next(min, max), Next(min, max));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f063f13ca7897a4699e15209e263fd4
|
||||
timeCreated: 1453788319
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user