Initial commit
This commit is contained in:
1 parent
ee9615239e
commit
16feac691f
4093 files changed
+1030491
No files matched your search
@@ -0,0 +1,869 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#if HDPipeline
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
#endif
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
[System.Serializable]
|
||||
public class BakedMaskCacheEntry
|
||||
{
|
||||
public string fileName;
|
||||
public string assetPath;
|
||||
public string fullPath;
|
||||
public RenderTexture texture;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class BakedMaskCache : UnityEngine.Object
|
||||
{
|
||||
public bool m_autoSpawnRunning = false;
|
||||
//bool m_cacheClearedForAutoSpawn = false;
|
||||
public GaiaSession m_gaiaSession;
|
||||
public GaiaSessionManager m_gaiaSessionManager;
|
||||
private Terrain m_worldMapTerrain;
|
||||
|
||||
public BakedMaskCacheEntry[] m_cacheEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_gaiaSession == null)
|
||||
{
|
||||
m_gaiaSession = GaiaSessionManager.GetSessionManager(false).m_session;
|
||||
}
|
||||
return m_gaiaSession.m_bakedMaskCacheEntries;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_gaiaSession == null)
|
||||
{
|
||||
m_gaiaSession = GaiaSessionManager.GetSessionManager(false).m_session;
|
||||
}
|
||||
m_gaiaSession.m_bakedMaskCacheEntries = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public RenderTexture BakeTerrainTagCollisions(Terrain terrain, string tag, float radius)
|
||||
{
|
||||
GameObject[] allGOsWithTag = new GameObject[0];
|
||||
|
||||
bool tagFound = false;
|
||||
try
|
||||
{
|
||||
allGOsWithTag = GameObject.FindGameObjectsWithTag(tag);
|
||||
tagFound = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
tagFound = false;
|
||||
}
|
||||
|
||||
if (!tagFound)
|
||||
{
|
||||
Debug.LogWarning("Could not find Game Objects for tag: " + tag + " when trying to bake a collision mask. Does this tag exist?");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//Array to store all positions and radi of the objects
|
||||
Vector4[] posAndRad = new Vector4[allGOsWithTag.Length];
|
||||
for (int i = 0; i < allGOsWithTag.Length; i++)
|
||||
{
|
||||
//need scalar position on the terrain from 0..1
|
||||
//start with the actual center of the object - the transform.position is at the pivot which is not necessarily the center of the object.
|
||||
Vector3 centerPosition = GetCenterAverage(allGOsWithTag[i].transform);
|
||||
|
||||
|
||||
//get relative positon on the terrain first
|
||||
float scaleFactor = (allGOsWithTag[i].transform.localScale.x + allGOsWithTag[i].transform.localScale.z) / 2f;
|
||||
Vector4 v4 = new Vector4(centerPosition.x, centerPosition.y, centerPosition.z, WorldDistance2UVDistance(terrain, radius * scaleFactor));
|
||||
v4.x -= terrain.transform.position.x;
|
||||
v4.y -= terrain.transform.position.y;
|
||||
v4.z -= terrain.transform.position.z;
|
||||
//now make that relative position scalar (0..1)
|
||||
v4.x /= terrain.terrainData.size.x;
|
||||
v4.y /= terrain.terrainData.size.y;
|
||||
v4.z /= terrain.terrainData.size.z;
|
||||
//flip on z-axis
|
||||
v4.z = 1 - v4.z;
|
||||
|
||||
posAndRad[i] = v4;
|
||||
}
|
||||
|
||||
string fileName = GetTagCollisionMaskFileName(terrain, tag, radius);
|
||||
|
||||
return BakeVectorArrayForTerrain(posAndRad, terrain, fileName);
|
||||
}
|
||||
|
||||
private Vector3 GetCenterAverage(Transform transform)
|
||||
{
|
||||
int childCount = transform.childCount;
|
||||
if (childCount == 0)
|
||||
{
|
||||
return transform.position;
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 returnVector = Vector3.zero;
|
||||
for (int i = 0; i < childCount; i++)
|
||||
{
|
||||
returnVector += GetCenterAverage(transform.GetChild(i));
|
||||
}
|
||||
returnVector /= childCount;
|
||||
return returnVector;
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteCacheToDisk()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
int length = m_cacheEntries.Length;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
ImageProcessing.WriteRenderTexture(m_cacheEntries[i].fullPath, m_cacheEntries[i].texture);
|
||||
|
||||
//Refresh mask immediately by reimporting it in the same step
|
||||
AssetDatabase.ImportAsset(m_cacheEntries[i].assetPath, ImportAssetOptions.ForceUpdate);
|
||||
|
||||
m_cacheEntries[i].texture = null;
|
||||
|
||||
}
|
||||
|
||||
//clear the cache for a clean start, this will free the cache from outdated entries, etc.
|
||||
//the cache will be rebuilt quickly only with the relevant files which are saved to disk now.
|
||||
m_cacheEntries = new BakedMaskCacheEntry[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
public RenderTexture BakeTerrainWorldBiomeMask(Terrain terrain, string worldBiomeMaskGUID)
|
||||
{
|
||||
if (m_gaiaSessionManager == null)
|
||||
{
|
||||
m_gaiaSessionManager = GaiaSessionManager.GetSessionManager(false);
|
||||
}
|
||||
if (m_worldMapTerrain == null)
|
||||
{
|
||||
m_worldMapTerrain = TerrainHelper.GetWorldMapTerrain();
|
||||
}
|
||||
if (m_worldMapTerrain == null)
|
||||
{
|
||||
Debug.LogWarning("Found no world map terrain for baking a world biome mask.");
|
||||
return null;
|
||||
}
|
||||
if (String.IsNullOrEmpty(worldBiomeMaskGUID))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (m_gaiaSessionManager.m_session == null)
|
||||
{
|
||||
Debug.LogWarning("Found no session for baking a world biome mask.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (m_gaiaSessionManager.m_session.m_worldBiomeMaskSettings == null)
|
||||
{
|
||||
Debug.LogWarning("Found no world designer settings in the session for baking a world biome mask.");
|
||||
return null;
|
||||
}
|
||||
|
||||
//we need to apply the mask stack for this biome mask on the world map to get the result, then copy the appropiate rectangle for the queried terrain into the cache & return it.
|
||||
bool worldMapActiveState = m_worldMapTerrain.gameObject.activeInHierarchy;
|
||||
m_worldMapTerrain.gameObject.SetActive(true);
|
||||
GameObject emptyGO = new GameObject();
|
||||
emptyGO.transform.position = new Vector3(m_worldMapTerrain.transform.position.x + m_worldMapTerrain.terrainData.size.x / 2f, m_worldMapTerrain.transform.position.y, m_worldMapTerrain.transform.position.z + +m_worldMapTerrain.terrainData.size.z / 2f);
|
||||
GaiaMultiTerrainOperation operation = new GaiaMultiTerrainOperation(m_worldMapTerrain, emptyGO.transform, m_worldMapTerrain.terrainData.size.x);
|
||||
operation.m_isWorldMapOperation = true;
|
||||
operation.GetHeightmap();
|
||||
operation.GetNormalmap();
|
||||
operation.CollectTerrainBakedMasks();
|
||||
RenderTextureDescriptor rtDescriptor = operation.RTbakedMask.descriptor;
|
||||
|
||||
RenderTexture inputTexture = RenderTexture.GetTemporary(rtDescriptor);
|
||||
|
||||
RenderTexture currentRT = RenderTexture.active;
|
||||
RenderTexture.active = inputTexture;
|
||||
GL.Clear(true, true, Color.white);
|
||||
RenderTexture.active = currentRT;
|
||||
RenderTexture ruleOutputTexture = RenderTexture.GetTemporary(rtDescriptor);
|
||||
|
||||
ImageMask[] maskStack = m_gaiaSessionManager.m_session.m_worldBiomeMaskSettings.m_spawnerRules.Find(x => x.GUID == worldBiomeMaskGUID).m_imageMasks;
|
||||
|
||||
//Calculate Target position &/ resolution
|
||||
BoundsDouble bounds = new BoundsDouble();
|
||||
TerrainHelper.GetTerrainBounds(ref bounds);
|
||||
bounds.center -= TerrainLoaderManager.Instance.GetOrigin();
|
||||
RenderTexture chunkContent = new RenderTexture(terrain.terrainData.heightmapTexture.descriptor);
|
||||
int maxTilesX = Mathf.RoundToInt((float)bounds.size.x / terrain.terrainData.size.x);
|
||||
int maxTilesZ = Mathf.RoundToInt((float)bounds.size.z / terrain.terrainData.size.z);
|
||||
int currentTileX = Mathf.RoundToInt((terrain.transform.position.x - (float)bounds.min.x) / terrain.terrainData.size.x);
|
||||
int currentTileZ = Mathf.RoundToInt((terrain.transform.position.z - (float)bounds.min.z) / terrain.terrainData.size.z);
|
||||
float res = (terrain.terrainData.heightmapResolution) / ((float)bounds.size.x / terrain.terrainData.bounds.size.x * (terrain.terrainData.heightmapResolution - 1));
|
||||
|
||||
|
||||
Bounds worldSpaceBounds = terrain.terrainData.bounds;
|
||||
worldSpaceBounds.center = new Vector3(worldSpaceBounds.center.x + terrain.transform.position.x, worldSpaceBounds.center.y + terrain.transform.position.y, worldSpaceBounds.center.z + terrain.transform.position.z);
|
||||
float xPos = ((float)currentTileX * terrain.terrainData.heightmapResolution) / (maxTilesX * terrain.terrainData.heightmapResolution);
|
||||
float zPos = ((float)currentTileZ * terrain.terrainData.heightmapResolution) / (maxTilesZ * terrain.terrainData.heightmapResolution);
|
||||
Vector2 pos = new Vector2(xPos, zPos);
|
||||
|
||||
//If we have a mask stack, we need to process it
|
||||
if (maskStack != null && maskStack.Length > 0)
|
||||
{
|
||||
|
||||
//We start from a white texture, so we need the first mask action in the stack to always be "Multiply", otherwise there will be no result.
|
||||
maskStack[0].m_blendMode = ImageMaskBlendMode.Multiply;
|
||||
|
||||
float maxWorldHeight = 0f;
|
||||
float minWorldHeight = 0f;
|
||||
m_gaiaSessionManager.GetWorldMinMax(ref minWorldHeight, ref maxWorldHeight, true);
|
||||
|
||||
//Iterate through all image masks and set up the current paint context in case the shader uses heightmap data
|
||||
foreach (ImageMask mask in maskStack)
|
||||
{
|
||||
mask.m_multiTerrainOperation = operation;
|
||||
mask.m_seaLevel = m_gaiaSessionManager.GetSeaLevel(true);
|
||||
mask.m_maxWorldHeight = maxWorldHeight;
|
||||
mask.m_minWorldHeight = minWorldHeight;
|
||||
}
|
||||
|
||||
Graphics.Blit(ImageProcessing.ApplyMaskStack(inputTexture, ruleOutputTexture, maskStack, ImageMaskInfluence.Local), ruleOutputTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
//no mask stack -> just blit the white input texture over as the output
|
||||
Graphics.Blit(inputTexture, ruleOutputTexture);
|
||||
}
|
||||
operation.CloseOperation();
|
||||
DestroyImmediate(emptyGO);
|
||||
RenderTexture.ReleaseTemporary(inputTexture);
|
||||
m_worldMapTerrain.gameObject.SetActive(worldMapActiveState);
|
||||
|
||||
//copy the rule output into the right size for the requested terrain chunk
|
||||
Graphics.Blit(ruleOutputTexture, chunkContent, new Vector2(res, res), pos);
|
||||
|
||||
string filename = GetWorldBiomeMaskFilename(terrain, worldBiomeMaskGUID);
|
||||
SaveBakedMaskInCache(chunkContent, terrain, filename);
|
||||
|
||||
RenderTexture.ReleaseTemporary(ruleOutputTexture);
|
||||
|
||||
return chunkContent;
|
||||
}
|
||||
|
||||
public RenderTexture BakeLayerGameObjectCollisions(Terrain terrain, LayerMask layerMask, float distance)
|
||||
{
|
||||
//Set up the scene for the layer mask bake. Do all this in a try catch so we can clean up in case anything goes wrong.
|
||||
RenderTexture collisionMask = OrthoLayerBake(terrain, layerMask, distance);
|
||||
|
||||
string fileName = GetLayerGameObjectCollisionMaskFileName(terrain, layerMask, distance);
|
||||
SaveBakedMaskInCache(collisionMask, terrain, fileName);
|
||||
|
||||
return collisionMask;
|
||||
}
|
||||
|
||||
private RenderTexture OrthoLayerBake(Terrain terrain, LayerMask layerMask, float distance)
|
||||
{
|
||||
RenderTextureDescriptor rtDesc = GetDefaultCollisionMaskRTDescriptor(terrain);
|
||||
RenderTexture collisionMask = new RenderTexture(rtDesc);
|
||||
RenderTexture currentRT = RenderTexture.active;
|
||||
RenderTexture.active = collisionMask;
|
||||
//we start with a full white texture, the areas that would create a collision are painted in black
|
||||
GL.Clear(true, true, Color.white);
|
||||
RenderTexture.active = currentRT;
|
||||
var originalLODBias = QualitySettings.lodBias;
|
||||
try
|
||||
{
|
||||
#if HDPipeline
|
||||
//In HD Pipeline we can use a frame override to set the LOD Bias for the capture.
|
||||
OrthographicBake.m_HDLODBiasOverride = 100;
|
||||
#else
|
||||
QualitySettings.lodBias = 100;
|
||||
#endif
|
||||
OrthographicBake.LightsOff();
|
||||
OrthographicBake.CreateBakeDirectionalLight(9999f, Color.white);
|
||||
OrthographicBake.BakeTerrain(terrain, terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution, layerMask, null);
|
||||
Material growShrinkMaterial = new Material(Shader.Find("Hidden/Gaia/GrowShrink"));
|
||||
growShrinkMaterial.SetTexture("_InputTex", OrthographicBake.m_tmpRenderTexture);
|
||||
//translate the grow shrink distance into a scalar terrain value, as the shader works with U/V coordinates
|
||||
float scalarDistance = distance / terrain.terrainData.size.x;
|
||||
growShrinkMaterial.SetFloat("_Distance", scalarDistance);
|
||||
growShrinkMaterial.SetFloat("_TexelSize", OrthographicBake.m_tmpRenderTexture.texelSize.x);
|
||||
Graphics.Blit(OrthographicBake.m_tmpRenderTexture, collisionMask, growShrinkMaterial, 1);
|
||||
OrthographicBake.CleanUpRenderTexture();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError("Error while trying to bake a layer-based game object collision mask. Error Message: " + ex.Message + " Stack Trace: " + ex.StackTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if !HDPipeline
|
||||
QualitySettings.lodBias = originalLODBias;
|
||||
#endif
|
||||
|
||||
OrthographicBake.LightsOn();
|
||||
OrthographicBake.RemoveBakeDirectionalLight();
|
||||
OrthographicBake.RemoveOrthoCam();
|
||||
}
|
||||
return collisionMask;
|
||||
}
|
||||
|
||||
private RenderTexture BakeLayerTreeCollisions(Terrain terrain, LayerMask layerMask, float growShrinkDistance)
|
||||
{
|
||||
bool originalHeightmapEnabled = terrain.drawHeightmap;
|
||||
bool[] originalChildEnabledStates = new bool[terrain.transform.childCount];
|
||||
for (int i = 0; i < terrain.transform.childCount; i++)
|
||||
{
|
||||
originalChildEnabledStates[i] = terrain.transform.GetChild(i).gameObject.activeInHierarchy;
|
||||
}
|
||||
|
||||
RenderTexture collisionMask = null;
|
||||
try
|
||||
{
|
||||
//Add in the layer of the terrain to the layer selection - needs to be visible for the ortho bake so the trees show up in the baked image
|
||||
int terrainlayerbits = 1 << terrain.gameObject.layer;
|
||||
layerMask = layerMask | terrainlayerbits;
|
||||
|
||||
terrain.drawHeightmap = false;
|
||||
for (int i = 0; i < terrain.transform.childCount; i++)
|
||||
{
|
||||
terrain.transform.GetChild(i).gameObject.SetActive(false);
|
||||
}
|
||||
collisionMask = OrthoLayerBake(terrain, layerMask, growShrinkDistance);
|
||||
string fileName = GetLayerTreeCollisionMaskFileName(terrain, layerMask, growShrinkDistance);
|
||||
SaveBakedMaskInCache(collisionMask, terrain, fileName);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError("Error while trying to bake a layer-based tree collision mask. Error Message: " + ex.Message + " Stack Trace: " + ex.StackTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
terrain.drawHeightmap = originalHeightmapEnabled;
|
||||
for (int i = 0; i < terrain.transform.childCount; i++)
|
||||
{
|
||||
terrain.transform.GetChild(i).gameObject.SetActive(originalChildEnabledStates[i]);
|
||||
}
|
||||
|
||||
}
|
||||
return collisionMask;
|
||||
}
|
||||
|
||||
|
||||
public RenderTexture BakeTerrainTreeCollisions(Terrain terrain, int treePrototypeId, string spawnRuleGUID, float boundsRadius)
|
||||
{
|
||||
//Iterate through the trees and build a v4 array with the positions
|
||||
|
||||
TreeInstance[] allRelevantTrees = terrain.terrainData.treeInstances.Where(x => x.prototypeIndex == treePrototypeId).ToArray();
|
||||
//Array to store all positions and radi of the tree
|
||||
Vector4[] posAndRad = new Vector4[allRelevantTrees.Length];
|
||||
|
||||
for (int i = 0; i < allRelevantTrees.Length; i++)
|
||||
{
|
||||
//note the flip on the z-axis
|
||||
posAndRad[i] = new Vector4(allRelevantTrees[i].position.x, allRelevantTrees[i].position.y, 1 - allRelevantTrees[i].position.z, WorldDistance2UVDistance(terrain, boundsRadius * allRelevantTrees[i].widthScale));
|
||||
}
|
||||
|
||||
string fileName = GetTreeCollisionMaskFileName(terrain, spawnRuleGUID, boundsRadius);
|
||||
|
||||
return BakeVectorArrayForTerrain(posAndRad, terrain, fileName);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a regular world space unity unit distance to a distance in scalar (0-1) UV-space on a terrain.
|
||||
/// </summary>
|
||||
/// <param name="Terrain">The terrain on which the conversion takes place</param>
|
||||
/// <param name="distance">The distance to convert.</param>
|
||||
/// <returns></returns>
|
||||
private float WorldDistance2UVDistance(Terrain terrain, float distance)
|
||||
{
|
||||
float longerSideLength = Mathf.Max(terrain.terrainData.size.x, terrain.terrainData.size.z);
|
||||
return Mathf.InverseLerp(0, longerSideLength, distance);
|
||||
}
|
||||
|
||||
private RenderTexture BakeVectorArrayForTerrain(Vector4[] posAndRad, Terrain terrain, string filename)
|
||||
{
|
||||
//setting up with default settings from the paint context source render texture
|
||||
RenderTextureDescriptor rtDesc = GetDefaultCollisionMaskRTDescriptor(terrain);
|
||||
|
||||
RenderTexture collisionMask = new RenderTexture(rtDesc);
|
||||
RenderTexture currentRT = RenderTexture.active;
|
||||
RenderTexture.active = collisionMask;
|
||||
//we start with a full white texture, the areas that would create a collision are painted in black
|
||||
GL.Clear(true, true, Color.white);
|
||||
RenderTexture.active = currentRT;
|
||||
|
||||
//We need a buffer texture to continously feed the output of the tree collision baking back into the shader.
|
||||
//while still iterating through the trees.
|
||||
RenderTexture collisionMaskBuffer = RenderTexture.GetTemporary(collisionMask.descriptor);
|
||||
//Clear the buffer for a clean start
|
||||
Graphics.Blit(collisionMask, collisionMaskBuffer);
|
||||
//Prepare a material that will bake the trees into a mask as we spawn them
|
||||
Material treeBakeMat = new Material(Shader.Find("Hidden/Gaia/TreeCollisionMaskBaking"));
|
||||
//treeBakeMat.SetFloat("_Strength", 1f);
|
||||
//AnimationCurve tempCurve = new AnimationCurve(new Keyframe[] { new Keyframe { time = 0, value = 1 }, new Keyframe { time = 1, value = 0 } });
|
||||
//Texture2D tempTexture = new Texture2D(256, 1);
|
||||
//ImageProcessing.CreateMaskCurveTexture(ref tempTexture);
|
||||
//ImageProcessing.BakeCurveTexture(tempCurve, tempTexture);
|
||||
//treeBakeMat.SetTexture("_DistanceMaskTex", tempTexture);
|
||||
|
||||
//treeBakeMat.SetInt("_Invert", 0);
|
||||
//
|
||||
int currentPosNumber = 0;
|
||||
while (currentPosNumber < posAndRad.Length)
|
||||
{
|
||||
int segmentLength = Math.Min(1000, posAndRad.Length - currentPosNumber);
|
||||
Vector4[] segment = new Vector4[segmentLength];
|
||||
Array.Copy(posAndRad, Math.Max(0, currentPosNumber - 1), segment, 0, segmentLength);
|
||||
treeBakeMat.SetTexture("_InputTex", collisionMaskBuffer);
|
||||
treeBakeMat.SetVectorArray("_TargetPosition", segment);
|
||||
treeBakeMat.SetInt("_PositionsCount", segmentLength);
|
||||
Graphics.Blit(collisionMaskBuffer, collisionMask, treeBakeMat, 2);
|
||||
Graphics.Blit(collisionMask, collisionMaskBuffer);
|
||||
currentPosNumber += segmentLength;
|
||||
}
|
||||
////Iterate through the trees and bake
|
||||
//foreach (Vector4 v4 in posAndRad)
|
||||
//{
|
||||
|
||||
// //treeBakeMat.SetVector("_TargetPosition", new Vector4(v4.x, v4.z, 0, 0));
|
||||
// treeBakeMat.SetTexture("_InputTex", collisionMaskBuffer);
|
||||
// Graphics.Blit(collisionMaskBuffer, collisionMask, treeBakeMat, 2);
|
||||
// Graphics.Blit(collisionMask, collisionMaskBuffer);
|
||||
//}
|
||||
|
||||
//Store the final result in the appropiate file
|
||||
|
||||
SaveBakedMaskInCache(collisionMask, terrain, filename);
|
||||
//Clean Up
|
||||
//DestroyImmediate(tempTexture);
|
||||
//tempTexture = null;
|
||||
//RenderTexture.ReleaseTemporary(collisionMask);
|
||||
RenderTexture.ReleaseTemporary(collisionMaskBuffer);
|
||||
return collisionMask;
|
||||
}
|
||||
|
||||
private RenderTextureDescriptor GetDefaultCollisionMaskRTDescriptor(Terrain terrain)
|
||||
{
|
||||
RenderTextureDescriptor rtDesc = new RenderTextureDescriptor();
|
||||
rtDesc.autoGenerateMips = true;
|
||||
rtDesc.bindMS = false;
|
||||
rtDesc.colorFormat = RenderTextureFormat.R16;
|
||||
rtDesc.depthBufferBits = 0;
|
||||
rtDesc.dimension = UnityEngine.Rendering.TextureDimension.Tex2D;
|
||||
rtDesc.enableRandomWrite = true;
|
||||
rtDesc.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R16_UNorm;
|
||||
rtDesc.height = Mathf.RoundToInt(terrain.terrainData.size.z);
|
||||
rtDesc.memoryless = RenderTextureMemoryless.None;
|
||||
rtDesc.msaaSamples = 1;
|
||||
rtDesc.sRGB = false;
|
||||
rtDesc.shadowSamplingMode = UnityEngine.Rendering.ShadowSamplingMode.None;
|
||||
rtDesc.useDynamicScale = false;
|
||||
rtDesc.useMipMap = false;
|
||||
rtDesc.volumeDepth = 1;
|
||||
rtDesc.vrUsage = VRTextureUsage.None;
|
||||
rtDesc.width = Mathf.RoundToInt(terrain.terrainData.size.x);
|
||||
return rtDesc;
|
||||
}
|
||||
|
||||
private string GetTreeCollisionMaskFileName(Terrain terrain, string spawnRuleGUID, float radius)
|
||||
{
|
||||
return terrain.name + "_" + BakedMaskTypeInternal.RadiusTree.ToString() + "_" + spawnRuleGUID + "_" + radius.ToString();
|
||||
}
|
||||
|
||||
private string GetTreeCollisionMaskSearchString(string spawnRuleGUID)
|
||||
{
|
||||
return BakedMaskTypeInternal.RadiusTree.ToString() + "_" + spawnRuleGUID.ToString();
|
||||
}
|
||||
|
||||
private string GetLayerGameObjectCollisionMaskFileName(Terrain terrain, LayerMask layerMask, float distance)
|
||||
{
|
||||
return terrain.name + "_" + BakedMaskTypeInternal.LayerGameObject.ToString() + "_" + layerMask.value.ToString() + "_" + distance.ToString();
|
||||
}
|
||||
|
||||
private string GetLayerTreeCollisionMaskFileName(Terrain terrain, LayerMask layerMask, float distance)
|
||||
{
|
||||
return terrain.name + "_" + BakedMaskTypeInternal.LayerTree.ToString() + "_" + layerMask.value.ToString() + "_" + distance.ToString();
|
||||
}
|
||||
|
||||
private string GetTagCollisionMaskFileName(Terrain terrain, string m_tag, float radius)
|
||||
{
|
||||
return terrain.name + "_" + BakedMaskTypeInternal.RadiusTag.ToString() + "_" + m_tag + "_" + radius.ToString();
|
||||
}
|
||||
|
||||
private LayerMask GetLayerMaskFromFileName(string fileName)
|
||||
{
|
||||
string masktypeName = "";
|
||||
if (fileName.Contains(BakedMaskTypeInternal.LayerGameObject.ToString()))
|
||||
{
|
||||
masktypeName = BakedMaskTypeInternal.LayerGameObject.ToString();
|
||||
}
|
||||
if (fileName.Contains(BakedMaskTypeInternal.LayerTree.ToString()))
|
||||
{
|
||||
masktypeName = BakedMaskTypeInternal.LayerTree.ToString();
|
||||
}
|
||||
if (masktypeName == "")
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
string layerMaskString = fileName.Substring(fileName.IndexOf(masktypeName) + masktypeName.Length + 1);
|
||||
layerMaskString = layerMaskString.Substring(0, layerMaskString.LastIndexOf("_"));
|
||||
|
||||
try
|
||||
{
|
||||
int parsedInt = -1;
|
||||
int.TryParse(layerMaskString, out parsedInt);
|
||||
LayerMask layerMask = parsedInt;
|
||||
return layerMask;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError("could not reset a cached collision layer mask, tried to use the following layer mask string: " + layerMaskString);
|
||||
//workaround to avoid warning in the compiler
|
||||
if (ex.Message == "")
|
||||
{
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string GetTagCollisionMaskSearchString(string tag)
|
||||
{
|
||||
return BakedMaskTypeInternal.RadiusTag.ToString() + "_" + tag;
|
||||
}
|
||||
|
||||
private string GetWorldBiomeMaskFilename(Terrain terrain, string GUID)
|
||||
{
|
||||
return terrain.name + "_" + BakedMaskTypeInternal.WorldBiomeMask.ToString() + "_" + GUID;
|
||||
}
|
||||
|
||||
private string GetWorldBiomeMaskSearchString(string GUID)
|
||||
{
|
||||
return BakedMaskTypeInternal.WorldBiomeMask.ToString() + "_" + GUID;
|
||||
}
|
||||
|
||||
private void SaveBakedMaskInCache(RenderTexture renderTexture, Terrain terrain, string fileName)
|
||||
{
|
||||
if (m_cacheEntries == null)
|
||||
{
|
||||
m_cacheEntries = new BakedMaskCacheEntry[0];
|
||||
}
|
||||
|
||||
//Convert the RT
|
||||
//Texture2D texture = GaiaUtils.ConvertRenderTextureToTexture2D(renderTexture);
|
||||
|
||||
//texture.name = fileName;
|
||||
|
||||
//Check if there is an entry already
|
||||
int length = m_cacheEntries.Length;
|
||||
bool found = false;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (m_cacheEntries[i].fileName == fileName)
|
||||
{
|
||||
//found an entry, update with new render texture
|
||||
found = true;
|
||||
if (m_cacheEntries[i].texture != null)
|
||||
{
|
||||
m_cacheEntries[i].texture.Release();
|
||||
DestroyImmediate(m_cacheEntries[i].texture);
|
||||
}
|
||||
WriteCacheEntry(m_cacheEntries[i], renderTexture, terrain, fileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Not found? Need to append cache array and write the new entry at the end
|
||||
if (!found)
|
||||
{
|
||||
AddNewCollisionMaskCacheEntry(renderTexture, terrain, fileName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void AddNewCollisionMaskCacheEntry(RenderTexture texture, Terrain terrain, string fileName)
|
||||
{
|
||||
BakedMaskCacheEntry[] newArray = new BakedMaskCacheEntry[m_cacheEntries.Length + 1];
|
||||
int length2 = m_cacheEntries.Length;
|
||||
for (int i = 0; i < length2; i++)
|
||||
{
|
||||
newArray[i] = m_cacheEntries[i];
|
||||
}
|
||||
newArray[newArray.Length - 1] = new BakedMaskCacheEntry();
|
||||
WriteCacheEntry(newArray[newArray.Length - 1], texture, terrain, fileName);
|
||||
m_cacheEntries = newArray;
|
||||
//EditorUtility.SetDirty(this);
|
||||
#if UNITY_EDITOR
|
||||
EditorUtility.SetDirty(GaiaSessionManager.GetSessionManager(false));
|
||||
#endif
|
||||
}
|
||||
|
||||
private void WriteCacheEntry(BakedMaskCacheEntry entry, RenderTexture texture, Terrain terrain, string fileName)
|
||||
{
|
||||
|
||||
//build the paths
|
||||
string assetPath = GaiaDirectories.GetTerrainCollisionDirectory(terrain) + "/" + fileName;
|
||||
string fullPath = assetPath.Replace("Assets", Application.dataPath);
|
||||
|
||||
//clear old texture
|
||||
if (entry.texture != null && entry.texture != Texture2D.whiteTexture)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(entry.texture);
|
||||
entry.texture = null;
|
||||
}
|
||||
//overwrite texture contents
|
||||
entry.texture = texture;
|
||||
|
||||
//assign Paths & name
|
||||
entry.fileName = fileName;
|
||||
entry.assetPath = assetPath;
|
||||
entry.fullPath = fullPath;
|
||||
}
|
||||
|
||||
public RenderTexture LoadBakedMask(Terrain terrain, BakedMaskTypeInternal type, CollisionMask collisionMask = null, string worldMaskGUID = "", int treeID = 0) //float radius, int id = 0, string tag = "", string GUID = "")
|
||||
{
|
||||
|
||||
if (m_cacheEntries == null)
|
||||
{
|
||||
m_cacheEntries = new BakedMaskCacheEntry[0];
|
||||
}
|
||||
|
||||
string fileName = "";
|
||||
switch (type)
|
||||
{
|
||||
case BakedMaskTypeInternal.RadiusTree:
|
||||
fileName = GetTreeCollisionMaskFileName(terrain, collisionMask.m_treeSpawnRuleGUID, collisionMask.m_Radius);
|
||||
break;
|
||||
case BakedMaskTypeInternal.RadiusTag:
|
||||
fileName = GetTagCollisionMaskFileName(terrain, collisionMask.m_tag, collisionMask.m_Radius);
|
||||
break;
|
||||
case BakedMaskTypeInternal.WorldBiomeMask:
|
||||
fileName = GetWorldBiomeMaskFilename(terrain, worldMaskGUID);
|
||||
break;
|
||||
case BakedMaskTypeInternal.LayerGameObject:
|
||||
fileName = GetLayerGameObjectCollisionMaskFileName(terrain, collisionMask.m_layerMask, collisionMask.m_growShrinkDistance);
|
||||
break;
|
||||
case BakedMaskTypeInternal.LayerTree:
|
||||
fileName = GetLayerTreeCollisionMaskFileName(terrain, collisionMask.m_layerMask, collisionMask.m_growShrinkDistance);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
if (fileName != "")
|
||||
{
|
||||
//file in cache? If yes, return from there
|
||||
int length = m_cacheEntries.Length;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (m_cacheEntries[i].fileName == fileName)
|
||||
//does it have a texture as well?
|
||||
if (m_cacheEntries[i].texture != null)
|
||||
{
|
||||
//found it, we can return it & are done
|
||||
return m_cacheEntries[i].texture;
|
||||
}
|
||||
}
|
||||
|
||||
//not in cache? We need to bake it then!
|
||||
switch (type)
|
||||
{
|
||||
case BakedMaskTypeInternal.RadiusTree:
|
||||
return BakeTerrainTreeCollisions(terrain, treeID, collisionMask.m_treeSpawnRuleGUID, collisionMask.m_Radius);
|
||||
case BakedMaskTypeInternal.RadiusTag:
|
||||
return BakeTerrainTagCollisions(terrain, collisionMask.m_tag, collisionMask.m_Radius);
|
||||
case BakedMaskTypeInternal.WorldBiomeMask:
|
||||
return BakeTerrainWorldBiomeMask(terrain, worldMaskGUID);
|
||||
case BakedMaskTypeInternal.LayerGameObject:
|
||||
return BakeLayerGameObjectCollisions(terrain, collisionMask.m_layerMask, collisionMask.m_growShrinkDistance);
|
||||
case BakedMaskTypeInternal.LayerTree:
|
||||
return BakeLayerTreeCollisions(terrain, collisionMask.m_layerMask, collisionMask.m_growShrinkDistance);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//not in cache? try reading from disk...
|
||||
#if UNITY_EDITOR
|
||||
//Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(GaiaDirectories.GetTerrainCollisionDirectory(terrain) + "/" + GetTreeCollisionMaskFileName(terrain, id, radius), typeof(Texture2D));
|
||||
|
||||
|
||||
//if (texture != null)
|
||||
//{
|
||||
// //found it on disk, write a copy of it in cache for next access attempt, then return the copy.
|
||||
// //We need to work with a copy here because otherwise we can run into issue when trying to overwrite the image file
|
||||
// Texture2D copy = new Texture2D(texture.width, texture.height, texture.format, true);
|
||||
// Graphics.CopyTexture(texture, copy);
|
||||
// AddNewCollisionMaskCacheEntry(copy, terrain, fileName);
|
||||
// return copy;
|
||||
//}
|
||||
#endif
|
||||
|
||||
}
|
||||
else return null;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void BakeAllLayerGameObjectCollisions(LayerMask layerMask, float growShrinkDistance)
|
||||
{
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
BakeLayerGameObjectCollisions(t, layerMask, growShrinkDistance);
|
||||
}
|
||||
}
|
||||
|
||||
public void BakeAllLayerTreeCollisions(LayerMask layerMask, float growShrinkDistance)
|
||||
{
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
BakeLayerTreeCollisions(t, layerMask, growShrinkDistance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void BakeAllTreeCollisions(string spawnRuleGUID, float radius)
|
||||
{
|
||||
SpawnRule sr = CollisionMask.m_allTreeSpawnRules.FirstOrDefault(x => x.GUID == spawnRuleGUID);
|
||||
if (sr == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
int treePrototypeID = TerrainHelper.GetTreePrototypeIDFromSpawnRule(sr, t);
|
||||
if (treePrototypeID != -1)
|
||||
{
|
||||
BakeTerrainTreeCollisions(t, treePrototypeID, spawnRuleGUID, radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BakeAllTagCollisions(string m_tag, float m_tagRadius)
|
||||
{
|
||||
foreach (Terrain t in Terrain.activeTerrains)
|
||||
{
|
||||
BakeTerrainTagCollisions(t, m_tag, m_tagRadius);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearCache()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
int length = m_cacheEntries.Length;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (m_cacheEntries[i].texture != null)
|
||||
{
|
||||
m_cacheEntries[i].texture.Release();
|
||||
//DestroyImmediate(m_cacheEntries[i].texture);
|
||||
m_cacheEntries[i].texture = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_cacheEntries = new BakedMaskCacheEntry[0];
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ClearCacheForSpawn()
|
||||
{
|
||||
ClearCache();
|
||||
}
|
||||
|
||||
public void SetWorldBiomeMaskDirty(string worldBiomeMaskGUID)
|
||||
{
|
||||
string searchString = GetWorldBiomeMaskSearchString(worldBiomeMaskGUID);
|
||||
SetDirty(searchString);
|
||||
|
||||
}
|
||||
|
||||
public void SetTreeDirty(string spawnRuleGUID, int layerID)
|
||||
{
|
||||
string searchString = GetTreeCollisionMaskSearchString(spawnRuleGUID);
|
||||
SetDirty(searchString);
|
||||
SetLayerIDDirty(layerID);
|
||||
|
||||
}
|
||||
|
||||
public void SetGameObjectDirty(GameObject gameObject)
|
||||
{
|
||||
if (gameObject.tag != "Untagged")
|
||||
{
|
||||
string searchString = GetTagCollisionMaskSearchString(gameObject.tag);
|
||||
SetDirty(searchString);
|
||||
}
|
||||
SetLayerIDDirty(gameObject.layer);
|
||||
}
|
||||
|
||||
|
||||
private void SetLayerIDDirty(int layerID)
|
||||
{
|
||||
//Iterate through the cached textures, and fish out the ones that fit the layer ID according to the layer mask, then relase them
|
||||
for (int i = 0; i < m_cacheEntries.Length; i++)
|
||||
{
|
||||
LayerMask layerMask = GetLayerMaskFromFileName(m_cacheEntries[i].fileName);
|
||||
|
||||
if (layerMask != -1)
|
||||
{
|
||||
if ((layerMask & 1 << layerID) != 0)
|
||||
{
|
||||
//found the layer in the layer mask, need to release the texture
|
||||
if (m_cacheEntries[i].texture != null)
|
||||
{
|
||||
m_cacheEntries[i].texture.Release();
|
||||
//DestroyImmediate(m_cacheEntries[i].texture);
|
||||
m_cacheEntries[i].texture = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDirty(string searchString)
|
||||
{
|
||||
//Release the affected render textures
|
||||
for (int i = 0; i < m_cacheEntries.Length; i++)
|
||||
{
|
||||
if (m_cacheEntries[i].fileName.Contains(searchString))
|
||||
{
|
||||
if (m_cacheEntries[i].texture != null)
|
||||
{
|
||||
m_cacheEntries[i].texture.Release();
|
||||
//DestroyImmediate(m_cacheEntries[i].texture);
|
||||
m_cacheEntries[i].texture = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Remove the affected array entries
|
||||
m_cacheEntries = m_cacheEntries.Where(x => x.fileName.Contains(searchString) != true).ToArray();
|
||||
}
|
||||
|
||||
//public void BeginAutoSpawn()
|
||||
//{
|
||||
// m_autoSpawnRunning = true;
|
||||
// m_cacheClearedForAutoSpawn = false;
|
||||
//}
|
||||
|
||||
//public void EndAutoSpawn()
|
||||
//{
|
||||
// m_autoSpawnRunning = false;
|
||||
// m_cacheClearedForAutoSpawn = false;
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8c9c9899cbf1b44297881012fe98984
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The baked mask types publicly available for selection
|
||||
/// </summary>
|
||||
public enum BakedMaskType { LayerGameObject = 2, LayerTree = 3, RadiusTag=1, RadiusTree = 0}
|
||||
|
||||
/// <summary>
|
||||
/// All possible baked mask types
|
||||
/// </summary>
|
||||
public enum BakedMaskTypeInternal { RadiusTree=0, RadiusTag=1, WorldBiomeMask=2, LayerGameObject=3, LayerTree=4 }
|
||||
[System.Serializable]
|
||||
public class CollisionMask
|
||||
{
|
||||
public bool m_active = true;
|
||||
public bool m_invert = false;
|
||||
public BakedMaskType m_type;
|
||||
//public int m_treePrototypeId= -99;
|
||||
|
||||
public string m_treeSpawnRuleGUID = "";
|
||||
public static SpawnRule[] m_allTreeSpawnRules;
|
||||
public static Spawner[] m_allTreeSpawners;
|
||||
public static string[] m_allTreeSpawnRuleNames;
|
||||
public static int[] m_allTreeSpawnRuleIndices;
|
||||
|
||||
public string m_tag;
|
||||
public float m_Radius;
|
||||
public float m_growShrinkDistance;
|
||||
public LayerMask m_layerMask;
|
||||
public string[] m_layerMaskLayerNames;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7448818c18e21947b8db42ff0a17f8c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d266a3a15d5da4140a165cb86294643f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,237 @@
|
||||
using PWCommon4;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
//This class is not a full editor class by itself, but used to collect reusable methods
|
||||
//for editing collision masks in a reorderable list.
|
||||
public class CollisionMaskListEditor : PWEditor, IPWEditor
|
||||
{
|
||||
public static float OnElementHeight(int index, CollisionMask[] collisionMasks)
|
||||
{
|
||||
return EditorGUIUtility.singleLineHeight ;
|
||||
}
|
||||
|
||||
public static CollisionMask[] OnRemoveMaskListEntry(CollisionMask[] oldList, int index)
|
||||
{
|
||||
if (index < 0 || index >= oldList.Length)
|
||||
return null;
|
||||
CollisionMask toRemove = oldList[index];
|
||||
CollisionMask[] newList = new CollisionMask[oldList.Length - 1];
|
||||
for (int i = 0; i < newList.Length; ++i)
|
||||
{
|
||||
if (i < index)
|
||||
{
|
||||
newList[i] = oldList[i];
|
||||
}
|
||||
else if (i >= index)
|
||||
{
|
||||
newList[i] = oldList[i + 1];
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public static CollisionMask[] OnAddMaskListEntry(CollisionMask[] oldList)
|
||||
{
|
||||
CollisionMask[] newList = new CollisionMask[oldList.Length + 1];
|
||||
for (int i = 0; i < oldList.Length; ++i)
|
||||
{
|
||||
newList[i] = oldList[i];
|
||||
}
|
||||
newList[newList.Length - 1] = new CollisionMask();
|
||||
return newList;
|
||||
}
|
||||
|
||||
public static bool DrawFilterListHeader(Rect rect, bool currentFoldOutState, CollisionMask[] maskList, EditorUtils editorUtils)
|
||||
{
|
||||
int oldIndent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
rect.xMin += 8f;
|
||||
bool newFoldOutState = EditorGUI.Foldout(rect, currentFoldOutState, PropertyCount("MaskRespectedCollisions", maskList, editorUtils), true);
|
||||
EditorGUI.indentLevel = oldIndent;
|
||||
return newFoldOutState;
|
||||
}
|
||||
|
||||
public static void DrawMaskList(ref bool listExpanded, ReorderableList list, EditorUtils editorUtils, Rect rect)
|
||||
{
|
||||
Rect maskRect;
|
||||
if (listExpanded)
|
||||
{
|
||||
maskRect = rect;
|
||||
list.DoList(maskRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
int oldIndent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 1;
|
||||
listExpanded = EditorGUI.Foldout(rect,listExpanded, PropertyCount("MaskRespectedCollisions", (CollisionMask[])list.list, editorUtils), true);
|
||||
maskRect = rect;
|
||||
EditorGUI.indentLevel = oldIndent;
|
||||
}
|
||||
|
||||
//editorUtils.Panel("MaskBaking", DrawMaskBaking, false);
|
||||
}
|
||||
|
||||
public static void DrawMaskListElement(Rect rect, int index, CollisionMask collisionMask, EditorUtils m_editorUtils, Terrain currentTerrain, GaiaConstants.FeatureOperation operation)
|
||||
{
|
||||
int oldIndent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
//Active Label
|
||||
Rect fieldRect = new Rect(rect.x, rect.y, rect.width * 0.1f, EditorGUIUtility.singleLineHeight);
|
||||
EditorGUI.LabelField(fieldRect, m_editorUtils.GetContent("MaskActive"));
|
||||
//Active Checkbox
|
||||
fieldRect.x += rect.width * 0.1f;
|
||||
fieldRect.width = rect.width * 0.05f;
|
||||
collisionMask.m_active = EditorGUI.Toggle(fieldRect, collisionMask.m_active);
|
||||
//Invert Label
|
||||
fieldRect.x += rect.width * 0.05f;
|
||||
fieldRect.width = rect.width * 0.1f;
|
||||
EditorGUI.LabelField(fieldRect, m_editorUtils.GetContent("MaskInvert"));
|
||||
//Invert Checkbox
|
||||
fieldRect.x += rect.width * 0.1f;
|
||||
fieldRect.width = rect.width * 0.05f;
|
||||
collisionMask.m_invert = EditorGUI.Toggle(fieldRect, collisionMask.m_invert);
|
||||
//Type dropdown
|
||||
fieldRect.x += rect.width * 0.05f;
|
||||
fieldRect.width = rect.width * 0.2f;
|
||||
BakedMaskType oldType = collisionMask.m_type;
|
||||
collisionMask.m_type = (BakedMaskType)EditorGUI.EnumPopup(fieldRect, collisionMask.m_type);
|
||||
EditorGUI.LabelField(fieldRect, m_editorUtils.GetContent("CollisionMaskTypeTooltip"));
|
||||
switch (collisionMask.m_type)
|
||||
{
|
||||
case BakedMaskType.RadiusTree:
|
||||
//Tree dropdown
|
||||
string oldTreeId = collisionMask.m_treeSpawnRuleGUID;
|
||||
fieldRect.x += rect.width * 0.2f;
|
||||
int selectedGUIDIndex = 0;
|
||||
if (collisionMask.m_treeSpawnRuleGUID != "")
|
||||
{
|
||||
SpawnRule selectedRule = CollisionMask.m_allTreeSpawnRules.FirstOrDefault(x => x.GUID == collisionMask.m_treeSpawnRuleGUID);
|
||||
if (selectedRule != null)
|
||||
{
|
||||
selectedGUIDIndex = Array.IndexOf(CollisionMask.m_allTreeSpawnRules, selectedRule);
|
||||
}
|
||||
}
|
||||
selectedGUIDIndex = EditorGUI.IntPopup(fieldRect, selectedGUIDIndex, CollisionMask.m_allTreeSpawnRuleNames, CollisionMask.m_allTreeSpawnRuleIndices);
|
||||
if (selectedGUIDIndex >= 0 && selectedGUIDIndex < CollisionMask.m_allTreeSpawnRules.Length)
|
||||
{
|
||||
collisionMask.m_treeSpawnRuleGUID = CollisionMask.m_allTreeSpawnRules[selectedGUIDIndex].GUID;
|
||||
}
|
||||
if (oldType != collisionMask.m_type || oldTreeId != collisionMask.m_treeSpawnRuleGUID)
|
||||
{
|
||||
SpawnRule selectedRule = CollisionMask.m_allTreeSpawnRules.FirstOrDefault(x => x.GUID == collisionMask.m_treeSpawnRuleGUID);
|
||||
if (selectedRule != null)
|
||||
{
|
||||
Spawner spawner = CollisionMask.m_allTreeSpawners.FirstOrDefault(x => x.m_settings.m_spawnerRules.Contains(selectedRule));
|
||||
if (spawner != null)
|
||||
{
|
||||
GameObject treePrefab = spawner.m_settings.m_resources.m_treePrototypes[selectedRule.m_resourceIdx].m_desktopPrefab;
|
||||
collisionMask.m_Radius = GaiaUtils.GetTreeRadius(treePrefab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fieldRect.x += rect.width * 0.2f;
|
||||
fieldRect.width = rect.width * 0.1f;
|
||||
collisionMask.m_Radius = EditorGUI.FloatField(fieldRect, collisionMask.m_Radius);
|
||||
fieldRect.x += rect.width * 0.1f;
|
||||
fieldRect.width = rect.width * 0.2f;
|
||||
break;
|
||||
case BakedMaskType.RadiusTag:
|
||||
//Tree dropdown
|
||||
fieldRect.x += rect.width * 0.2f;
|
||||
////Building up a value array of incrementing ints of the size of the available tags this array will then match the displayed string selection in the popup
|
||||
//int[] tagValueArray = Enumerable
|
||||
// .Repeat(0, (int)((currentTerrain.terrainData.treePrototypes.Length - 0) / 1) + 1)
|
||||
// .Select((tr, ti) => tr + (1 * ti))
|
||||
// .ToArray();
|
||||
string oldTag = collisionMask.m_tag;
|
||||
collisionMask.m_tag = EditorGUI.TagField(fieldRect, collisionMask.m_tag);
|
||||
|
||||
if (oldType != collisionMask.m_type || oldTag != collisionMask.m_tag)
|
||||
{
|
||||
collisionMask.m_Radius = GaiaUtils.GetBoundsForTaggedObject(collisionMask.m_tag);
|
||||
}
|
||||
|
||||
|
||||
fieldRect.x += rect.width * 0.2f;
|
||||
fieldRect.width = rect.width * 0.1f;
|
||||
collisionMask.m_Radius = EditorGUI.FloatField(fieldRect, collisionMask.m_Radius);
|
||||
fieldRect.x += rect.width * 0.1f;
|
||||
fieldRect.width = rect.width * 0.2f;
|
||||
break;
|
||||
case (BakedMaskType.LayerGameObject):
|
||||
//Layer mask selection
|
||||
fieldRect.x += rect.width * 0.2f;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
collisionMask.m_layerMask = GaiaEditorUtils.LayerMaskFieldRect(fieldRect, new GUIContent(""), collisionMask.m_layerMask);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
collisionMask.m_layerMaskLayerNames = GaiaUtils.LayerMaskToString(collisionMask.m_layerMask);
|
||||
}
|
||||
EditorGUI.LabelField(fieldRect, m_editorUtils.GetContent("CollisionMaskLayerSelectionTooltip"));
|
||||
fieldRect.x += rect.width * 0.2f;
|
||||
fieldRect.width = rect.width * 0.1f;
|
||||
collisionMask.m_growShrinkDistance = EditorGUI.FloatField(fieldRect, collisionMask.m_growShrinkDistance);
|
||||
EditorGUI.LabelField(fieldRect, m_editorUtils.GetContent("CollisionMaskGrowShrinkDistanceTooltip"));
|
||||
fieldRect.x += rect.width * 0.1f;
|
||||
fieldRect.width = rect.width * 0.2f;
|
||||
|
||||
break;
|
||||
case (BakedMaskType.LayerTree):
|
||||
//Layer mask selection
|
||||
fieldRect.x += rect.width * 0.2f;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
collisionMask.m_layerMask = GaiaEditorUtils.LayerMaskFieldRect(fieldRect, new GUIContent(""), collisionMask.m_layerMask);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
collisionMask.m_layerMaskLayerNames = GaiaUtils.LayerMaskToString(collisionMask.m_layerMask);
|
||||
}
|
||||
EditorGUI.LabelField(fieldRect, m_editorUtils.GetContent("CollisionMaskLayerSelectionTooltip"));
|
||||
fieldRect.x += rect.width * 0.2f;
|
||||
fieldRect.width = rect.width * 0.1f;
|
||||
collisionMask.m_growShrinkDistance = EditorGUI.FloatField(fieldRect, collisionMask.m_growShrinkDistance);
|
||||
EditorGUI.LabelField(fieldRect, m_editorUtils.GetContent("CollisionMaskGrowShrinkDistanceTooltip"));
|
||||
fieldRect.x += rect.width * 0.1f;
|
||||
fieldRect.width = rect.width * 0.2f;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (GUI.Button(fieldRect, m_editorUtils.GetContent("MaskCollisionBake")))
|
||||
{
|
||||
switch (collisionMask.m_type)
|
||||
{
|
||||
case BakedMaskType.RadiusTree:
|
||||
GaiaSessionManager.GetSessionManager().m_bakedMaskCache.BakeAllTreeCollisions(collisionMask.m_treeSpawnRuleGUID, collisionMask.m_Radius);
|
||||
break;
|
||||
case BakedMaskType.RadiusTag:
|
||||
GaiaSessionManager.GetSessionManager().m_bakedMaskCache.BakeAllTagCollisions(collisionMask.m_tag, collisionMask.m_Radius);
|
||||
break;
|
||||
case BakedMaskType.LayerGameObject:
|
||||
GaiaSessionManager.GetSessionManager().m_bakedMaskCache.BakeAllLayerGameObjectCollisions(collisionMask.m_layerMask, collisionMask.m_growShrinkDistance); //, collisionMask.m_Radius);
|
||||
break;
|
||||
case BakedMaskType.LayerTree:
|
||||
GaiaSessionManager.GetSessionManager().m_bakedMaskCache.BakeAllLayerTreeCollisions(collisionMask.m_layerMask, collisionMask.m_growShrinkDistance); //, collisionMask.m_Radius);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EditorGUI.indentLevel = oldIndent;
|
||||
}
|
||||
|
||||
public static GUIContent PropertyCount(string key, Array array, EditorUtils editorUtils)
|
||||
{
|
||||
GUIContent content = editorUtils.GetContent(key);
|
||||
content.text += " [" + array.Length + "]";
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db0b58152ca78de4d8733e0d6d9e96a6
|
||||
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,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77f4b550e21df70459ad255efe76efc8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
using Gaia.Internal;
|
||||
using PWCommon4;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Editor for Spawner settings, only offers a text & a button to create the spawner in the scene
|
||||
/// If the user wants to edit or create new spawner settings, they can do so by saving a spawner settings file from a spawner directly.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(MaskMapExportSettings))]
|
||||
public class MaskMapExportSettingsEditor : PWEditor
|
||||
{
|
||||
private EditorUtils m_editorUtils;
|
||||
private MaskMapExportSettings m_maskMapExportSettings;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
//Init editor utils
|
||||
if (m_editorUtils == null)
|
||||
{
|
||||
// Get editor utils for this
|
||||
m_editorUtils = PWApp.GetEditorUtils(this);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
#if GAIA_PRO_PRESENT
|
||||
m_editorUtils.Initialize(); // Do not remove this!
|
||||
m_maskMapExportSettings = (MaskMapExportSettings)target;
|
||||
|
||||
string message = m_editorUtils.GetTextValue("Intro"); ;
|
||||
EditorGUILayout.HelpBox(message, MessageType.Info, true);
|
||||
if (m_editorUtils.Button("AddToScene"))
|
||||
{
|
||||
GameObject sessionTempObj = GaiaUtils.GetTempSessionToolsObject();
|
||||
GameObject maskMapExporterObj = new GameObject("Mask Map Exporter");
|
||||
maskMapExporterObj.transform.parent = sessionTempObj.transform;
|
||||
MaskMapExport maskMapExport = maskMapExporterObj.AddComponent<MaskMapExport>();
|
||||
maskMapExport.LoadSettings(m_maskMapExportSettings);
|
||||
}
|
||||
m_editorUtils.Heading("Stored Settings");
|
||||
DrawDefaultInspector();
|
||||
// Update is called once per frame
|
||||
#else
|
||||
string message = m_editorUtils.GetTextValue("GaiaProInfo"); ;
|
||||
EditorGUILayout.HelpBox(message, MessageType.Info, true);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30ba11a1990dc644fa9dff1a136e2cdc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores noise settings for the noise image mask type for proper serialization.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class GaiaNoiseSettings
|
||||
{
|
||||
public Vector3 m_translation;
|
||||
public Vector3 m_rotation;
|
||||
public Vector3 m_scale = new Vector3(10f,1,10f);
|
||||
public string m_noiseTypeName = "Perlin";
|
||||
public string m_noiseTypeParams;
|
||||
public string m_fractalTypeName = "Fbm";
|
||||
public string m_fractalTypeParams;
|
||||
//public float m_octaves;
|
||||
//public float m_amplitude;
|
||||
//public float m_persistence;
|
||||
//public float m_frequency;
|
||||
//public float m_lacunarity;
|
||||
public bool m_warpEnabled;
|
||||
public float m_warpIterations;
|
||||
public float m_warpStrength;
|
||||
public Vector4 m_warpOffset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c166f0fa91498f347a4e8202a5d7e85d
|
||||
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,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a071855fccfc2224585b0c809f670de7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
public class ImageProcessing
|
||||
{
|
||||
|
||||
|
||||
//static RenderTexture outputTexture;
|
||||
|
||||
/// <summary>
|
||||
/// Applies a stack of masks in an array on a render texture to get a combined final mask.
|
||||
/// </summary>
|
||||
/// <param name="inputTexture">The input render texture</param>
|
||||
/// <param name="maskStack">An array of ImageMasks to apply on the render texture.</param>
|
||||
/// <returns>A modified render texture containing the results of the filter application.</returns>
|
||||
public static RenderTexture ApplyMaskStack(RenderTexture inputTexture, RenderTexture outputTexture, ImageMask[] maskStack, ImageMaskInfluence influence)
|
||||
{
|
||||
//early out if no valid masks to begin with
|
||||
if (maskStack.Where(x=>x.m_active==true && x.m_influence == influence).Count() <=0)
|
||||
{
|
||||
return inputTexture;
|
||||
}
|
||||
|
||||
//RenderTexture outputTexture = null;
|
||||
|
||||
for (int i = 0; i < maskStack.Length; i++)
|
||||
{
|
||||
if (maskStack[i].m_active && maskStack[i].m_influence == influence)
|
||||
{
|
||||
////release old texture first before assigning new
|
||||
//if (outputTexture != null)
|
||||
//{
|
||||
// RenderTexture.ReleaseTemporary(outputTexture);
|
||||
// outputTexture = null;
|
||||
//}
|
||||
|
||||
outputTexture = maskStack[i].Apply(inputTexture, outputTexture);
|
||||
|
||||
//Write the result texture back to the input so we can use the result
|
||||
//of this iteration as input for the next, and so on.
|
||||
Graphics.Blit(outputTexture, inputTexture);
|
||||
}
|
||||
}
|
||||
|
||||
if (inputTexture != null)
|
||||
{
|
||||
RenderTexture.ReleaseTemporary(inputTexture);
|
||||
inputTexture = null;
|
||||
}
|
||||
|
||||
|
||||
return outputTexture;
|
||||
}
|
||||
|
||||
|
||||
///// <summary>
|
||||
///// Outputs a Render texture as a .png file
|
||||
///// </summary>
|
||||
///// <param name="path">The path to write to, including filename ending in .exr</param>
|
||||
///// <param name="sourceRenderTexture">The render texture to export</param>
|
||||
//public static void WriteRenderTexturePNG(string path, RenderTexture sourceRenderTexture, TextureFormat textureFormat = TextureFormat.RGBA32)
|
||||
//{
|
||||
// RenderTexture origTex = RenderTexture.active;
|
||||
// RenderTexture.active = sourceRenderTexture;
|
||||
// Texture2D exportTexture = new Texture2D(RenderTexture.active.width, RenderTexture.active.height, textureFormat, false);
|
||||
// exportTexture.ReadPixels(new Rect(0, 0, RenderTexture.active.width, RenderTexture.active.height), 0, 0);
|
||||
// exportTexture.Apply();
|
||||
// byte[] exrBytes = ImageConversion.EncodeToPNG(exportTexture);
|
||||
// PWCommon4.Utils.WriteAllBytes(path, exrBytes);
|
||||
// RenderTexture.active = origTex;
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a Render texture to different file formats (default: .exr file)
|
||||
/// </summary>
|
||||
/// <param name="path">The path to write to, without the extension. The correct extension will be added according to the chosen imageFileType.</param>
|
||||
/// <param name="sourceRenderTexture">The render texture to export</param>
|
||||
/// <param name="imageFileType">Image File Type: EXR, PNG, TGA or JPG</param>
|
||||
/// <param name="textureFormat">Texture color format for the temporary Texture 2D to read the render texture into for exporting.</param>
|
||||
/// <returns>The full path to the exported file.</returns>
|
||||
public static string WriteRenderTexture(string path, RenderTexture sourceRenderTexture, GaiaConstants.ImageFileType imageFileType = GaiaConstants.ImageFileType.Exr, TextureFormat textureFormat = TextureFormat.RGBAFloat, int jpgQuality=75)
|
||||
{
|
||||
RenderTexture origTex = RenderTexture.active;
|
||||
RenderTexture.active = sourceRenderTexture;
|
||||
Texture2D exportTexture = new Texture2D(RenderTexture.active.width, RenderTexture.active.height, textureFormat, false);
|
||||
exportTexture.ReadPixels(new Rect(0, 0, RenderTexture.active.width, RenderTexture.active.height), 0, 0);
|
||||
exportTexture.Apply();
|
||||
byte[] fileBytes = new byte[0];
|
||||
string extension = ".file";
|
||||
switch(imageFileType)
|
||||
{
|
||||
case GaiaConstants.ImageFileType.Exr:
|
||||
fileBytes = ImageConversion.EncodeToEXR(exportTexture, Texture2D.EXRFlags.CompressZIP);
|
||||
extension = ".exr";
|
||||
break;
|
||||
case GaiaConstants.ImageFileType.Png:
|
||||
fileBytes = ImageConversion.EncodeToPNG(exportTexture);
|
||||
extension = ".png";
|
||||
break;
|
||||
case GaiaConstants.ImageFileType.Tga:
|
||||
fileBytes = ImageConversion.EncodeToTGA(exportTexture);
|
||||
extension = ".tga";
|
||||
break;
|
||||
case GaiaConstants.ImageFileType.Jpg:
|
||||
fileBytes = ImageConversion.EncodeToJPG(exportTexture,jpgQuality);
|
||||
extension = ".jpg";
|
||||
break;
|
||||
|
||||
}
|
||||
path += extension;
|
||||
PWCommon4.Utils.WriteAllBytes(path, fileBytes);
|
||||
RenderTexture.active = origTex;
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a Texture2D as a .png file for debug purposes
|
||||
/// </summary>
|
||||
/// <param name="path">The path to write to, including filename ending in .png</param>
|
||||
/// <param name="sourceTexture">The texture to export</param>
|
||||
public static void WriteTexture2D(string path, Texture2D sourceTexture)
|
||||
{
|
||||
byte[] exrBytes = ImageConversion.EncodeToPNG(sourceTexture);
|
||||
if (exrBytes != null)
|
||||
{
|
||||
PWCommon4.Utils.WriteAllBytes(path, exrBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static void BakeMaskStack(ImageMask[] maskStack, Terrain terrain, Transform transform, float range, int resolution, string path)
|
||||
{
|
||||
//Simulate an operation to allow the image masks to acces the current terrain data
|
||||
GaiaMultiTerrainOperation operation = new GaiaMultiTerrainOperation(terrain, transform, range);
|
||||
operation.GetHeightmap();
|
||||
operation.GetNormalmap();
|
||||
operation.CollectTerrainBakedMasks();
|
||||
|
||||
float maxCurrentTerrainHeight = 0f;
|
||||
float minCurrentTerrainHeight = 0f;
|
||||
float seaLevel;
|
||||
|
||||
GaiaSessionManager gsm = GaiaSessionManager.GetSessionManager();
|
||||
gsm.GetWorldMinMax(ref minCurrentTerrainHeight, ref maxCurrentTerrainHeight);
|
||||
seaLevel = gsm.GetSeaLevel();
|
||||
|
||||
if (maskStack.Length > 0)
|
||||
{
|
||||
//We start from a white texture, so we need the first mask action in the stack to always be "Multiply", otherwise there will be no result.
|
||||
maskStack[0].m_blendMode = ImageMaskBlendMode.Multiply;
|
||||
|
||||
//Iterate through all image masks and set up the required data that masks might need to function properly
|
||||
foreach (ImageMask mask in maskStack)
|
||||
{
|
||||
//mask.m_heightmapContext = heightmapContext;
|
||||
//mask.m_normalmapContext = normalmapContext;
|
||||
//mask.m_collisionContext = collisionContext;
|
||||
mask.m_multiTerrainOperation = operation;
|
||||
mask.m_seaLevel = seaLevel;
|
||||
mask.m_maxWorldHeight = maxCurrentTerrainHeight;
|
||||
mask.m_minWorldHeight = minCurrentTerrainHeight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RenderTexture inputTexture = RenderTexture.GetTemporary(resolution, resolution, 0,RenderTextureFormat.ARGBFloat);
|
||||
RenderTexture currentRT = RenderTexture.active;
|
||||
RenderTexture.active = inputTexture;
|
||||
GL.Clear(true, true, Color.white);
|
||||
RenderTexture.active = currentRT;
|
||||
RenderTexture localOutputTexture = RenderTexture.GetTemporary(inputTexture.descriptor);
|
||||
RenderTexture globalOutputTexture = RenderTexture.GetTemporary(inputTexture.descriptor);
|
||||
localOutputTexture = ImageProcessing.ApplyMaskStack(inputTexture, localOutputTexture, maskStack, ImageMaskInfluence.Local);
|
||||
globalOutputTexture = ImageProcessing.ApplyMaskStack(localOutputTexture, globalOutputTexture, maskStack, ImageMaskInfluence.Global);
|
||||
|
||||
WriteRenderTexture(path, globalOutputTexture);
|
||||
|
||||
RenderTexture.ReleaseTemporary(inputTexture);
|
||||
RenderTexture.ReleaseTemporary(localOutputTexture);
|
||||
RenderTexture.ReleaseTemporary(globalOutputTexture);
|
||||
inputTexture = null;
|
||||
localOutputTexture = null;
|
||||
globalOutputTexture = null;
|
||||
operation.CloseOperation();
|
||||
|
||||
}
|
||||
|
||||
public static Texture2D CreateMaskCurveTexture(ref Texture2D inputCurveTexture)
|
||||
{
|
||||
if (inputCurveTexture == null)
|
||||
{
|
||||
TextureFormat format = TextureFormat.RGB24;
|
||||
if (SystemInfo.SupportsTextureFormat(TextureFormat.RFloat))
|
||||
format = TextureFormat.RFloat;
|
||||
else if (SystemInfo.SupportsTextureFormat(TextureFormat.RHalf))
|
||||
format = TextureFormat.RHalf;
|
||||
|
||||
inputCurveTexture = new Texture2D(256, 1, format, false, true)
|
||||
{
|
||||
name = "Height Mask curve texture",
|
||||
wrapMode = TextureWrapMode.Clamp,
|
||||
filterMode = FilterMode.Bilinear,
|
||||
anisoLevel = 0,
|
||||
hideFlags = HideFlags.DontSave
|
||||
};
|
||||
}
|
||||
|
||||
return inputCurveTexture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bakes an animation curve into a 1 pixel high black and white texture that represents the curve contents. This texture is intended for use as shader input
|
||||
/// </summary>
|
||||
/// <param name="animationCurve">The curve to bake.</param>
|
||||
/// <param name="bakedTexture">The Texture2D to bake into, needs to be 1 pixel high, 256 pixels wide.</param>
|
||||
public static void BakeCurveTexture(AnimationCurve animationCurve, Texture2D bakedTexture)
|
||||
{
|
||||
if (animationCurve != null && animationCurve.length > 0)
|
||||
{
|
||||
float range = animationCurve[animationCurve.length - 1].time;
|
||||
for (float i = 0f; i <= 1f; i += 1f / 255f)
|
||||
{
|
||||
float c = animationCurve.Evaluate(i * range);
|
||||
bakedTexture.SetPixel(Mathf.FloorToInt(i * 255f), 0, new Color(c, c, c));
|
||||
}
|
||||
bakedTexture.Apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08a59090a6cda664c9606858e8c61b3b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright © 2018 Procedural Worlds Pty Limited. All Rights Reserved.
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using static Gaia.GaiaConstants;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
public enum MaskMapExportMultiTerrainOption { SeparateTextures, OneCombinedTexture }
|
||||
/*
|
||||
* Scriptable Object containing mask map export settings
|
||||
*/
|
||||
|
||||
namespace Gaia
|
||||
{
|
||||
[System.Serializable]
|
||||
public class MaskMapChannelSettings
|
||||
{
|
||||
public bool m_channelIsFoldedOut = true;
|
||||
public bool m_channelIsActive = true;
|
||||
public string m_channelName;
|
||||
public Color m_visualisationColor;
|
||||
}
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public class MaskMapExportSettings : ScriptableObject, ISerializationCallbackReceiver
|
||||
{
|
||||
public MaskMapChannelSettings m_redChannelSettings = new MaskMapChannelSettings() { m_channelName = "Red Channel", m_visualisationColor = Color.red};
|
||||
public MaskMapChannelSettings m_greenChannelSettings = new MaskMapChannelSettings() { m_channelName = "Green Channel", m_visualisationColor = Color.green };
|
||||
public MaskMapChannelSettings m_blueChannelSettings = new MaskMapChannelSettings() { m_channelName = "Blue Channel", m_visualisationColor = Color.blue };
|
||||
public MaskMapChannelSettings m_alphaChannelSettings = new MaskMapChannelSettings() { m_channelName = "Alpha Channel", m_visualisationColor = Color.magenta };
|
||||
|
||||
|
||||
public float m_range = 1024;
|
||||
public string m_exportDirectory = "Assets/Gaia User Data/Gaia Exports";
|
||||
public string m_exportFileName = "MaskMap";
|
||||
public MaskMapExportMultiTerrainOption m_multiTerrainOption = MaskMapExportMultiTerrainOption.SeparateTextures;
|
||||
public int m_combinedTextureResolution = 2048;
|
||||
public bool m_addTerrainNameToFileName = true;
|
||||
public GaiaConstants.ImageFileType m_exportFileType = ImageFileType.Exr;
|
||||
public int m_exportJpgQuality = 75;
|
||||
public string lastSavePath;
|
||||
public float m_x;
|
||||
public float m_y;
|
||||
public float m_z;
|
||||
|
||||
|
||||
[SerializeField]
|
||||
private ImageMask[] red_imageMasks = new ImageMask[0];
|
||||
|
||||
//Using a property to make sure the image mask list is always initialized
|
||||
//<summary>All image filters that are being applied in this spawning process</summary>
|
||||
|
||||
public ImageMask[] m_red_imageMasks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (red_imageMasks == null)
|
||||
{
|
||||
red_imageMasks = new ImageMask[0];
|
||||
}
|
||||
return red_imageMasks;
|
||||
}
|
||||
set
|
||||
{
|
||||
red_imageMasks = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[SerializeField]
|
||||
private ImageMask[] green_imageMasks = new ImageMask[0];
|
||||
|
||||
//Using a property to make sure the image mask list is always initialized
|
||||
//<summary>All image filters that are being applied in this spawning process</summary>
|
||||
|
||||
public ImageMask[] m_green_imageMasks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (green_imageMasks == null)
|
||||
{
|
||||
green_imageMasks = new ImageMask[0];
|
||||
}
|
||||
return green_imageMasks;
|
||||
}
|
||||
set
|
||||
{
|
||||
green_imageMasks = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private ImageMask[] blue_imageMasks = new ImageMask[0];
|
||||
|
||||
//Using a property to make sure the image mask list is always initialized
|
||||
//<summary>All image filters that are being applied in this spawning process</summary>
|
||||
|
||||
public ImageMask[] m_blue_imageMasks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (blue_imageMasks == null)
|
||||
{
|
||||
blue_imageMasks = new ImageMask[0];
|
||||
}
|
||||
return blue_imageMasks;
|
||||
}
|
||||
set
|
||||
{
|
||||
blue_imageMasks = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[SerializeField]
|
||||
private ImageMask[] alpha_imageMasks = new ImageMask[0];
|
||||
|
||||
|
||||
public bool m_readWriteEnabled = true;
|
||||
|
||||
//Using a property to make sure the image mask list is always initialized
|
||||
//<summary>All image filters that are being applied in this spawning process</summary>
|
||||
|
||||
public ImageMask[] m_alpha_imageMasks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (alpha_imageMasks == null)
|
||||
{
|
||||
alpha_imageMasks = new ImageMask[0];
|
||||
}
|
||||
return alpha_imageMasks;
|
||||
}
|
||||
set
|
||||
{
|
||||
alpha_imageMasks = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes References to Texture2Ds in Image masks. The image mask will still remember the GUID of that texture to load it when needed.
|
||||
/// Call this when you are "done" with the mask map export settings to free up memory caused by these references.
|
||||
/// </summary>
|
||||
public void ClearImageMaskTextures()
|
||||
{
|
||||
foreach (ImageMask im in m_red_imageMasks)
|
||||
{
|
||||
im.FreeTextureReferences();
|
||||
}
|
||||
foreach (ImageMask im in m_green_imageMasks)
|
||||
{
|
||||
im.FreeTextureReferences();
|
||||
}
|
||||
foreach (ImageMask im in m_blue_imageMasks)
|
||||
{
|
||||
im.FreeTextureReferences();
|
||||
}
|
||||
foreach (ImageMask im in m_alpha_imageMasks)
|
||||
{
|
||||
im.FreeTextureReferences();
|
||||
}
|
||||
|
||||
Resources.UnloadUnusedAssets();
|
||||
}
|
||||
|
||||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnBeforeSerialize()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36c16d09d4555244e9d178fb672944ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user