Heroes_of_Hiis/Assets/Polaris - Low Poly Ecosystem/Polaris - Low Poly Terrain .../Runtime/Scripts/StampTool/GTextureStamper.cs

606 lines
20 KiB
C#
Raw Normal View History

#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