756 lines
30 KiB
C#
756 lines
30 KiB
C#
|
|
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using UnityEngine.Splines;
|
|
|
|
namespace JBooth.MicroVerseCore
|
|
{
|
|
public class SplinePath : Stamp, IHeightModifier, ITextureModifier
|
|
{
|
|
public enum CombineMode
|
|
{
|
|
Override = 0,
|
|
Max = 1,
|
|
Min = 2,
|
|
Blend = 9,
|
|
}
|
|
public CombineMode heightBlendMode = CombineMode.Override;
|
|
public enum SDFRes
|
|
{
|
|
k256 = 256,
|
|
k512 = 512,
|
|
k1024 = 1024,
|
|
k2048 = 2048
|
|
}
|
|
|
|
public enum SearchQuality
|
|
{
|
|
VeryLow = 64,
|
|
Low = 128,
|
|
Medium = 256,
|
|
High = 512,
|
|
VeryHigh = 1024,
|
|
ExtremelyHigh = 2048
|
|
}
|
|
|
|
[HideInInspector] public SplineRenderer.RenderDesc[] multiSpline;
|
|
|
|
public SplineContainer spline;
|
|
[Tooltip("When true, a closed spline is treated as an area for the effect instead of following the path")]
|
|
|
|
public Noise positionNoise = new Noise();
|
|
public Noise widthNoise = new Noise();
|
|
|
|
[Tooltip("Blend between existing height map and new one")]
|
|
[Range(0, 1)] public float blend = 1;
|
|
|
|
public bool treatAsSplineArea;
|
|
[Tooltip("Resolution of the internal SDF used for the spline. Higher makes edits take longer")]
|
|
public SDFRes sdfRes = SDFRes.k512;
|
|
[Tooltip("Higher values will spend more time finding the closest point on the spline, improving quality but increasing update times")]
|
|
public SearchQuality searchQuality = SearchQuality.Medium;
|
|
[Tooltip("Should the heightmap be adjusted to match the spline")]
|
|
public bool modifyHeightMap = true;
|
|
[Tooltip("Width of the area")]
|
|
public float width = 1;
|
|
[Tooltip("How many units should it be before the effect is gone")]
|
|
public float smoothness = 2;
|
|
[Tooltip("Positive values push the terrain down, negative up")]
|
|
public float trench = 0;
|
|
public AnimationCurve trenchCurve = AnimationCurve.Constant(0, 1, 0);
|
|
public bool useTrenchCurve;
|
|
public Noise heightNoise = new Noise();
|
|
public Easing embankmentEasing = new Easing();
|
|
public Noise embankmentNoise = new Noise();
|
|
|
|
public bool useTextureCurve;
|
|
public bool useDetailCurve;
|
|
public bool useTreeCurve;
|
|
public AnimationCurve textureCurve = AnimationCurve.EaseInOut(0, 1, 1, 0);
|
|
public AnimationCurve treeCurve = AnimationCurve.EaseInOut(0, 1, 1, 0);
|
|
public AnimationCurve detailCurve = AnimationCurve.EaseInOut(0, 1, 1, 0);
|
|
|
|
[Tooltip("Allows you to texture the area of the spline with a terrain layer")]
|
|
public bool modifySplatMap = true;
|
|
public TerrainLayer layer;
|
|
[Tooltip("Width of texturing effect")]
|
|
[Range(0,1)]public float splatWeight = 1;
|
|
public float splatWidth = 1;
|
|
[Tooltip("How many units should it be before the effect is gone")]
|
|
public float splatSmoothness = 2;
|
|
public Noise splatNoise = new Noise();
|
|
[Tooltip("Texture the area of the spline's falloff with a separate texture")]
|
|
public TerrainLayer embankmentLayer;
|
|
|
|
[Tooltip("When true, tree's will not appear on the path")]
|
|
public bool clearTrees = true;
|
|
[Tooltip("Width of tree clearing effect")]
|
|
public float treeWidth = 1;
|
|
[Tooltip("Falloff of tree clearing effect")]
|
|
public float treeSmoothness = 3;
|
|
|
|
[Tooltip("When true, detail objects will not appear on the path")]
|
|
public bool clearDetails = true;
|
|
[Tooltip("Width of detail clearing effect")]
|
|
public float detailWidth = 1;
|
|
[Tooltip("falloff of detail clearing effect")]
|
|
public float detailSmoothness = 3;
|
|
|
|
[Tooltip("When true, objects will not appear on the path")]
|
|
public bool clearObjects = false;
|
|
[Tooltip("Width of detail clearing effect")]
|
|
public float objectWidth = 1;
|
|
[Tooltip("falloff of detail clearing effect")]
|
|
public float objectSmoothness = 3;
|
|
|
|
[Tooltip("Will prevent future things from modifying heights")]
|
|
public bool occludeHeightMod = false;
|
|
[Tooltip("Width of detail clearing effect")]
|
|
public float occludeHeightWidth = 1;
|
|
[Tooltip("falloff of detail clearing effect")]
|
|
public float occludeHeightSmoothness = 3;
|
|
[Tooltip("Will prevent future things from modifying splats")]
|
|
public bool occludeTextureMod = false;
|
|
[Tooltip("Width of detail clearing effect")]
|
|
public float occludeTextureWidth = 1;
|
|
[Tooltip("falloff of detail clearing effect")]
|
|
public float occludeTextureSmoothness = 3;
|
|
|
|
[Tooltip("Curve to use when interpolating the width of the spline")]
|
|
public Easing splineWidthEasing = new Easing();
|
|
|
|
static Material heightMat;
|
|
static Material splatMat;
|
|
|
|
float ComputeMaxSDF()
|
|
{
|
|
float val = 0;
|
|
if (modifyHeightMap)
|
|
val = width + smoothness;
|
|
if (modifySplatMap)
|
|
val = Mathf.Max(val, splatWidth + splatSmoothness);
|
|
if (clearTrees)
|
|
val = Mathf.Max(val, treeWidth + treeSmoothness);
|
|
if (clearDetails)
|
|
val = Mathf.Max(val, detailWidth + detailSmoothness);
|
|
if (occludeHeightMod)
|
|
val = Mathf.Max(val, occludeHeightSmoothness + occludeHeightWidth);
|
|
if (occludeTextureMod)
|
|
val = Mathf.Max(val, occludeTextureWidth + occludeTextureSmoothness);
|
|
if (splineWidths != null)
|
|
{
|
|
float mw = 0;
|
|
foreach (var sw in splineWidths)
|
|
{
|
|
foreach (var w in sw.widthData)
|
|
{
|
|
if (w.Value > mw)
|
|
mw = w.Value;
|
|
}
|
|
}
|
|
val += mw;
|
|
}
|
|
return val + 3; // lets make sure it's at least something..
|
|
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class SplineWidthData
|
|
{
|
|
public SplineData<float> widthData = new SplineData<float>();
|
|
}
|
|
|
|
public List<SplineWidthData> splineWidths = new List<SplineWidthData>();
|
|
|
|
RenderBuffer[] multipleRenderBuffers;
|
|
|
|
public bool NeedCurvatureMap() { return false; }
|
|
public bool NeedFlowMap() { return false; }
|
|
|
|
Dictionary<Terrain, SplineRenderer> splineRenderers = new Dictionary<Terrain, SplineRenderer>();
|
|
|
|
public override void OnEnable()
|
|
{
|
|
if (spline == null)
|
|
{
|
|
spline = GetComponent<SplineContainer>();
|
|
}
|
|
base.OnEnable();
|
|
|
|
}
|
|
|
|
public void ClearSplineRenders(Bounds? bounds = null)
|
|
{
|
|
if (bounds == null)
|
|
{
|
|
foreach (var sr in splineRenderers.Values)
|
|
{
|
|
sr.Dispose();
|
|
}
|
|
splineRenderers.Clear();
|
|
}
|
|
else
|
|
{
|
|
var b = bounds.Value;
|
|
b.max = new Vector3(b.max.x, 100000, b.max.z);
|
|
b.min = new Vector3(b.min.x, -100000, b.min.z);
|
|
b.Expand(this.ComputeMaxSDF());
|
|
List<Terrain> toClear = new List<Terrain>();
|
|
foreach (var t in splineRenderers.Keys)
|
|
{
|
|
if (TerrainUtil.ComputeTerrainBounds(t).Intersects(b))
|
|
{
|
|
toClear.Add(t);
|
|
}
|
|
}
|
|
foreach (var t in toClear)
|
|
{
|
|
splineRenderers[t].Dispose();
|
|
splineRenderers.Remove(t);
|
|
}
|
|
}
|
|
ClearCachedBounds();
|
|
}
|
|
|
|
SplineRenderer GetSplineRenderer(Terrain terrain)
|
|
{
|
|
if (splineRenderers.ContainsKey(terrain))
|
|
{
|
|
var sr = splineRenderers[terrain];
|
|
var mx = ComputeMaxSDF();
|
|
if (sr.lastMaxSDF < mx)
|
|
{
|
|
if (multiSpline != null)
|
|
{
|
|
sr.Render(multiSpline, terrain, (int)sdfRes, mx, (int)searchQuality);
|
|
}
|
|
else if (spline != null)
|
|
{
|
|
sr.Render(spline, terrain, positionNoise, widthNoise, splineWidths, splineWidthEasing, (int)sdfRes, mx, (int)searchQuality);
|
|
}
|
|
}
|
|
return sr;
|
|
}
|
|
else
|
|
{
|
|
var terrainBounds = TerrainUtil.ComputeTerrainBounds(terrain);
|
|
if (terrainBounds.Intersects(GetBounds()))
|
|
{
|
|
SplineRenderer sr = new SplineRenderer();
|
|
bounds = new Bounds(Vector3.zero, Vector3.zero);
|
|
if (multiSpline != null)
|
|
{
|
|
sr.Render(multiSpline, terrain, (int)sdfRes, ComputeMaxSDF(), (int)searchQuality);
|
|
}
|
|
else if (spline != null)
|
|
{
|
|
sr.Render(spline, terrain, positionNoise, widthNoise, splineWidths, splineWidthEasing, (int)sdfRes, ComputeMaxSDF(), (int)searchQuality);
|
|
}
|
|
|
|
splineRenderers.Add(terrain, sr);
|
|
return sr;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void UpdateSplineSDFs()
|
|
{
|
|
ClearSplineRenders();
|
|
if (MicroVerse.instance == null)
|
|
return;
|
|
MicroVerse.instance.SyncTerrainList();
|
|
foreach (var terrain in MicroVerse.instance.terrains)
|
|
{
|
|
GetSplineRenderer(terrain);
|
|
}
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
if (heightMat == null)
|
|
{
|
|
heightMat = new Material(Shader.Find("Hidden/MicroVerse/SplinePathHeight"));
|
|
}
|
|
if (splatMat == null)
|
|
{
|
|
splatMat = new Material(Shader.Find("Hidden/MicroVerse/SplinePathTexture"));
|
|
}
|
|
if (multipleRenderBuffers == null)
|
|
{
|
|
multipleRenderBuffers = new RenderBuffer[2];
|
|
}
|
|
}
|
|
int mainChannelIndex = -1;
|
|
int embankmentChannelIndex;
|
|
|
|
public override void OnDisable()
|
|
{
|
|
base.OnDisable();
|
|
ClearSplineRenders();
|
|
}
|
|
protected override void OnDestroy()
|
|
{
|
|
if (heightMat != null) DestroyImmediate(heightMat);
|
|
if (splatMat != null) DestroyImmediate(splatMat);
|
|
if (sdfToMaskMat != null) DestroyImmediate(sdfToMaskMat);
|
|
ClearSplineRenders();
|
|
base.OnDestroy();
|
|
}
|
|
|
|
|
|
static int _SplineSDF = Shader.PropertyToID("_SplineSDF");
|
|
static int _TerrainHeight = Shader.PropertyToID("_TerrainHeight");
|
|
static int _TreeWidth = Shader.PropertyToID("_TreeWidth");
|
|
static int _Channel = Shader.PropertyToID("_Channel");
|
|
static int _TreeSmoothness = Shader.PropertyToID("_TreeSmoothness");
|
|
static int _DetailWidth = Shader.PropertyToID("_DetailWidth");
|
|
static int _DetailSmoothness = Shader.PropertyToID("_DetailSmoothness");
|
|
static int _SplatWidth = Shader.PropertyToID("_SplatWidth");
|
|
static int _SplatSmoothness = Shader.PropertyToID("_SplatSmoothness");
|
|
static int _WeightMap = Shader.PropertyToID("_WeightMap");
|
|
static int _IndexMap = Shader.PropertyToID("_IndexMap");
|
|
static int _AlphaMapSize = Shader.PropertyToID("_AlphaMapSize");
|
|
static int _SplatWeight = Shader.PropertyToID("_SplatWeight");
|
|
static int _HeightMapSize = Shader.PropertyToID("_HeightMapSize");
|
|
static int _Blend = Shader.PropertyToID("_Blend");
|
|
static Shader sdfToMaskShader = null;
|
|
static Material sdfToMaskMat = null;
|
|
public bool ApplyHeightStamp(RenderTexture source, RenderTexture dest,
|
|
HeightmapData heightmapData, OcclusionData od)
|
|
{
|
|
bool ret = false;
|
|
|
|
keywordBuilder.Clear();
|
|
SplineRenderer sr = GetSplineRenderer(od.terrain);
|
|
if (sr != null)
|
|
{
|
|
if (modifyHeightMap)
|
|
{
|
|
PrepareMaterial(heightMat, heightmapData, keywordBuilder.keywords);
|
|
|
|
heightMat.SetTexture(_SplineSDF, sr.splineSDF);
|
|
heightMat.SetFloat(_TerrainHeight, od.terrain.transform.position.y);
|
|
heightMat.SetFloat(_HeightMapSize, source.width);
|
|
keywordBuilder.Assign(heightMat);
|
|
Graphics.Blit(source, dest, heightMat);
|
|
heightMat.SetFloat(_Blend, blend);
|
|
ret = true;
|
|
}
|
|
|
|
if (clearTrees || clearDetails || occludeHeightMod || occludeTextureMod)
|
|
{
|
|
if (sdfToMaskShader == null)
|
|
{
|
|
sdfToMaskShader = Shader.Find("Hidden/MicroVerse/SDFToMask");
|
|
}
|
|
if (sdfToMaskMat == null)
|
|
{
|
|
sdfToMaskMat = new Material(sdfToMaskShader);
|
|
}
|
|
sdfToMaskMat.DisableKeyword("_TREATASAREA");
|
|
if (treatAsSplineArea)
|
|
{
|
|
sdfToMaskMat.EnableKeyword("_TREATASAREA");
|
|
}
|
|
sdfToMaskMat.SetFloat(_HeightWidth, occludeHeightMod ? occludeHeightWidth : -1);
|
|
sdfToMaskMat.SetFloat(_HeightSmoothness, occludeHeightSmoothness);
|
|
sdfToMaskMat.SetFloat(_SplatWidth, occludeTextureMod ? occludeTextureWidth : -1);
|
|
sdfToMaskMat.SetFloat(_SplatSmoothness, occludeTextureSmoothness);
|
|
sdfToMaskMat.SetFloat(_TreeWidth, clearTrees ? treeWidth : -1);
|
|
sdfToMaskMat.SetFloat(_TreeSmoothness, treeSmoothness);
|
|
sdfToMaskMat.SetFloat(_DetailWidth, clearDetails ? detailWidth : -1);
|
|
sdfToMaskMat.SetFloat(_DetailSmoothness, detailSmoothness);
|
|
|
|
sdfToMaskMat.SetTexture(_SplineSDF, sr.splineSDF);
|
|
|
|
sdfToMaskMat.DisableKeyword("_SPLINECURVETREEWEIGHT");
|
|
sdfToMaskMat.DisableKeyword("_SPLINECURVEDETAILWEIGHT");
|
|
if (useTreeCurve)
|
|
{
|
|
sdfToMaskMat.EnableKeyword("_SPLINECURVETREEWEIGHT");
|
|
UpdateCachedTreeWeight();
|
|
sdfToMaskMat.SetTexture("_SplineTreeWeight", cachedSplineTreeWeight);
|
|
}
|
|
|
|
if (useDetailCurve)
|
|
{
|
|
sdfToMaskMat.EnableKeyword("_SPLINECURVEDETAILWEIGHT");
|
|
UpdateCachedDetailWeight();
|
|
sdfToMaskMat.SetTexture("_SplineDetailWeight", cachedSplineDetailWeight);
|
|
}
|
|
|
|
var rt = RenderTexture.GetTemporary(od.terrainMask.descriptor);
|
|
rt.name = "SplinePath::OcclusionRender";
|
|
rt.wrapMode = TextureWrapMode.Clamp;
|
|
|
|
Graphics.Blit(od.terrainMask, rt, sdfToMaskMat);
|
|
RenderTexture.active = null;
|
|
RenderTexture.ReleaseTemporary(od.terrainMask);
|
|
od.terrainMask = rt;
|
|
RenderTexture.active = dest;
|
|
}
|
|
if (clearObjects)
|
|
{
|
|
if (sdfToMaskShader == null)
|
|
{
|
|
sdfToMaskShader = Shader.Find("Hidden/MicroVerse/SDFToMask");
|
|
}
|
|
if (sdfToMaskMat == null)
|
|
{
|
|
sdfToMaskMat = new Material(sdfToMaskShader);
|
|
}
|
|
sdfToMaskMat.DisableKeyword("_TREATASAREA");
|
|
sdfToMaskMat.SetFloat(_HeightWidth, objectWidth);
|
|
sdfToMaskMat.SetFloat(_HeightSmoothness, objectSmoothness);
|
|
|
|
sdfToMaskMat.SetTexture(_SplineSDF, sr.splineSDF);
|
|
|
|
var rt = RenderTexture.GetTemporary(od.objectMask.descriptor);
|
|
rt.name = "SplinePath::OcclusionRender";
|
|
rt.wrapMode = TextureWrapMode.Clamp;
|
|
|
|
Graphics.Blit(od.objectMask, rt, sdfToMaskMat);
|
|
RenderTexture.active = null;
|
|
RenderTexture.ReleaseTemporary(od.objectMask);
|
|
od.objectMask = rt;
|
|
RenderTexture.active = dest;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Texture2D cachedSplineTextureWeight;
|
|
Texture2D cachedSplineTreeWeight;
|
|
Texture2D cachedSplineDetailWeight;
|
|
Texture2D cachedSplineTrenchWeight;
|
|
|
|
|
|
public void ClearCachedSplineTextureCurve()
|
|
{
|
|
if (cachedSplineTextureWeight != null)
|
|
{
|
|
DestroyImmediate(cachedSplineTextureWeight);
|
|
}
|
|
}
|
|
|
|
public void ClearCachedSplineTreeCurve()
|
|
{
|
|
if (cachedSplineTreeWeight != null)
|
|
{
|
|
DestroyImmediate(cachedSplineTreeWeight);
|
|
}
|
|
}
|
|
|
|
public void ClearCachedSplineDetailCurve()
|
|
{
|
|
if (cachedSplineDetailWeight != null)
|
|
{
|
|
DestroyImmediate(cachedSplineDetailWeight);
|
|
}
|
|
}
|
|
|
|
public void ClearCachedSplineTrenchCurve()
|
|
{
|
|
if (cachedSplineTrenchWeight != null)
|
|
{
|
|
DestroyImmediate(cachedSplineTrenchWeight);
|
|
}
|
|
}
|
|
|
|
public void UpdateCachedTextureWeight()
|
|
{
|
|
if (cachedSplineTextureWeight == null)
|
|
{
|
|
cachedSplineTextureWeight = new Texture2D(128, 1, TextureFormat.R8, false);
|
|
cachedSplineTextureWeight.filterMode = FilterMode.Bilinear;
|
|
cachedSplineTextureWeight.wrapMode = TextureWrapMode.Clamp;
|
|
cachedSplineTextureWeight.hideFlags = HideFlags.HideAndDontSave;
|
|
for (int i = 0; i < 128; ++i)
|
|
{
|
|
cachedSplineTextureWeight.SetPixel(i, 0, new Color(textureCurve.Evaluate((float)i/128.0f), 0, 0, 1));
|
|
}
|
|
cachedSplineTextureWeight.Apply();
|
|
}
|
|
}
|
|
|
|
public void UpdateCachedTreeWeight()
|
|
{
|
|
if (cachedSplineTreeWeight == null)
|
|
{
|
|
cachedSplineTreeWeight = new Texture2D(128, 1, TextureFormat.R8, false);
|
|
cachedSplineTreeWeight.filterMode = FilterMode.Bilinear;
|
|
cachedSplineTreeWeight.wrapMode = TextureWrapMode.Clamp;
|
|
cachedSplineTreeWeight.hideFlags = HideFlags.HideAndDontSave;
|
|
for (int i = 0; i < 128; ++i)
|
|
{
|
|
cachedSplineTreeWeight.SetPixel(i, 0, new Color(treeCurve.Evaluate((float)i / 128.0f), 0, 0, 1));
|
|
}
|
|
cachedSplineTreeWeight.Apply();
|
|
}
|
|
}
|
|
|
|
public void UpdateCachedTrenchCurve()
|
|
{
|
|
if (cachedSplineTrenchWeight == null)
|
|
{
|
|
cachedSplineTrenchWeight = new Texture2D(128, 1, TextureFormat.RFloat, false);
|
|
cachedSplineTrenchWeight.filterMode = FilterMode.Bilinear;
|
|
cachedSplineTrenchWeight.wrapMode = TextureWrapMode.Clamp;
|
|
cachedSplineTrenchWeight.hideFlags = HideFlags.HideAndDontSave;
|
|
for (int i = 0; i < 128; ++i)
|
|
{
|
|
cachedSplineTrenchWeight.SetPixel(i, 0, new Color(trenchCurve.Evaluate((float)i / 128.0f), 0, 0, 1));
|
|
}
|
|
cachedSplineTrenchWeight.Apply();
|
|
}
|
|
}
|
|
|
|
public void UpdateCachedDetailWeight()
|
|
{
|
|
if (cachedSplineDetailWeight == null)
|
|
{
|
|
cachedSplineDetailWeight = new Texture2D(128, 1, TextureFormat.R8, false);
|
|
cachedSplineDetailWeight.filterMode = FilterMode.Bilinear;
|
|
cachedSplineDetailWeight.wrapMode = TextureWrapMode.Clamp;
|
|
cachedSplineDetailWeight.hideFlags = HideFlags.HideAndDontSave;
|
|
for (int i = 0; i < 128; ++i)
|
|
{
|
|
cachedSplineDetailWeight.SetPixel(i, 0, new Color(detailCurve.Evaluate((float)i / 128.0f), 0, 0, 1));
|
|
}
|
|
cachedSplineDetailWeight.Apply();
|
|
}
|
|
}
|
|
|
|
public bool ApplyTextureStamp(RenderTexture indexSrc, RenderTexture indexDest,
|
|
RenderTexture weightSrc, RenderTexture weightDest,
|
|
TextureData splatmapData, OcclusionData od)
|
|
{
|
|
if (layer == null)
|
|
return false;
|
|
if (!modifySplatMap)
|
|
return false;
|
|
|
|
SplineRenderer sr = GetSplineRenderer(od.terrain);
|
|
if (sr != null)
|
|
{
|
|
mainChannelIndex = TerrainUtil.FindTextureChannelIndex(od.terrain, layer);
|
|
embankmentChannelIndex = TerrainUtil.FindTextureChannelIndex(od.terrain, embankmentLayer);
|
|
|
|
|
|
if (mainChannelIndex == -1)
|
|
{
|
|
//Debug.LogError("Layer is not on terrain ", layer);
|
|
return false;
|
|
}
|
|
keywordBuilder.Clear();
|
|
|
|
PrepareMaterial(splatMat, splatmapData, keywordBuilder.keywords);
|
|
splatMat.SetTexture(_SplineSDF, sr.splineSDF);
|
|
splatMat.SetFloat(_Channel, mainChannelIndex);
|
|
splatMat.SetTexture(_WeightMap, weightSrc);
|
|
splatMat.SetTexture(_IndexMap, indexSrc);
|
|
splatMat.SetFloat(_AlphaMapSize, indexSrc.width);
|
|
splatMat.SetFloat(_SplatWeight, splatWeight);
|
|
if (useTextureCurve)
|
|
{
|
|
keywordBuilder.Add("_SPLINECURVETEXTUREWEIGHT");
|
|
UpdateCachedTextureWeight();
|
|
splatMat.SetTexture("_SplineTextureWeight", cachedSplineTextureWeight);
|
|
}
|
|
keywordBuilder.Assign(splatMat);
|
|
|
|
multipleRenderBuffers[0] = indexDest.colorBuffer;
|
|
multipleRenderBuffers[1] = weightDest.colorBuffer;
|
|
|
|
Graphics.SetRenderTarget(multipleRenderBuffers, indexDest.depthBuffer);
|
|
|
|
Graphics.Blit(null, splatMat, 0);
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
public void Dispose()
|
|
{
|
|
|
|
}
|
|
|
|
static int _NoiseUV = Shader.PropertyToID("_NoiseUV");
|
|
static int _Width = Shader.PropertyToID("_Width");
|
|
static int _Smoothness = Shader.PropertyToID("_Smoothness");
|
|
static int _RealHeight = Shader.PropertyToID("_RealHeight");
|
|
static int _Trench = Shader.PropertyToID("_Trench");
|
|
static int _TrenchCurve = Shader.PropertyToID("_TrenchCurve");
|
|
static int _CombineMode = Shader.PropertyToID("_CombineMode");
|
|
static int _CombineBlend = Shader.PropertyToID("_CombineBlend");
|
|
|
|
void PrepareMaterial(Material material, HeightmapData heightmapData, List<string> keywords)
|
|
{
|
|
if (treatAsSplineArea)
|
|
{
|
|
keywordBuilder.Add("_TREATASAREA");
|
|
}
|
|
var noisePos = heightmapData.terrain.transform.position;
|
|
noisePos.x /= heightmapData.terrain.terrainData.size.x;
|
|
noisePos.z /= heightmapData.terrain.terrainData.size.z;
|
|
|
|
material.SetVector(_NoiseUV, new Vector3(noisePos.x, noisePos.z, GetTerrainScalingFactor(heightmapData.terrain)));
|
|
|
|
|
|
material.SetFloat(_Width, width);
|
|
material.SetFloat(_Smoothness, smoothness);
|
|
material.SetFloat(_Trench, trench);
|
|
if (useTrenchCurve)
|
|
{
|
|
keywords.Add("_SPLINECURVETRENCHWEIGHT");
|
|
UpdateCachedTrenchCurve();
|
|
material.SetTexture(_TrenchCurve, cachedSplineTrenchWeight);
|
|
}
|
|
|
|
heightNoise.PrepareMaterial(material, "_HEIGHT", "_Height", keywords);
|
|
material.SetFloat(_RealHeight, heightmapData.RealHeight);
|
|
material.SetFloat(_Blend, blend);
|
|
material.SetFloat(_CombineBlend, blend);
|
|
embankmentEasing.PrepareMaterial(material, "_FALLOFF", keywords);
|
|
embankmentNoise.PrepareMaterial(material, "_FALLOFF", "_Falloff", keywords);
|
|
|
|
material.SetInt(_CombineMode, (int)heightBlendMode);
|
|
}
|
|
|
|
|
|
static int _EmbankmentChannel = Shader.PropertyToID("_EmbankmentChannel");
|
|
static int _HeightWidth = Shader.PropertyToID("_HeightWidth");
|
|
static int _HeightSmoothness = Shader.PropertyToID("_HeightSmoothness");
|
|
static int _NoiseParams = Shader.PropertyToID("_NoiseParams");
|
|
static int _NoiseParams2 = Shader.PropertyToID("_NoiseParams2");
|
|
static int _SplatNoiseChannel = Shader.PropertyToID("_SplatNoiseChannel");
|
|
static int _SplatNoiseTexture = Shader.PropertyToID("_SplatNoiseTexture");
|
|
|
|
|
|
void PrepareMaterial(Material material, TextureData splatmapData, List<string> keywords)
|
|
{
|
|
if (treatAsSplineArea)
|
|
{
|
|
keywordBuilder.Add("_TREATASAREA");
|
|
}
|
|
material.SetFloat(_Width, splatWidth);
|
|
material.SetFloat(_Smoothness, splatSmoothness);
|
|
material.SetFloat(_EmbankmentChannel, embankmentChannelIndex);
|
|
material.SetFloat(_HeightWidth, width);
|
|
material.SetFloat(_HeightSmoothness, smoothness);
|
|
material.SetVector(_NoiseParams, splatNoise.GetParamVector());
|
|
material.SetVector(_NoiseParams2, splatNoise.GetParam2Vector());
|
|
material.SetFloat(_SplatNoiseChannel, (int)splatNoise.channel);
|
|
material.SetTexture(_SplatNoiseTexture, splatNoise.texture);
|
|
material.SetTextureScale(_SplatNoiseTexture, splatNoise.GetTextureScale());
|
|
material.SetTextureOffset(_SplatNoiseTexture, splatNoise.GetTextureOffset());
|
|
material.SetFloat(_CombineBlend, blend);
|
|
|
|
var noisePos = splatmapData.terrain.transform.position;
|
|
noisePos.x /= splatmapData.terrain.terrainData.size.x;
|
|
noisePos.z /= splatmapData.terrain.terrainData.size.z;
|
|
|
|
material.SetVector(_NoiseUV, new Vector3(noisePos.x, noisePos.z, GetTerrainScalingFactor(splatmapData.terrain)));
|
|
splatNoise.EnableKeyword(material, "_SPLAT", keywords);
|
|
|
|
|
|
if (embankmentChannelIndex != -1)
|
|
{
|
|
keywordBuilder.Add("_EMBANKMENT");
|
|
}
|
|
}
|
|
|
|
// Spline Bounds computation in Unity is stupidly slow. Rather than rewrite it all,
|
|
// I just cache it.
|
|
Bounds bounds = new Bounds(Vector3.zero, Vector3.zero);
|
|
public static Bounds ComputeBounds(SplineContainer spline, float expand)
|
|
{
|
|
if (spline == null || spline.Spline == null)
|
|
return new Bounds(new Vector3(-999999, -999999, -99999), Vector3.one);
|
|
Bounds b = SplineUtility.GetBounds(spline.Spline, spline.transform.localToWorldMatrix);
|
|
b.Expand(expand);
|
|
b.max = new Vector3(b.max.x, 100000, b.max.z);
|
|
b.min = new Vector3(b.min.x, -100000, b.min.z);
|
|
|
|
for (int i = 1; i < spline.Splines.Count; ++i)
|
|
{
|
|
Spline s = spline.Splines[i];
|
|
Bounds sb = SplineUtility.GetBounds(s, spline.transform.localToWorldMatrix);
|
|
|
|
sb.center = spline.transform.localToWorldMatrix.MultiplyPoint(sb.center);
|
|
sb.size = spline.transform.localToWorldMatrix.MultiplyPoint(sb.size);
|
|
sb.Expand(expand);
|
|
sb.max = new Vector3(sb.max.x, 100000, sb.max.z);
|
|
sb.min = new Vector3(sb.min.x, -100000, sb.min.z);
|
|
b.Encapsulate(sb);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
public override Bounds GetBounds()
|
|
{
|
|
if (bounds.size == Vector3.zero)
|
|
{
|
|
float expand = (Mathf.Max(width, splatWidth));
|
|
expand = (Mathf.Max(expand, smoothness));
|
|
expand = (Mathf.Max(expand, splatSmoothness));
|
|
if (multiSpline != null)
|
|
{
|
|
int count = 0;
|
|
foreach (var m in multiSpline)
|
|
{
|
|
if (m.splineContainer != null)
|
|
{
|
|
if (count == 0)
|
|
{
|
|
bounds = ComputeBounds(m.splineContainer, expand + m.widthBoost + positionNoise.amplitude * 0.5f);
|
|
}
|
|
else
|
|
{
|
|
bounds.Encapsulate(ComputeBounds(m.splineContainer, expand + m.widthBoost + positionNoise.amplitude * 0.5f));
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
else if (spline != null)
|
|
{
|
|
bounds = ComputeBounds(spline, expand);
|
|
}
|
|
else
|
|
bounds = new Bounds(Vector3.zero, Vector3.zero);
|
|
}
|
|
return bounds;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
public override void OnMoved()
|
|
{
|
|
ClearSplineRenders();
|
|
base.OnMoved();
|
|
}
|
|
#endif
|
|
|
|
|
|
public void InqTerrainLayers(Terrain terrain, List<TerrainLayer> layers)
|
|
{
|
|
if (layer != null)
|
|
layers.Add(layer);
|
|
if (embankmentLayer != null)
|
|
layers.Add(embankmentLayer);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|