This commit is contained in:
CortexCore
2025-03-14 21:04:19 +08:00
parent ff8670c453
commit 757ffe79ee
1282 changed files with 104378 additions and 3 deletions

View File

@@ -0,0 +1,322 @@
#if GRIFFIN
using Pinwheel.Griffin.TextureTool;
using UnityEngine;
namespace Pinwheel.Griffin.StampTool
{
public class GConditionalStampLayer
{
[SerializeField]
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
[SerializeField]
private bool ignore;
public bool Ignore
{
get
{
return ignore;
}
set
{
ignore = value;
}
}
[SerializeField]
private bool blendHeight;
public bool BlendHeight
{
get
{
return blendHeight;
}
set
{
blendHeight = value;
}
}
[SerializeField]
private float minHeight;
public float MinHeight
{
get
{
return minHeight;
}
set
{
minHeight = Mathf.Max(0, value);
}
}
[SerializeField]
private float maxHeight;
public float MaxHeight
{
get
{
return maxHeight;
}
set
{
maxHeight = Mathf.Max(0, value);
}
}
[SerializeField]
private AnimationCurve heightTransition;
public AnimationCurve HeightTransition
{
get
{
if (heightTransition == null)
{
heightTransition = AnimationCurve.EaseInOut(0, 1, 1, 1);
}
return heightTransition;
}
set
{
heightTransition = value;
}
}
[SerializeField]
private bool blendSlope;
public bool BlendSlope
{
get
{
return blendSlope;
}
set
{
blendSlope = value;
}
}
[SerializeField]
private GNormalMapMode normalMapMode;
public GNormalMapMode NormalMapMode
{
get
{
return normalMapMode;
}
set
{
normalMapMode = value;
}
}
[SerializeField]
private float minSlope;
public float MinSlope
{
get
{
return minSlope;
}
set
{
minSlope = Mathf.Clamp(value, 0, 90);
}
}
[SerializeField]
private float maxSlope;
public float MaxSlope
{
get
{
return maxSlope;
}
set
{
maxSlope = Mathf.Clamp(value, 0, 90);
}
}
[SerializeField]
private AnimationCurve slopeTransition;
public AnimationCurve SlopeTransition
{
get
{
if (slopeTransition == null)
{
slopeTransition = AnimationCurve.EaseInOut(0, 1, 1, 1);
}
return slopeTransition;
}
set
{
slopeTransition = value;
}
}
[SerializeField]
private bool blendNoise;
public bool BlendNoise
{
get
{
return blendNoise;
}
set
{
blendNoise = value;
}
}
[SerializeField]
private Vector2 noiseOrigin;
public Vector2 NoiseOrigin
{
get
{
return noiseOrigin;
}
set
{
noiseOrigin = value;
}
}
[SerializeField]
private float noiseFrequency;
public float NoiseFrequency
{
get
{
return noiseFrequency;
}
set
{
noiseFrequency = value;
}
}
[SerializeField]
private int noiseOctaves;
public int NoiseOctaves
{
get
{
return noiseOctaves;
}
set
{
noiseOctaves = Mathf.Clamp(value, 1, 4);
}
}
[SerializeField]
private float noiseLacunarity;
public float NoiseLacunarity
{
get
{
return noiseLacunarity;
}
set
{
noiseLacunarity = Mathf.Max(1, value);
}
}
[SerializeField]
private float noisePersistence;
public float NoisePersistence
{
get
{
return noisePersistence;
}
set
{
noisePersistence = Mathf.Clamp(value, 0.01f, 1f);
}
}
[SerializeField]
private AnimationCurve noiseRemap;
public AnimationCurve NoiseRemap
{
get
{
if (noiseRemap == null)
{
noiseRemap = AnimationCurve.EaseInOut(0, 0, 1, 1);
}
return noiseRemap;
}
set
{
noiseRemap = value;
}
}
internal Texture2D heightTransitionTexture;
internal Texture2D slopeTransitionTexture;
internal Texture2D noiseRemapTexture;
~GConditionalStampLayer()
{
if (heightTransitionTexture != null)
GUtilities.DestroyObject(heightTransitionTexture);
if (slopeTransitionTexture != null)
GUtilities.DestroyObject(slopeTransitionTexture);
if (noiseRemapTexture != null)
GUtilities.DestroyObject(noiseRemapTexture);
}
public void UpdateCurveTextures()
{
if (heightTransitionTexture != null)
GUtilities.DestroyObject(heightTransitionTexture);
if (slopeTransitionTexture != null)
GUtilities.DestroyObject(slopeTransitionTexture);
if (noiseRemapTexture != null)
GUtilities.DestroyObject(noiseRemapTexture);
heightTransitionTexture = GCommon.CreateTextureFromCurve(HeightTransition, 256, 1);
slopeTransitionTexture = GCommon.CreateTextureFromCurve(SlopeTransition, 256, 1);
noiseRemapTexture = GCommon.CreateTextureFromCurve(NoiseRemap, 256, 1);
}
public GConditionalStampLayer()
{
Ignore = false;
BlendHeight = true;
MinHeight = 0;
MaxHeight = 1000;
HeightTransition = AnimationCurve.EaseInOut(0, 1, 1, 1);
BlendSlope = true;
MinSlope = 0;
MaxSlope = 90;
SlopeTransition = AnimationCurve.EaseInOut(0, 1, 1, 1);
BlendNoise = false;
NoiseOrigin = Vector2.zero;
NoiseFrequency = 1f;
NoiseOctaves = 1;
NoiseLacunarity = 2;
NoisePersistence = 0.5f;
NoiseRemap = AnimationCurve.EaseInOut(0, 0, 1, 1);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3606907f819ef9a43b61141ba1580450
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,196 @@
#if GRIFFIN
using System.Collections.Generic;
using UnityEngine;
namespace Pinwheel.Griffin.StampTool
{
[System.Serializable]
public class GFoliageStampLayer : GConditionalStampLayer
{
[SerializeField]
private Color visualizeColor;
public Color VisualizeColor
{
get
{
return visualizeColor;
}
set
{
visualizeColor = value;
}
}
[SerializeField]
private bool stampTrees;
public bool StampTrees
{
get
{
return stampTrees;
}
set
{
stampTrees = value;
}
}
[SerializeField]
private List<int> treeIndices;
public List<int> TreeIndices
{
get
{
if (treeIndices == null)
{
treeIndices = new List<int>();
}
return treeIndices;
}
set
{
treeIndices = value;
}
}
[SerializeField]
private bool stampGrass;
public bool StampGrasses
{
get
{
return stampGrass;
}
set
{
stampGrass = value;
}
}
[SerializeField]
private List<int> grassIndices;
public List<int> GrassIndices
{
get
{
if (grassIndices == null)
{
grassIndices = new List<int>();
}
return grassIndices;
}
set
{
grassIndices = value;
}
}
[SerializeField]
private int treeInstanceCount;
public int TreeInstanceCount
{
get
{
return treeInstanceCount;
}
set
{
treeInstanceCount = Mathf.Max(0, value);
}
}
[SerializeField]
private int grassInstanceCount;
public int GrassInstanceCount
{
get
{
return grassInstanceCount;
}
set
{
grassInstanceCount = value;
}
}
[SerializeField]
private float minRotation;
public float MinRotation
{
get
{
return minRotation;
}
set
{
minRotation = value;
}
}
[SerializeField]
private float maxRotation;
public float MaxRotation
{
get
{
return maxRotation;
}
set
{
maxRotation = value;
}
}
[SerializeField]
private Vector3 minScale;
public Vector3 MinScale
{
get
{
return minScale;
}
set
{
minScale = value;
}
}
[SerializeField]
private Vector3 maxScale;
public Vector3 MaxScale
{
get
{
return maxScale;
}
set
{
maxScale = value;
}
}
public GFoliageStampLayer() : base() { }
public static GFoliageStampLayer Create()
{
GFoliageStampLayer layer = new GFoliageStampLayer();
layer.StampTrees = true;
layer.TreeIndices = null;
layer.StampGrasses = false;
layer.GrassIndices = null;
layer.TreeInstanceCount = 1000;
#if UNITY_EDITOR
layer.VisualizeColor = GEditorSettings.Instance.stampTools.visualizeColor;
layer.MinRotation = GEditorSettings.Instance.stampTools.minRotation;
layer.MaxRotation = GEditorSettings.Instance.stampTools.maxRotation;
layer.MinScale = GEditorSettings.Instance.stampTools.minScale;
layer.MaxScale = GEditorSettings.Instance.stampTools.maxScale;
#endif
layer.UpdateCurveTextures();
return layer;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 81ade946a78e26f4e83f0f4975f2281f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,606 @@
#if GRIFFIN
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.Jobs;
namespace Pinwheel.Griffin.StampTool
{
[System.Serializable]
[ExecuteInEditMode]
public class GFoliageStamper : MonoBehaviour
{
[SerializeField]
private bool enableTerrainMask;
public bool EnableTerrainMask
{
get
{
return enableTerrainMask;
}
set
{
enableTerrainMask = value;
}
}
[SerializeField]
private int groupId;
public int GroupId
{
get
{
return groupId;
}
set
{
groupId = value;
}
}
[SerializeField]
private Vector3 position;
public Vector3 Position
{
get
{
return position;
}
set
{
position = value;
transform.position = value;
}
}
[SerializeField]
private Quaternion rotation;
public Quaternion Rotation
{
get
{
return rotation;
}
set
{
rotation = value;
transform.rotation = value;
}
}
[SerializeField]
private Vector3 scale;
public Vector3 Scale
{
get
{
return scale;
}
set
{
scale = value;
transform.localScale = value;
}
}
[SerializeField]
private Texture2D mask;
public Texture2D Mask
{
get
{
return mask;
}
set
{
mask = value;
}
}
[SerializeField]
private AnimationCurve falloff;
public AnimationCurve Falloff
{
get
{
return falloff;
}
set
{
falloff = value;
}
}
[SerializeField]
private List<GFoliageStampLayer> layers;
public List<GFoliageStampLayer> Layers
{
get
{
if (layers == null)
{
layers = new List<GFoliageStampLayer>();
}
return layers;
}
set
{
layers = value;
}
}
[SerializeField]
private int maskResolution;
public int MaskResolution
{
get
{
return maskResolution;
}
set
{
maskResolution = Mathf.Clamp(Mathf.ClosestPowerOfTwo(value), GCommon.TEXTURE_SIZE_MIN, GCommon.TEXTURE_SIZE_MAX);
}
}
public Rect Rect
{
get
{
Vector3[] quad = new Vector3[4];
GetQuad(quad);
Rect r = GUtilities.GetRectContainsPoints(quad);
return r;
}
}
private Texture2D falloffTexture;
private Vector3[] worldPoints = new Vector3[4];
private Vector2[] uvPoints = new Vector2[4];
private Dictionary<string, RenderTexture> tempRt;
private Dictionary<string, RenderTexture> TempRt
{
get
{
if (tempRt == null)
{
tempRt = new Dictionary<string, RenderTexture>();
}
return tempRt;
}
}
private void Reset()
{
position = Vector3.zero;
rotation = Quaternion.identity;
scale = Vector3.one * 100;
mask = null;
falloff = AnimationCurve.EaseInOut(0, 1, 1, 0);
maskResolution = 1024;
}
private void OnDisable()
{
ReleaseResources();
}
private void OnDestroy()
{
ReleaseResources();
}
private void ReleaseResources()
{
foreach (RenderTexture rt in TempRt.Values)
{
if (rt != null)
{
rt.Release();
GUtilities.DestroyObject(rt);
}
}
}
public void Apply()
{
if (falloffTexture != null)
Object.DestroyImmediate(falloffTexture);
Internal_UpdateFalloffTexture();
Internal_UpdateLayerTransitionTextures();
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(GCommon.OverlapTest(groupId, GetQuad()));
try
{
foreach (GStylizedTerrain t in terrains)
{
Apply(t);
}
}
catch (GProgressCancelledException)
{
Debug.Log("Stamp process canceled, result may be incorrect. Use History to clean up!");
#if UNITY_EDITOR
GCommonGUI.ClearProgressBar();
#endif
}
}
private void Apply(GStylizedTerrain t)
{
if (t.TerrainData == null)
return;
if (Layers.Count == 0)
return;
GetQuad(worldPoints);
GetUvPoints(t, worldPoints, uvPoints);
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvPoints);
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
return;
RenderTexture[] brushes = new RenderTexture[Layers.Count];
for (int i = 0; i < Layers.Count; ++i)
{
brushes[i] = GetRenderTexture("brush" + i.ToString());
}
Internal_RenderBrushes(brushes, t, uvPoints);
for (int i = 0; i < Layers.Count; ++i)
{
StampLayer(t, brushes[i], i);
}
bool willUpdateTree = Layers.Exists(l => l.StampTrees && l.TreeInstanceCount > 0);
bool willUpdateGrass = Layers.Exists(l => l.StampGrasses && l.TreeInstanceCount > 0);
#if UNITY_EDITOR
string title = "Stamping on " + t.name;
string info = "Finishing up...";
GCommonGUI.ProgressBar(title, info, 1);
#endif
try
{
t.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
t.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect);
if (willUpdateTree)
t.UpdateTreesPosition();
if (willUpdateGrass)
t.UpdateGrassPatches();
t.TerrainData.Foliage.ClearTreeDirtyRegions();
t.TerrainData.Foliage.ClearGrassDirtyRegions();
}
catch (System.Exception e)
{
Debug.LogError(e);
}
#if UNITY_EDITOR
GCommonGUI.ClearProgressBar();
#endif
t.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage);
}
private void StampLayer(GStylizedTerrain t, RenderTexture brush, int layerIndex)
{
GFoliageStampLayer layer = Layers[layerIndex];
if (layer.Ignore)
return;
if (layer.TreeInstanceCount == 0)
return;
Texture2D layerMask = GCommon.CreateTexture(MaskResolution, Color.clear);
GCommon.CopyFromRT(layerMask, brush);
if (layer.StampTrees &&
layer.TreeIndices.Count > 0 &&
t.TerrainData.Foliage.Trees != null)
{
SpawnTreeOnTerrain(t, layerMask, layerIndex);
}
if (layer.StampGrasses &&
layer.GrassIndices.Count > 0 &&
t.TerrainData.Foliage.Grasses != null)
{
SpawnGrassOnTerrain(t, layerMask, layerIndex);
}
}
private void SpawnTreeOnTerrain(GStylizedTerrain t, Texture2D layerMask, int layerIndex)
{
GFoliageStampLayer layer = Layers[layerIndex];
#if UNITY_EDITOR
string title = "Stamping on " + t.name;
string info = string.Format("Layer: {0}", !string.IsNullOrEmpty(layer.Name) ? layer.Name : layerIndex.ToString());
int currentPercent = 0;
int attemptPercent = 0;
GCommonGUI.CancelableProgressBar(title, info, 0);
#endif
int sampleCount = layer.TreeInstanceCount;
NativeArray<bool> cullResult = new NativeArray<bool>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
NativeArray<GPrototypeInstanceInfo> foliageInfo = new NativeArray<GPrototypeInstanceInfo>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
NativeArray<int> selectedPrototypeIndices = new NativeArray<int>(layer.TreeIndices.ToArray(), Allocator.TempJob);
GTextureNativeDataDescriptor<Color32> maskHandle = new GTextureNativeDataDescriptor<Color32>(layerMask);
GSampleInstanceJob job = new GSampleInstanceJob()
{
cullResult = cullResult,
instanceInfo = foliageInfo,
mask = maskHandle,
selectedPrototypeIndices = selectedPrototypeIndices,
minRotation = layer.MinRotation,
maxRotation = layer.MaxRotation,
minScale = layer.MinScale,
maxScale = layer.MaxScale,
seed = Random.Range(int.MinValue, int.MaxValue)
};
JobHandle jHandle = job.Schedule(sampleCount, 100);
jHandle.Complete();
List<GTreeInstance> instances = new List<GTreeInstance>();
for (int i = 0; i < sampleCount; ++i)
{
#if UNITY_EDITOR
attemptPercent = (int)(i * 100.0f / sampleCount);
if (currentPercent != attemptPercent)
{
currentPercent = attemptPercent;
GCommonGUI.CancelableProgressBar(title, string.Format("{0} ... {1}%", info, currentPercent), currentPercent / 100.0f);
}
#endif
if (cullResult[i] == false)
continue;
GTreeInstance tree = foliageInfo[i].ToTreeInstance();
instances.Add(tree);
}
t.TerrainData.Foliage.AddTreeInstances(instances);
cullResult.Dispose();
foliageInfo.Dispose();
selectedPrototypeIndices.Dispose();
#if UNITY_EDITOR
GCommonGUI.ClearProgressBar();
#endif
}
private void SpawnGrassOnTerrain(GStylizedTerrain t, Texture2D layerMask, int layerIndex)
{
GFoliageStampLayer layer = Layers[layerIndex];
#if UNITY_EDITOR
string title = "Stamping on " + t.name;
string info = string.Format("Layer: {0}", !string.IsNullOrEmpty(layer.Name) ? layer.Name : layerIndex.ToString());
GCommonGUI.CancelableProgressBar(title, info, 1);
#endif
int sampleCount = layer.GrassInstanceCount;
NativeArray<bool> cullResultNA = new NativeArray<bool>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
NativeArray<GPrototypeInstanceInfo> foliageInfoNA = new NativeArray<GPrototypeInstanceInfo>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
NativeArray<int> selectedPrototypeIndicesNA = new NativeArray<int>(layer.GrassIndices.ToArray(), Allocator.TempJob);
GTextureNativeDataDescriptor<Color32> maskHandleNA = new GTextureNativeDataDescriptor<Color32>(layerMask);
GSampleInstanceJob job = new GSampleInstanceJob()
{
cullResult = cullResultNA,
instanceInfo = foliageInfoNA,
mask = maskHandleNA,
selectedPrototypeIndices = selectedPrototypeIndicesNA,
minRotation = layer.MinRotation,
maxRotation = layer.MaxRotation,
minScale = layer.MinScale,
maxScale = layer.MaxScale,
seed = Random.Range(int.MinValue, int.MaxValue)
};
JobHandle jHandle = job.Schedule(sampleCount, 100);
jHandle.Complete();
t.TerrainData.Foliage.AddGrassInstancesWithFilter(cullResultNA, foliageInfoNA);
cullResultNA.Dispose();
foliageInfoNA.Dispose();
selectedPrototypeIndicesNA.Dispose();
#if UNITY_EDITOR
GCommonGUI.ClearProgressBar();
#endif
}
public void Internal_RenderBrushes(RenderTexture[] brushes, GStylizedTerrain t, Vector2[] uvPoints)
{
for (int i = 0; i < brushes.Length; ++i)
{
GStampLayerMaskRenderer.Render(
brushes[i],
Layers[i],
t,
Matrix4x4.TRS(Position, Rotation, Scale),
Mask,
falloffTexture,
uvPoints,
EnableTerrainMask);
}
}
public void Internal_UpdateFalloffTexture()
{
if (falloffTexture != null)
GUtilities.DestroyObject(falloffTexture);
falloffTexture = GCommon.CreateTextureFromCurve(Falloff, 256, 1);
}
public void Internal_UpdateLayerTransitionTextures()
{
for (int i = 0; i < Layers.Count; ++i)
{
Layers[i].UpdateCurveTextures();
}
}
public Vector3[] GetQuad()
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
Vector3[] quad = new Vector3[4]
{
matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f)),
matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f)),
matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f)),
matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f))
};
return quad;
}
public void GetQuad(Vector3[] quad)
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
quad[0] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f));
quad[1] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f));
quad[2] = matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f));
quad[3] = matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f));
}
private void GetUvPoints(GStylizedTerrain t, Vector3[] worldPoint, Vector2[] uvPoint)
{
for (int i = 0; i < uvPoints.Length; ++i)
{
uvPoints[i] = t.WorldPointToUV(worldPoints[i]);
}
}
public void GetBox(Vector3[] box)
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
box[0] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f));
box[1] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f));
box[2] = matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f));
box[3] = matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f));
box[4] = matrix.MultiplyPoint(new Vector3(-0.5f, 1, -0.5f));
box[5] = matrix.MultiplyPoint(new Vector3(-0.5f, 1, 0.5f));
box[6] = matrix.MultiplyPoint(new Vector3(0.5f, 1, 0.5f));
box[7] = matrix.MultiplyPoint(new Vector3(0.5f, 1, -0.5f));
}
private RenderTexture GetRenderTexture(string key)
{
int resolution = MaskResolution;
if (!TempRt.ContainsKey(key) ||
TempRt[key] == null)
{
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
rt.wrapMode = TextureWrapMode.Clamp;
TempRt[key] = rt;
}
else if (TempRt[key].width != resolution || TempRt[key].height != resolution)
{
TempRt[key].Release();
Object.DestroyImmediate(TempRt[key]);
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
rt.wrapMode = TextureWrapMode.Clamp;
TempRt[key] = rt;
}
return TempRt[key];
}
public void ClearTrees()
{
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(GCommon.OverlapTest(GroupId, GetQuad()));
foreach (GStylizedTerrain t in terrains)
{
ClearTrees(t);
}
}
private void ClearTrees(GStylizedTerrain t)
{
if (t.TerrainData == null)
return;
if (t.TerrainData.Foliage.Trees == null)
return;
Vector3 terrainSize = new Vector3(
t.TerrainData.Geometry.Width,
t.TerrainData.Geometry.Height,
t.TerrainData.Geometry.Length);
Vector3 scale = new Vector3(
GUtilities.InverseLerpUnclamped(0, terrainSize.x, Scale.x),
GUtilities.InverseLerpUnclamped(0, terrainSize.y, Scale.y),
GUtilities.InverseLerpUnclamped(0, terrainSize.z, Scale.z));
Matrix4x4 matrix = Matrix4x4.TRS(
t.WorldPointToNormalized(Position),
Rotation,
scale);
Matrix4x4 normalizeToStamp = matrix.inverse;
t.TerrainData.Foliage.RemoveTreeInstances(tree =>
{
Vector3 stampSpacePos = normalizeToStamp.MultiplyPoint(tree.Position);
return
stampSpacePos.x >= -0.5f && stampSpacePos.x <= 0.5f &&
stampSpacePos.y >= 0f && stampSpacePos.y <= 1f &&
stampSpacePos.z >= -0.5f && stampSpacePos.z <= 0.5f;
});
t.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage);
}
public void ClearGrasses()
{
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(GCommon.OverlapTest(GroupId, GetQuad()));
foreach (GStylizedTerrain t in terrains)
{
ClearGrasses(t);
}
}
private void ClearGrasses(GStylizedTerrain t)
{
if (t.TerrainData == null)
return;
if (t.TerrainData.Foliage.Grasses == null)
return;
Vector3 terrainSize = new Vector3(
t.TerrainData.Geometry.Width,
t.TerrainData.Geometry.Height,
t.TerrainData.Geometry.Length);
Vector3 scale = new Vector3(
GUtilities.InverseLerpUnclamped(0, terrainSize.x, Scale.x),
GUtilities.InverseLerpUnclamped(0, terrainSize.y, Scale.y),
GUtilities.InverseLerpUnclamped(0, terrainSize.z, Scale.z));
Matrix4x4 matrix = Matrix4x4.TRS(
t.WorldPointToNormalized(Position),
Rotation,
scale);
Matrix4x4 normalizeToStamp = matrix.inverse;
GGrassPatch[] patches = t.TerrainData.Foliage.GrassPatches;
for (int i = 0; i < patches.Length; ++i)
{
patches[i].RemoveInstances(grass =>
{
Vector3 stampSpacePos = normalizeToStamp.MultiplyPoint(grass.Position);
return
stampSpacePos.x >= -0.5f && stampSpacePos.x <= 0.5f &&
stampSpacePos.y >= 0f && stampSpacePos.y <= 1f &&
stampSpacePos.z >= -0.5f && stampSpacePos.z <= 0.5f;
});
}
t.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc2df825bbad26448bbc53968b0fb698
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,371 @@
#if GRIFFIN
using System.Collections.Generic;
using UnityEngine;
namespace Pinwheel.Griffin.StampTool
{
[System.Serializable]
[ExecuteInEditMode]
public class GGeometryStamper : MonoBehaviour
{
public enum GStampChannel
{
Elevation, Visibility
}
[SerializeField]
private bool enableTerrainMask = true;
public bool EnableTerrainMask
{
get
{
return enableTerrainMask;
}
set
{
enableTerrainMask = value;
}
}
[SerializeField]
private int groupId;
public int GroupId
{
get
{
return groupId;
}
set
{
groupId = value;
}
}
[SerializeField]
private Vector3 position;
public Vector3 Position
{
get
{
return position;
}
set
{
position = value;
transform.position = value;
}
}
[SerializeField]
private Quaternion rotation;
public Quaternion Rotation
{
get
{
return rotation;
}
set
{
rotation = value;
transform.rotation = value;
}
}
[SerializeField]
private Vector3 scale;
public Vector3 Scale
{
get
{
return scale;
}
set
{
scale = value;
transform.localScale = value;
}
}
[SerializeField]
private Texture2D stamp;
public Texture2D Stamp
{
get
{
return stamp;
}
set
{
stamp = value;
}
}
[SerializeField]
private GStampChannel channel;
public GStampChannel Channel
{
get
{
return channel;
}
set
{
channel = value;
}
}
[SerializeField]
private AnimationCurve falloff;
public AnimationCurve Falloff
{
get
{
return falloff;
}
set
{
falloff = value;
}
}
[SerializeField]
private bool inverseStamp;
public bool InverseStamp
{
get
{
return inverseStamp;
}
set
{
inverseStamp = value;
}
}
[SerializeField]
private bool useFalloffAsBlendFactor;
public bool UseFalloffAsBlendFactor
{
get
{
return useFalloffAsBlendFactor;
}
set
{
useFalloffAsBlendFactor = value;
}
}
[SerializeField]
private GStampOperation operation;
public GStampOperation Operation
{
get
{
return operation;
}
set
{
operation = value;
}
}
[SerializeField]
private float lerpFactor;
public float LerpFactor
{
get
{
return lerpFactor;
}
set
{
lerpFactor = Mathf.Clamp01(value);
}
}
[SerializeField]
private int additionalMeshResolution;
public int AdditionalMeshResolution
{
get
{
return additionalMeshResolution;
}
set
{
additionalMeshResolution = Mathf.Clamp(value, 0, 10);
}
}
private Texture2D falloffTexture;
public Rect Rect
{
get
{
Vector3[] quad = new Vector3[4];
GetQuad(quad);
Rect r = GUtilities.GetRectContainsPoints(quad);
return r;
}
}
private void Reset()
{
position = Vector3.zero;
rotation = Quaternion.identity;
scale = Vector3.one * 100;
stamp = null;
falloff = AnimationCurve.EaseInOut(0, 1, 1, 0);
inverseStamp = false;
useFalloffAsBlendFactor = true;
operation = GStampOperation.Max;
lerpFactor = 0.5f;
additionalMeshResolution = 0;
}
public void Apply()
{
if (falloffTexture != null)
Object.DestroyImmediate(falloffTexture);
Internal_UpdateFalloffTexture();
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(GCommon.OverlapTest(GroupId, GetQuad()));
foreach (GStylizedTerrain t in terrains)
{
DrawOnTexture(t);
}
foreach(GStylizedTerrain t in terrains)
{
UpdateTerrain(t);
}
foreach (GStylizedTerrain t in terrains)
{
t.MatchEdges();
}
}
private void DrawOnTexture(GStylizedTerrain t)
{
if (t.TerrainData == null)
return;
int heightMapResolution = t.TerrainData.Geometry.HeightMapResolution;
RenderTexture rt = new RenderTexture(heightMapResolution, heightMapResolution, 0, GGeometry.HeightMapRTFormat, RenderTextureReadWrite.Linear);
Internal_DrawOnTexture(t, rt);
Color[] oldHeightMapColors = t.TerrainData.Geometry.HeightMap.GetPixels();
RenderTexture.active = rt;
t.TerrainData.Geometry.HeightMap.ReadPixels(new Rect(0, 0, heightMapResolution, heightMapResolution), 0, 0);
t.TerrainData.Geometry.HeightMap.Apply();
RenderTexture.active = null;
Color[] newHeightMapColors = t.TerrainData.Geometry.HeightMap.GetPixels();
rt.Release();
Object.DestroyImmediate(rt);
List<Rect> dirtyRects = new List<Rect>(GCommon.CompareTerrainTexture(t.TerrainData.Geometry.ChunkGridSize, oldHeightMapColors, newHeightMapColors));
for (int i = 0; i < dirtyRects.Count; ++i)
{
t.TerrainData.Geometry.SetRegionDirty(dirtyRects[i]);
t.TerrainData.Foliage.SetTreeRegionDirty(dirtyRects[i]);
t.TerrainData.Foliage.SetGrassRegionDirty(dirtyRects[i]);
}
}
private void UpdateTerrain(GStylizedTerrain t)
{
t.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
t.UpdateTreesPosition();
t.UpdateGrassPatches();
t.TerrainData.Foliage.ClearTreeDirtyRegions();
t.TerrainData.Foliage.ClearGrassDirtyRegions();
t.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage);
}
public void Internal_DrawOnTexture(GStylizedTerrain t, RenderTexture rt)
{
GCommon.CopyToRT(t.TerrainData.Geometry.HeightMap, rt);
Vector3[] worldCorner = GetQuad();
Vector2[] uvCorners = new Vector2[worldCorner.Length];
for (int i = 0; i < uvCorners.Length; ++i)
{
uvCorners[i] = t.WorldPointToUV(worldCorner[i]);
}
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
return;
Vector3 normalizedPos = t.WorldPointToNormalized(Position);
float stampHeight = GUtilities.InverseLerpUnclamped(0, t.TerrainData.Geometry.Height, Scale.y);
Material mat = GInternalMaterials.StamperMaterial;
mat.SetTexture("_HeightMap", t.TerrainData.Geometry.HeightMap);
mat.SetTexture("_Stamp", Stamp);
mat.SetTexture("_Falloff", falloffTexture);
mat.SetInt("_Operation", (int)Operation);
mat.SetFloat("_LerpFactor", LerpFactor);
mat.SetFloat("_StampHeight", stampHeight);
mat.SetFloat("_StampPositionY", normalizedPos.y);
mat.SetFloat("_Inverse", InverseStamp ? 1 : 0);
mat.SetFloat("_UseFalloffAsBlendFactor", UseFalloffAsBlendFactor ? 1 : 0);
mat.SetFloat("_AdditionalMeshResolution", GCommon.SUB_DIV_STEP * AdditionalMeshResolution);
if (EnableTerrainMask)
{
mat.SetTexture("_TerrainMask", t.TerrainData.Mask.MaskMapOrDefault);
}
else
{
mat.SetTexture("_TerrainMask", Texture2D.blackTexture);
}
int pass = (int)Channel;
GCommon.DrawQuad(rt, uvCorners, mat, pass);
}
public void Internal_UpdateFalloffTexture()
{
falloffTexture = GCommon.CreateTextureFromCurve(Falloff, 256, 1);
}
public Vector3[] GetQuad()
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
Vector3[] quad = new Vector3[4]
{
matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f)),
matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f)),
matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f)),
matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f))
};
return quad;
}
public void GetQuad(Vector3[] quad)
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
quad[0] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f));
quad[1] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f));
quad[2] = matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f));
quad[3] = matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f));
}
public void GetBox(Vector3[] box)
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
box[0] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f));
box[1] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f));
box[2] = matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f));
box[3] = matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f));
box[4] = matrix.MultiplyPoint(new Vector3(-0.5f, 1, -0.5f));
box[5] = matrix.MultiplyPoint(new Vector3(-0.5f, 1, 0.5f));
box[6] = matrix.MultiplyPoint(new Vector3(0.5f, 1, 0.5f));
box[7] = matrix.MultiplyPoint(new Vector3(0.5f, 1, -0.5f));
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0fa49e4eea7d11044997fe999472ea32
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,181 @@
#if GRIFFIN
using System.Collections.Generic;
using UnityEngine;
namespace Pinwheel.Griffin.StampTool
{
[System.Serializable]
public class GObjectStampLayer : GConditionalStampLayer
{
[SerializeField]
private Color visualizeColor;
public Color VisualizeColor
{
get
{
return visualizeColor;
}
set
{
visualizeColor = value;
}
}
[SerializeField]
public List<GameObject> prototypes;
public List<GameObject> Prototypes
{
get
{
if (prototypes == null)
{
prototypes = new List<GameObject>();
}
return prototypes;
}
set
{
prototypes = value;
}
}
[SerializeField]
private List<int> prototypeIndices;
public List<int> PrototypeIndices
{
get
{
if (prototypeIndices == null)
{
prototypeIndices = new List<int>();
}
return prototypeIndices;
}
set
{
prototypeIndices = value;
}
}
[SerializeField]
private int instanceCount;
public int InstanceCount
{
get
{
return instanceCount;
}
set
{
instanceCount = Mathf.Max(0, value);
}
}
[SerializeField]
private float minRotation;
public float MinRotation
{
get
{
return minRotation;
}
set
{
minRotation = value;
}
}
[SerializeField]
private float maxRotation;
public float MaxRotation
{
get
{
return maxRotation;
}
set
{
maxRotation = value;
}
}
[SerializeField]
private Vector3 minScale;
public Vector3 MinScale
{
get
{
return minScale;
}
set
{
minScale = value;
}
}
[SerializeField]
private Vector3 maxScale;
public Vector3 MaxScale
{
get
{
return maxScale;
}
set
{
maxScale = value;
}
}
[SerializeField]
private bool alignToSurface;
public bool AlignToSurface
{
get
{
return alignToSurface;
}
set
{
alignToSurface = value;
}
}
[SerializeField]
private LayerMask worldRaycastMask;
public LayerMask WorldRaycastMask
{
get
{
return worldRaycastMask;
}
set
{
worldRaycastMask = value;
}
}
public GObjectStampLayer() : base() { }
public static GObjectStampLayer Create()
{
GObjectStampLayer layer = new GObjectStampLayer();
layer.Prototypes = null;
layer.PrototypeIndices = null;
layer.InstanceCount = 100;
layer.AlignToSurface = false;
#if UNITY_EDITOR
layer.VisualizeColor = GEditorSettings.Instance.stampTools.visualizeColor;
layer.MinRotation = GEditorSettings.Instance.stampTools.minRotation;
layer.MaxRotation = GEditorSettings.Instance.stampTools.maxRotation;
layer.MinScale = GEditorSettings.Instance.stampTools.minScale;
layer.MaxScale = GEditorSettings.Instance.stampTools.maxScale;
#endif
layer.WorldRaycastMask = 1;
layer.UpdateCurveTextures();
return layer;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e205da52ebccbc944b2eb9105efedb36
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,514 @@
#if GRIFFIN
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.Jobs;
namespace Pinwheel.Griffin.StampTool
{
[System.Serializable]
[ExecuteInEditMode]
public class GObjectStamper : MonoBehaviour
{
[SerializeField]
private bool enableTerrainMask;
public bool EnableTerrainMask
{
get
{
return enableTerrainMask;
}
set
{
enableTerrainMask = value;
}
}
[SerializeField]
private int groupId;
public int GroupId
{
get
{
return groupId;
}
set
{
groupId = value;
}
}
[SerializeField]
private Vector3 position;
public Vector3 Position
{
get
{
return position;
}
set
{
position = value;
transform.position = value;
}
}
[SerializeField]
private Quaternion rotation;
public Quaternion Rotation
{
get
{
return rotation;
}
set
{
rotation = value;
transform.rotation = value;
}
}
[SerializeField]
private Vector3 scale;
public Vector3 Scale
{
get
{
return scale;
}
set
{
scale = value;
transform.localScale = value;
}
}
[SerializeField]
private Texture2D mask;
public Texture2D Mask
{
get
{
return mask;
}
set
{
mask = value;
}
}
[SerializeField]
private AnimationCurve falloff;
public AnimationCurve Falloff
{
get
{
return falloff;
}
set
{
falloff = value;
}
}
[SerializeField]
private List<GObjectStampLayer> layers;
public List<GObjectStampLayer> Layers
{
get
{
if (layers == null)
{
layers = new List<GObjectStampLayer>();
}
return layers;
}
set
{
layers = value;
}
}
[SerializeField]
private int maskResolution;
public int MaskResolution
{
get
{
return maskResolution;
}
set
{
maskResolution = Mathf.Clamp(Mathf.ClosestPowerOfTwo(value), GCommon.TEXTURE_SIZE_MIN, GCommon.TEXTURE_SIZE_MAX);
}
}
public Rect Rect
{
get
{
Vector3[] quad = new Vector3[4];
GetQuad(quad);
Rect r = GUtilities.GetRectContainsPoints(quad);
return r;
}
}
private Texture2D falloffTexture;
private Vector3[] worldPoints = new Vector3[4];
private Vector2[] uvPoints = new Vector2[4];
private Dictionary<string, RenderTexture> tempRt;
private Dictionary<string, RenderTexture> TempRt
{
get
{
if (tempRt == null)
{
tempRt = new Dictionary<string, RenderTexture>();
}
return tempRt;
}
}
private void Reset()
{
position = Vector3.zero;
rotation = Quaternion.identity;
scale = Vector3.one * 100;
mask = null;
falloff = AnimationCurve.EaseInOut(0, 1, 1, 0);
maskResolution = 1024;
}
private void OnDisable()
{
ReleaseResources();
}
private void OnDestroy()
{
ReleaseResources();
}
private void ReleaseResources()
{
foreach (RenderTexture rt in TempRt.Values)
{
if (rt != null)
{
rt.Release();
GUtilities.DestroyObject(rt);
}
}
}
public void Apply()
{
if (falloffTexture != null)
Object.DestroyImmediate(falloffTexture);
Internal_UpdateFalloffTexture();
Internal_UpdateLayerTransitionTextures();
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(GCommon.OverlapTest(GroupId, GetQuad()));
try
{
foreach (GStylizedTerrain t in terrains)
{
Apply(t);
}
}
catch (GProgressCancelledException)
{
Debug.Log("Stamp process canceled, result may be incorrect. Use History to clean up!");
#if UNITY_EDITOR
GCommonGUI.ClearProgressBar();
#endif
}
}
private void Apply(GStylizedTerrain t)
{
if (t.TerrainData == null)
return;
if (Layers.Count == 0)
return;
GetQuad(worldPoints);
GetUvPoints(t, worldPoints, uvPoints);
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvPoints);
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
return;
RenderTexture[] brushes = new RenderTexture[Layers.Count];
for (int i = 0; i < Layers.Count; ++i)
{
brushes[i] = GetRenderTexture("brush" + i.ToString());
}
Internal_RenderBrushes(brushes, t, uvPoints);
for (int i = 0; i < Layers.Count; ++i)
{
StampLayer(t, brushes[i], i);
}
}
private void StampLayer(GStylizedTerrain t, RenderTexture brush, int layerIndex)
{
GObjectStampLayer layer = Layers[layerIndex];
if (layer.Ignore)
return;
if (layer.InstanceCount == 0)
return;
if (layer.Prototypes.Count == 0 ||
layer.PrototypeIndices.Count == 0)
return;
Texture2D layerMask = GCommon.CreateTexture(MaskResolution, Color.clear);
GCommon.CopyFromRT(layerMask, brush);
SpawnObjectOnTerrain(t, layerMask, layerIndex);
GUtilities.DestroyObject(layerMask);
}
private void SpawnObjectOnTerrain(GStylizedTerrain t, Texture2D layerMask, int layerIndex)
{
GObjectStampLayer layer = Layers[layerIndex];
#if UNITY_EDITOR
string title = "Stamping on " + t.name;
string text = string.Format("Layer: {0}", !string.IsNullOrEmpty(layer.Name) ? layer.Name : layerIndex.ToString());
GCommonGUI.CancelableProgressBar(title, text, 1);
#endif
int sampleCount = layer.InstanceCount;
NativeArray<bool> cullResult = new NativeArray<bool>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
NativeArray<GPrototypeInstanceInfo> instanceInfo = new NativeArray<GPrototypeInstanceInfo>(sampleCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
NativeArray<int> selectedPrototypeIndices = new NativeArray<int>(layer.PrototypeIndices.ToArray(), Allocator.TempJob);
GTextureNativeDataDescriptor<Color32> maskHandle = new GTextureNativeDataDescriptor<Color32>(layerMask);
{
GSampleInstanceJob job = new GSampleInstanceJob()
{
cullResult = cullResult,
instanceInfo = instanceInfo,
mask = maskHandle,
selectedPrototypeIndices = selectedPrototypeIndices,
minRotation = layer.MinRotation,
maxRotation = layer.MaxRotation,
minScale = layer.MinScale,
maxScale = layer.MaxScale,
seed = Random.Range(int.MinValue, int.MaxValue)
};
JobHandle jHandle = job.Schedule(sampleCount, 100);
jHandle.Complete();
}
Vector3 terrainSize = t.TerrainData.Geometry.Size;
NativeArray<RaycastCommand> raycastCommands = new NativeArray<RaycastCommand>(instanceInfo.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
NativeArray<RaycastHit> hits = new NativeArray<RaycastHit>(instanceInfo.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
for (int i = 0; i < raycastCommands.Length; ++i)
{
GPrototypeInstanceInfo info = instanceInfo[i];
Vector3 from = new Vector3(t.transform.position.x + info.position.x * terrainSize.x, 10000, t.transform.position.z + info.position.z * terrainSize.z);
#if UNITY_2022_2_OR_NEWER
QueryParameters q = new QueryParameters(layer.WorldRaycastMask, false, QueryTriggerInteraction.Ignore, false);
RaycastCommand cmd = new RaycastCommand(from, Vector3.down, q, float.MaxValue);
#else
RaycastCommand cmd = new RaycastCommand(from, Vector3.down, float.MaxValue, layer.WorldRaycastMask, 1);
#endif
raycastCommands[i] = cmd;
}
{
JobHandle jHandle = RaycastCommand.ScheduleBatch(raycastCommands, hits, 10);
jHandle.Complete();
}
for (int i = 0; i < instanceInfo.Length; ++i)
{
GPrototypeInstanceInfo info = instanceInfo[i];
RaycastHit h = hits[i];
info.position.Set(info.position.x * terrainSize.x, h.collider != null ? h.point.y : 0, info.position.z * terrainSize.z);
instanceInfo[i] = info;
}
int count = instanceInfo.Length;
for (int i = 0; i < count; ++i)
{
GPrototypeInstanceInfo info = instanceInfo[i];
if (cullResult[i] == false)
continue;
if (info.prototypeIndex < 0 || info.prototypeIndex >= layer.Prototypes.Count)
continue;
GameObject prototype = layer.Prototypes[info.prototypeIndex];
GameObject go = GSpawner.Spawn(t, prototype, Vector3.zero);
go.transform.position = t.transform.position + info.position;
go.transform.rotation = info.rotation;
go.transform.localScale = info.scale;
if (layer.AlignToSurface)
{
RaycastHit hit = hits[i];
if (hit.collider != null)
{
Quaternion q = Quaternion.FromToRotation(go.transform.up, hit.normal);
go.transform.rotation *= q;
}
}
}
raycastCommands.Dispose();
hits.Dispose();
cullResult.Dispose();
instanceInfo.Dispose();
selectedPrototypeIndices.Dispose();
#if UNITY_EDITOR
GCommonGUI.ClearProgressBar();
#endif
}
public void Internal_RenderBrushes(RenderTexture[] brushes, GStylizedTerrain t, Vector2[] uvPoints)
{
for (int i = 0; i < brushes.Length; ++i)
{
GStampLayerMaskRenderer.Render(
brushes[i],
Layers[i],
t,
Matrix4x4.TRS(Position, Rotation, Scale),
Mask,
falloffTexture,
uvPoints,
EnableTerrainMask);
}
}
public void Internal_UpdateFalloffTexture()
{
if (falloffTexture != null)
GUtilities.DestroyObject(falloffTexture);
falloffTexture = GCommon.CreateTextureFromCurve(Falloff, 256, 1);
}
public void Internal_UpdateLayerTransitionTextures()
{
for (int i = 0; i < Layers.Count; ++i)
{
Layers[i].UpdateCurveTextures();
}
}
public Vector3[] GetQuad()
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
Vector3[] quad = new Vector3[4]
{
matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f)),
matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f)),
matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f)),
matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f))
};
return quad;
}
public void GetQuad(Vector3[] quad)
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
quad[0] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f));
quad[1] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f));
quad[2] = matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f));
quad[3] = matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f));
}
private void GetUvPoints(GStylizedTerrain t, Vector3[] worldPoint, Vector2[] uvPoint)
{
for (int i = 0; i < uvPoints.Length; ++i)
{
uvPoints[i] = t.WorldPointToUV(worldPoints[i]);
}
}
public void GetBox(Vector3[] box)
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
box[0] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f));
box[1] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f));
box[2] = matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f));
box[3] = matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f));
box[4] = matrix.MultiplyPoint(new Vector3(-0.5f, 1, -0.5f));
box[5] = matrix.MultiplyPoint(new Vector3(-0.5f, 1, 0.5f));
box[6] = matrix.MultiplyPoint(new Vector3(0.5f, 1, 0.5f));
box[7] = matrix.MultiplyPoint(new Vector3(0.5f, 1, -0.5f));
}
private RenderTexture GetRenderTexture(string key)
{
int resolution = MaskResolution;
if (!TempRt.ContainsKey(key) ||
TempRt[key] == null)
{
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
rt.wrapMode = TextureWrapMode.Clamp;
TempRt[key] = rt;
}
else if (TempRt[key].width != resolution || TempRt[key].height != resolution)
{
TempRt[key].Release();
Object.DestroyImmediate(TempRt[key]);
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
rt.wrapMode = TextureWrapMode.Clamp;
TempRt[key] = rt;
}
return TempRt[key];
}
public void ClearObjects()
{
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(GCommon.OverlapTest(GroupId, GetQuad()));
foreach (GStylizedTerrain t in terrains)
{
ClearObjects(t);
}
}
private void ClearObjects(GStylizedTerrain t)
{
if (t.TerrainData == null)
return;
Vector3 terrainSize = new Vector3(
t.TerrainData.Geometry.Width,
t.TerrainData.Geometry.Height,
t.TerrainData.Geometry.Length);
Vector3 scale = new Vector3(
GUtilities.InverseLerpUnclamped(0, terrainSize.x, Scale.x),
GUtilities.InverseLerpUnclamped(0, terrainSize.y, Scale.y),
GUtilities.InverseLerpUnclamped(0, terrainSize.z, Scale.z));
Matrix4x4 matrix = Matrix4x4.TRS(
t.WorldPointToNormalized(Position),
Rotation,
scale);
Matrix4x4 normalizeToStamp = matrix.inverse;
GSpawner.DestroyIf(t, (g) =>
{
Vector3 normalizePos = t.WorldPointToNormalized(g.transform.position);
Vector3 stampSpacePos = normalizeToStamp.MultiplyPoint(normalizePos);
return
stampSpacePos.x >= -0.5f && stampSpacePos.x <= 0.5f &&
stampSpacePos.y >= 0f && stampSpacePos.y <= 1f &&
stampSpacePos.z >= -0.5f && stampSpacePos.z <= 0.5f;
});
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 059eb2e48433fcb4d9e7de033a744202
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,108 @@
#if GRIFFIN
using Pinwheel.Griffin.TextureTool;
using UnityEngine;
namespace Pinwheel.Griffin.StampTool
{
public static class GStampLayerMaskRenderer
{
private const string BLEND_HEIGHT_KW = "BLEND_HEIGHT";
private const string BLEND_SLOPE_KW = "BLEND_SLOPE";
private const string BLEND_NOISE_KW = "BLEND_NOISE";
public static void Render(
RenderTexture rt,
GConditionalStampLayer layer,
GStylizedTerrain terrain,
Matrix4x4 stamperTransform,
Texture mask,
Texture falloffTexture,
Vector2[] uvPoints,
bool useTerrainMask)
{
GCommon.ClearRT(rt);
if (layer.Ignore)
{
return;
}
Material brushMat = Object.Instantiate(GInternalMaterials.TextureStamperBrushMaterial);
int resolution = Mathf.Max(rt.width, rt.height);
//no need to release these maps
RenderTexture heightMap = terrain.GetHeightMap(resolution);
RenderTexture normalMap =
layer.NormalMapMode == GNormalMapMode.Sharp ? terrain.GetSharpNormalMap(resolution) :
layer.NormalMapMode == GNormalMapMode.Interpolated ? terrain.GetInterpolatedNormalMap(resolution) :
layer.NormalMapMode == GNormalMapMode.PerPixel ? terrain.GetPerPixelNormalMap(resolution) : null;
brushMat.SetTexture("_HeightMap", heightMap);
Vector3 position = stamperTransform.MultiplyPoint(Vector3.zero);
Vector3 scale = stamperTransform.lossyScale;
float stamperMinHeight = terrain.WorldPointToNormalized(position).y;
float stamperMaxHeight = terrain.WorldPointToNormalized(position + Vector3.up * scale.y).y;
brushMat.SetFloat("_StamperMinHeight", stamperMinHeight);
brushMat.SetFloat("_StamperMaxHeight", stamperMaxHeight);
Vector3 terrainSize = new Vector3(
terrain.TerrainData.Geometry.Width,
terrain.TerrainData.Geometry.Height,
terrain.TerrainData.Geometry.Length);
brushMat.SetTexture("_Mask", mask);
brushMat.SetTexture("_Falloff", falloffTexture);
brushMat.SetFloat("_MinHeight", GUtilities.InverseLerpUnclamped(0, terrainSize.y, layer.MinHeight));
brushMat.SetFloat("_MaxHeight", GUtilities.InverseLerpUnclamped(0, terrainSize.y, layer.MaxHeight));
brushMat.SetTexture("_HeightTransition", layer.heightTransitionTexture);
brushMat.SetFloat("_MinSlope", layer.MinSlope * Mathf.Deg2Rad);
brushMat.SetFloat("_MaxSlope", layer.MaxSlope * Mathf.Deg2Rad);
brushMat.SetTexture("_SlopeTransition", layer.slopeTransitionTexture);
brushMat.SetVector("_NoiseOrigin", layer.NoiseOrigin);
brushMat.SetFloat("_NoiseFrequency", layer.NoiseFrequency);
brushMat.SetInt("_NoiseOctaves", layer.NoiseOctaves);
brushMat.SetFloat("_NoiseLacunarity", layer.NoiseLacunarity);
brushMat.SetFloat("_NoisePersistence", layer.NoisePersistence);
brushMat.SetTexture("_NoiseRemap", layer.noiseRemapTexture);
brushMat.SetTexture("_NormalMap", normalMap);
if (useTerrainMask)
{
brushMat.SetTexture("_TerrainMask", terrain.TerrainData.Mask.MaskMapOrDefault);
}
else
{
brushMat.SetTexture("_TerrainMask", Texture2D.blackTexture);
}
GCommon.SetMaterialKeywordActive(brushMat, BLEND_HEIGHT_KW, layer.BlendHeight);
GCommon.SetMaterialKeywordActive(brushMat, BLEND_SLOPE_KW, layer.BlendSlope);
GCommon.SetMaterialKeywordActive(brushMat, BLEND_NOISE_KW, layer.BlendNoise);
DrawOnBrushTexture(rt, uvPoints, brushMat, 0);
}
private static void DrawOnBrushTexture(RenderTexture rt, Vector2[] quadCorners, Material mat, int pass)
{
RenderTexture.active = rt;
GL.PushMatrix();
mat.SetPass(pass);
GL.LoadOrtho();
GL.Begin(GL.QUADS);
GL.MultiTexCoord(0, new Vector3(0, 0, 0));
GL.Vertex3(quadCorners[0].x, quadCorners[0].y, 0);
GL.MultiTexCoord(0, new Vector3(0, 1, 0));
GL.Vertex3(quadCorners[1].x, quadCorners[1].y, 0);
GL.MultiTexCoord(0, new Vector3(1, 1, 0));
GL.Vertex3(quadCorners[2].x, quadCorners[2].y, 0);
GL.MultiTexCoord(0, new Vector3(1, 0, 0));
GL.Vertex3(quadCorners[3].x, quadCorners[3].y, 0);
GL.End();
GL.PopMatrix();
RenderTexture.active = null;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca6a4de51cb9ceb4dae58882a8f8574d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
#if GRIFFIN
namespace Pinwheel.Griffin.StampTool
{
public enum GStampOperation
{
Add, Subtract, ReverseSubtract, Max, Min, Lerp, Different
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15bb6698698c1264bb6b83f45fdf0812
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
#if GRIFFIN
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
namespace Pinwheel.Griffin.StampTool
{
public static class GStampToolUtilities
{
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6ed08dce1f8e1a247b852b231e1f38a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
#if GRIFFIN
namespace Pinwheel.Griffin.StampTool
{
public enum GTextureStampChannel
{
AlbedoMetallicSmoothness, Splat
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0eee7cc1ac3c7a4429b9bfb9f54ba970
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,80 @@
#if GRIFFIN
using UnityEngine;
namespace Pinwheel.Griffin.StampTool
{
[System.Serializable]
public class GTextureStampLayer : GConditionalStampLayer
{
[SerializeField]
private Color color;
public Color Color
{
get
{
return color;
}
set
{
color = value;
}
}
[SerializeField]
private float metallic;
public float Metallic
{
get
{
return metallic;
}
set
{
metallic = Mathf.Clamp01(value);
}
}
[SerializeField]
private float smoothness;
public float Smoothness
{
get
{
return smoothness;
}
set
{
smoothness = Mathf.Clamp01(value);
}
}
[SerializeField]
private int splatIndex;
public int SplatIndex
{
get
{
return splatIndex;
}
set
{
splatIndex = value;
}
}
public GTextureStampLayer() : base() { }
public static GTextureStampLayer Create()
{
GTextureStampLayer layer = new GTextureStampLayer();
layer.Color = Color.white;
layer.Metallic = 0;
layer.Smoothness = 0;
layer.SplatIndex = 0;
layer.UpdateCurveTextures();
return layer;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 733a7f8c1e0121948ad9c423e02276dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,605 @@
#if GRIFFIN
using System.Collections.Generic;
using UnityEngine;
namespace Pinwheel.Griffin.StampTool
{
[System.Serializable]
[ExecuteInEditMode]
public class GTextureStamper : MonoBehaviour
{
#if UNITY_EDITOR
[SerializeField]
private bool editor_ShowLivePreview = true;
public bool Editor_ShowLivePreview
{
get
{
return editor_ShowLivePreview;
}
set
{
editor_ShowLivePreview = value;
}
}
[SerializeField]
private bool editor_ShowBounds = true;
public bool Editor_ShowBounds
{
get
{
return editor_ShowBounds;
}
set
{
editor_ShowBounds = value;
}
}
#endif
[SerializeField]
private bool enableTerrainMask;
public bool EnableTerrainMask
{
get
{
return enableTerrainMask;
}
set
{
enableTerrainMask = value;
}
}
[SerializeField]
private int groupId;
public int GroupId
{
get
{
return groupId;
}
set
{
groupId = value;
}
}
[SerializeField]
private Vector3 position;
public Vector3 Position
{
get
{
return position;
}
set
{
position = value;
transform.position = value;
}
}
[SerializeField]
private Quaternion rotation = Quaternion.identity;
public Quaternion Rotation
{
get
{
return rotation;
}
set
{
rotation = value;
transform.rotation = value;
}
}
[SerializeField]
private Vector3 scale;
public Vector3 Scale
{
get
{
return scale;
}
set
{
scale = value;
transform.localScale = value;
}
}
[SerializeField]
private Texture2D mask;
public Texture2D Mask
{
get
{
return mask;
}
set
{
mask = value;
}
}
[SerializeField]
private AnimationCurve falloff;
public AnimationCurve Falloff
{
get
{
return falloff;
}
set
{
falloff = value;
}
}
[SerializeField]
private GTextureStampChannel channel;
public GTextureStampChannel Channel
{
get
{
return channel;
}
set
{
channel = value;
}
}
[SerializeField]
private List<GTextureStampLayer> layers;
public List<GTextureStampLayer> Layers
{
get
{
if (layers == null)
{
layers = new List<GTextureStampLayer>();
}
return layers;
}
set
{
layers = value;
}
}
public Rect Rect
{
get
{
Vector3[] quad = new Vector3[4];
GetQuad(quad);
Rect r = GUtilities.GetRectContainsPoints(quad);
return r;
}
}
private Texture2D falloffTexture;
private Vector3[] worldPoints = new Vector3[4];
private Vector2[] uvPoints = new Vector2[4];
private Dictionary<string, RenderTexture> tempRt;
private Dictionary<string, RenderTexture> TempRt
{
get
{
if (tempRt == null)
{
tempRt = new Dictionary<string, RenderTexture>();
}
return tempRt;
}
}
private static Material albedoPainterMaterial;
private static Material AlbedoPainterMaterial
{
get
{
if (albedoPainterMaterial == null)
{
albedoPainterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.albedoPainterShader);
}
return albedoPainterMaterial;
}
}
private static Material metallicPainterMaterial;
private static Material MetallicPainterMaterial
{
get
{
if (metallicPainterMaterial == null)
{
metallicPainterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.metallicPainterShader);
}
return metallicPainterMaterial;
}
}
private static Material smoothnessPainterMaterial;
private static Material SmoothnessPainterMaterial
{
get
{
if (smoothnessPainterMaterial == null)
{
smoothnessPainterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.smoothnessPainterShader);
}
return smoothnessPainterMaterial;
}
}
private static Material splatPainterMaterial;
private static Material SplatPainterMaterial
{
get
{
if (splatPainterMaterial == null)
{
splatPainterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.splatPainterShader);
}
return splatPainterMaterial;
}
}
private void Reset()
{
position = Vector3.zero;
rotation = Quaternion.identity;
scale = Vector3.one * 100;
mask = null;
falloff = AnimationCurve.EaseInOut(0, 1, 1, 0);
channel = GTextureStampChannel.AlbedoMetallicSmoothness;
}
private void OnDisable()
{
ReleaseResources();
}
private void OnDestroy()
{
ReleaseResources();
}
private void ReleaseResources()
{
foreach (RenderTexture rt in TempRt.Values)
{
if (rt != null)
{
rt.Release();
GUtilities.DestroyObject(rt);
}
}
}
public void Apply()
{
if (falloffTexture != null)
Object.DestroyImmediate(falloffTexture);
Internal_UpdateFalloffTexture();
Internal_UpdateLayerTransitionTextures();
IEnumerator<GStylizedTerrain> terrains = GStylizedTerrain.ActiveTerrains.GetEnumerator();
while (terrains.MoveNext())
{
GStylizedTerrain t = terrains.Current;
if (groupId < 0 ||
(groupId >= 0 && groupId == t.GroupId))
{
Apply(t);
}
}
}
private void Apply(GStylizedTerrain t)
{
if (t.TerrainData == null)
return;
if (Layers.Count == 0)
return;
if (Channel == GTextureStampChannel.AlbedoMetallicSmoothness)
{
ApplyAlbedoMetallicSmoothness(t);
}
else if (Channel == GTextureStampChannel.Splat)
{
ApplySplat(t);
}
t.TerrainData.SetDirty(GTerrainData.DirtyFlags.Shading);
}
private void ApplySplat(GStylizedTerrain t)
{
int splatControlResolution = t.TerrainData.Shading.SplatControlResolution;
int controlMapCount = t.TerrainData.Shading.SplatControlMapCount;
RenderTexture[] rtControls = new RenderTexture[controlMapCount];
for (int i = 0; i < controlMapCount; ++i)
{
rtControls[i] = new RenderTexture(splatControlResolution, splatControlResolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
}
bool succeed = Internal_ApplySplat(t, rtControls);
if (!succeed)
{
for (int i = 0; i < controlMapCount; ++i)
{
rtControls[i].Release();
Object.DestroyImmediate(rtControls[i]);
}
return;
}
for (int i = 0; i < controlMapCount; ++i)
{
Texture2D splatControl = t.TerrainData.Shading.GetSplatControl(i);
RenderTexture.active = rtControls[i];
splatControl.ReadPixels(new Rect(0, 0, splatControlResolution, splatControlResolution), 0, 0);
splatControl.Apply();
RenderTexture.active = null;
rtControls[i].Release();
Object.DestroyImmediate(rtControls[i]);
}
}
private RenderTexture[] RenderBrushes(GStylizedTerrain t, Vector2[] uvPoints, int brushResolution)
{
RenderTexture[] brushes = new RenderTexture[Layers.Count];
for (int i = 0; i < Layers.Count; ++i)
{
brushes[i] = GetRenderTexture("brush" + i.ToString(), brushResolution);
GStampLayerMaskRenderer.Render(
brushes[i],
Layers[i],
t,
Matrix4x4.TRS(Position, Rotation, Scale),
Mask,
falloffTexture,
uvPoints,
EnableTerrainMask);
}
return brushes;
}
public bool Internal_ApplySplat(GStylizedTerrain t, RenderTexture[] rtControls)
{
GetQuad(worldPoints);
GetUvPoints(t, worldPoints, uvPoints);
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvPoints);
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
return false;
int brushResolution = t.TerrainData.Shading.SplatControlResolution;
RenderTexture[] brushes = RenderBrushes(t, uvPoints, brushResolution);
RenderTexture[] bg = new RenderTexture[rtControls.Length];
for (int i = 0; i < bg.Length; ++i)
{
bg[i] = GetRenderTexture("bg" + i.ToString(), brushResolution);
Texture2D splatControl = t.TerrainData.Shading.GetSplatControlOrDefault(i);
GCommon.CopyToRT(splatControl, bg[i]);
GCommon.CopyToRT(splatControl, rtControls[i]);
}
Material paintMaterial = SplatPainterMaterial;
paintMaterial.SetFloat("_Opacity", 1);
for (int i = 0; i < brushes.Length; ++i)
{
if (Layers[i].Ignore)
continue;
paintMaterial.SetTexture("_Mask", brushes[i]);
int controlMapCount = rtControls.Length;
for (int controlIndex = 0; controlIndex < controlMapCount; ++controlIndex)
{
GCommon.CopyToRT(bg[controlIndex], rtControls[controlIndex]);
paintMaterial.SetTexture("_MainTex", bg[controlIndex]);
if (Layers[i].SplatIndex / 4 == controlIndex)
{
paintMaterial.SetInt("_ChannelIndex", Layers[i].SplatIndex % 4);
}
else
{
paintMaterial.SetInt("_ChannelIndex", -1);
}
int pass = 0;
GCommon.DrawQuad(rtControls[controlIndex], GCommon.FullRectUvPoints, paintMaterial, pass);
GCommon.CopyToRT(rtControls[controlIndex], bg[controlIndex]);
}
}
t.TerrainData.SetDirty(GTerrainData.DirtyFlags.Shading);
return true;
}
private void ApplyAlbedoMetallicSmoothness(GStylizedTerrain t)
{
int albedoMapResolution = t.TerrainData.Shading.AlbedoMapResolution;
RenderTexture albedoRt = new RenderTexture(albedoMapResolution, albedoMapResolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
int metallicMapResolution = t.TerrainData.Shading.MetallicMapResolution;
RenderTexture metallicRt = new RenderTexture(metallicMapResolution, metallicMapResolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
bool succeed = Internal_ApplyAlbedoMetallicSmoothness(t, albedoRt, metallicRt);
if (!succeed)
return;
RenderTexture.active = albedoRt;
t.TerrainData.Shading.AlbedoMap.ReadPixels(new Rect(0, 0, albedoMapResolution, albedoMapResolution), 0, 0);
t.TerrainData.Shading.AlbedoMap.Apply();
RenderTexture.active = null;
RenderTexture.active = metallicRt;
t.TerrainData.Shading.MetallicMap.ReadPixels(new Rect(0, 0, metallicMapResolution, metallicMapResolution), 0, 0);
t.TerrainData.Shading.MetallicMap.Apply();
RenderTexture.active = null;
albedoRt.Release();
GUtilities.DestroyObject(albedoRt);
metallicRt.Release();
GUtilities.DestroyObject(metallicRt);
}
public bool Internal_ApplyAlbedoMetallicSmoothness(GStylizedTerrain t, RenderTexture albedoRt, RenderTexture metallicRt)
{
GetQuad(worldPoints);
GetUvPoints(t, worldPoints, uvPoints);
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvPoints);
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
return false;
int brushResolution = Mathf.Max(t.TerrainData.Shading.AlbedoMapResolution, t.TerrainData.Shading.MetallicMapResolution);
RenderTexture[] brushes = RenderBrushes(t, uvPoints, brushResolution);
RenderTexture bg0 = GetRenderTexture("bg0", brushResolution);
Texture2D albedoMap = t.TerrainData.Shading.AlbedoMapOrDefault;
GCommon.CopyToRT(albedoMap, bg0);
GCommon.CopyToRT(albedoMap, albedoRt);
Material mat = AlbedoPainterMaterial;
mat.SetFloat("_Opacity", 1);
for (int i = 0; i < brushes.Length; ++i)
{
if (Layers[i].Ignore)
continue;
mat.SetTexture("_MainTex", bg0);
mat.SetTexture("_Mask", brushes[i]);
mat.SetColor("_Color", Layers[i].Color);
int pass = 0;
GCommon.DrawQuad(albedoRt, GCommon.FullRectUvPoints, mat, pass);
GCommon.CopyToRT(albedoRt, bg0);
}
RenderTexture bg1 = GetRenderTexture("bg1", brushResolution);
Texture2D metallicMap = t.TerrainData.Shading.MetallicMapOrDefault;
GCommon.CopyToRT(metallicMap, bg1);
GCommon.CopyToRT(metallicMap, metallicRt);
mat = MetallicPainterMaterial;
mat.SetFloat("_Opacity", 1);
for (int i = 0; i < brushes.Length; ++i)
{
if (Layers[i].Ignore)
continue;
mat.SetTexture("_MainTex", bg1);
mat.SetTexture("_Mask", brushes[i]);
mat.SetColor("_Color", Color.white * Layers[i].Metallic);
int pass = 3; //fragSet
GCommon.DrawQuad(metallicRt, GCommon.FullRectUvPoints, mat, pass);
GCommon.CopyToRT(metallicRt, bg1);
}
mat = SmoothnessPainterMaterial;
mat.SetFloat("_Opacity", 1);
for (int i = 0; i < brushes.Length; ++i)
{
if (Layers[i].Ignore)
continue;
mat.SetTexture("_MainTex", bg1);
mat.SetTexture("_Mask", brushes[i]);
mat.SetColor("_Color", Color.white * Layers[i].Smoothness);
int pass = 3; //fragSet
GCommon.DrawQuad(metallicRt, GCommon.FullRectUvPoints, mat, pass);
GCommon.CopyToRT(metallicRt, bg1);
}
t.TerrainData.SetDirty(GTerrainData.DirtyFlags.Shading);
return true;
}
public void Internal_UpdateFalloffTexture()
{
if (falloffTexture != null)
GUtilities.DestroyObject(falloffTexture);
falloffTexture = GCommon.CreateTextureFromCurve(Falloff, 256, 1);
}
public void Internal_UpdateLayerTransitionTextures()
{
for (int i = 0; i < Layers.Count; ++i)
{
Layers[i].UpdateCurveTextures();
}
}
public Vector3[] GetQuad()
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
Vector3[] quad = new Vector3[4]
{
matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f)),
matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f)),
matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f)),
matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f))
};
return quad;
}
public void GetQuad(Vector3[] quad)
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
quad[0] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f));
quad[1] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f));
quad[2] = matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f));
quad[3] = matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f));
}
private void GetUvPoints(GStylizedTerrain t, Vector3[] worldPoint, Vector2[] uvPoint)
{
for (int i = 0; i < uvPoints.Length; ++i)
{
uvPoints[i] = t.WorldPointToUV(worldPoints[i]);
}
}
public void GetBox(Vector3[] box)
{
Matrix4x4 matrix = Matrix4x4.TRS(Position, Rotation, Scale);
box[0] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, -0.5f));
box[1] = matrix.MultiplyPoint(new Vector3(-0.5f, 0, 0.5f));
box[2] = matrix.MultiplyPoint(new Vector3(0.5f, 0, 0.5f));
box[3] = matrix.MultiplyPoint(new Vector3(0.5f, 0, -0.5f));
box[4] = matrix.MultiplyPoint(new Vector3(-0.5f, 1, -0.5f));
box[5] = matrix.MultiplyPoint(new Vector3(-0.5f, 1, 0.5f));
box[6] = matrix.MultiplyPoint(new Vector3(0.5f, 1, 0.5f));
box[7] = matrix.MultiplyPoint(new Vector3(0.5f, 1, -0.5f));
}
private RenderTexture GetRenderTexture(string key, int resolution)
{
if (!TempRt.ContainsKey(key) ||
TempRt[key] == null)
{
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
rt.wrapMode = TextureWrapMode.Clamp;
TempRt[key] = rt;
}
else if (TempRt[key].width != resolution || TempRt[key].height != resolution)
{
TempRt[key].Release();
Object.DestroyImmediate(TempRt[key]);
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
rt.wrapMode = TextureWrapMode.Clamp;
TempRt[key] = rt;
}
return TempRt[key];
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2e25ed844b59c434e9d2c74c099405cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: