1
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99df235d1a63c114b8c74607080f9ad4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,69 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public static class GPaintToolUtilities
|
||||
{
|
||||
public static void AddCustomSpawnFilter(List<Type> filters)
|
||||
{
|
||||
for (int i = 0; i < GSpawnFilter.AllFilters.Count; ++i)
|
||||
{
|
||||
Type t = GSpawnFilter.AllFilters[i];
|
||||
if (!IsBuiltinFilter(t))
|
||||
filters.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsBuiltinFilter(Type t)
|
||||
{
|
||||
return t == typeof(GAlignToSurfaceFilter) ||
|
||||
t == typeof(GHeightConstraintFilter) ||
|
||||
t == typeof(GRotationRandomizeFilter) ||
|
||||
t == typeof(GScaleClampFilter) ||
|
||||
t == typeof(GScaleRandomizeFilter) ||
|
||||
t == typeof(GSlopeConstraintFilter);
|
||||
}
|
||||
|
||||
public static Matrix4x4 GetUnitRectToWorldMatrix(Vector3 position, float radius, float rotation)
|
||||
{
|
||||
Matrix4x4 m = Matrix4x4.TRS(position, Quaternion.Euler(0, rotation, 0), Vector3.one * radius);
|
||||
Matrix4x4 offset = Matrix4x4.Translate(new Vector3(-0.5f, 0, -0.5f));
|
||||
|
||||
return m * offset;
|
||||
}
|
||||
|
||||
public static List<GOverlapTestResult> OverlapTest(int groupId, Vector3 position, float radius, float rotation)
|
||||
{
|
||||
Vector3[] corners = GCommon.GetBrushQuadCorners(position, radius, rotation);
|
||||
return GCommon.OverlapTest(groupId, corners);
|
||||
}
|
||||
|
||||
public static Rect GetDirtyRect(GStylizedTerrain t, Vector3[] worldCorners)
|
||||
{
|
||||
Vector2[] uvCorners = new Vector2[worldCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = t.WorldPointToUV(worldCorners[i]);
|
||||
}
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
return dirtyRect;
|
||||
}
|
||||
|
||||
public static Vector2[] WorldToUvCorners(GStylizedTerrain t, Vector3[] worldCorners)
|
||||
{
|
||||
Vector2[] uvCorners = new Vector2[worldCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = t.WorldPointToUV(worldCorners[i]);
|
||||
}
|
||||
return uvCorners;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cb2040270de7b44b9e31cfc45208142
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,9 @@
|
||||
#if GRIFFIN
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public enum GPainterActionType
|
||||
{
|
||||
Normal, Negative, Alternative
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 977f5fe957b28b441ae4c38659d7bc73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,9 @@
|
||||
#if GRIFFIN
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public enum GPainterMouseEventType
|
||||
{
|
||||
Down, Drag, Up
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b72658925d377924a9088a0ca3394a48
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3be83a406f028364199cf9a7387ae4fa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,549 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Type = System.Type;
|
||||
using Rand = System.Random;
|
||||
#if UNITY_EDITOR
|
||||
using Pinwheel.Griffin.BackupTool;
|
||||
#endif
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[System.Serializable]
|
||||
[ExecuteInEditMode]
|
||||
public class GFoliagePainter : MonoBehaviour
|
||||
{
|
||||
private static readonly List<string> BUILTIN_PAINTER_NAME = new List<string>(new string[]
|
||||
{
|
||||
"GTreePainter",
|
||||
"GTreeScaler",
|
||||
"GGrassPainter",
|
||||
"GGrassScaler"
|
||||
});
|
||||
|
||||
private static List<Type> customPainterTypes;
|
||||
public static List<Type> CustomPainterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (customPainterTypes == null)
|
||||
customPainterTypes = new List<Type>();
|
||||
return customPainterTypes;
|
||||
}
|
||||
private set
|
||||
{
|
||||
customPainterTypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static string FoliagePainterInterfaceName
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(IGFoliagePainter).Name;
|
||||
}
|
||||
}
|
||||
|
||||
static GFoliagePainter()
|
||||
{
|
||||
RefreshCustomPainterTypes();
|
||||
}
|
||||
|
||||
public static void RefreshCustomPainterTypes()
|
||||
{
|
||||
List<Type> loadedTypes = GCommon.GetAllLoadedTypes();
|
||||
CustomPainterTypes = loadedTypes.FindAll(
|
||||
t => t.GetInterface(FoliagePainterInterfaceName) != null &&
|
||||
!BUILTIN_PAINTER_NAME.Contains(t.Name));
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int groupId;
|
||||
public int GroupId
|
||||
{
|
||||
get
|
||||
{
|
||||
return groupId;
|
||||
}
|
||||
set
|
||||
{
|
||||
groupId = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private GFoliagePaintingMode mode;
|
||||
public GFoliagePaintingMode Mode
|
||||
{
|
||||
get
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
set
|
||||
{
|
||||
mode = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int customPainterIndex;
|
||||
public int CustomPainterIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return customPainterIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
customPainterIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private string customPainterArgs;
|
||||
public string CustomPainterArgs
|
||||
{
|
||||
get
|
||||
{
|
||||
return customPainterArgs;
|
||||
}
|
||||
set
|
||||
{
|
||||
customPainterArgs = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool enableTerrainMask;
|
||||
public bool EnableTerrainMask
|
||||
{
|
||||
get
|
||||
{
|
||||
return enableTerrainMask;
|
||||
}
|
||||
set
|
||||
{
|
||||
enableTerrainMask = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IGFoliagePainter ActivePainter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Mode == GFoliagePaintingMode.PaintTree)
|
||||
{
|
||||
return new GTreePainter();
|
||||
}
|
||||
else if (Mode == GFoliagePaintingMode.ScaleTree)
|
||||
{
|
||||
return new GTreeScaler();
|
||||
}
|
||||
else if (Mode == GFoliagePaintingMode.PaintGrass)
|
||||
{
|
||||
return new GGrassPainter();
|
||||
}
|
||||
else if (Mode == GFoliagePaintingMode.ScaleGrass)
|
||||
{
|
||||
return new GGrassScaler();
|
||||
}
|
||||
else if (mode == GFoliagePaintingMode.Custom)
|
||||
{
|
||||
if (CustomPainterIndex >= 0 && CustomPainterIndex < CustomPainterTypes.Count)
|
||||
return System.Activator.CreateInstance(CustomPainterTypes[CustomPainterIndex]) as IGFoliagePainter;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRadius;
|
||||
public float BrushRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRadius;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRadius = Mathf.Max(0.01f, value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRadiusJitter;
|
||||
public float BrushRadiusJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRadiusJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRadiusJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRotation;
|
||||
public float BrushRotation
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRotation;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRotation = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRotationJitter;
|
||||
public float BrushRotationJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRotationJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRotationJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int brushDensity;
|
||||
public int BrushDensity
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushDensity;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushDensity = Mathf.Clamp(value, 1, 100);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushDensityJitter;
|
||||
public float BrushDensityJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushDensityJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushDensityJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushScatter;
|
||||
public float BrushScatter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushScatter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushScatter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushScatterJitter;
|
||||
public float BrushScatterJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushScatterJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushScatterJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<Texture2D> brushMasks;
|
||||
public List<Texture2D> BrushMasks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (brushMasks == null)
|
||||
brushMasks = new List<Texture2D>();
|
||||
return brushMasks;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushMasks = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int selectedBrushMaskIndex;
|
||||
public int SelectedBrushMaskIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return selectedBrushMaskIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (BrushMasks.Count > 0)
|
||||
selectedBrushMaskIndex = Mathf.Clamp(value, 0, BrushMasks.Count);
|
||||
else
|
||||
selectedBrushMaskIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<int> selectedTreeIndices;
|
||||
public List<int> SelectedTreeIndices
|
||||
{
|
||||
get
|
||||
{
|
||||
if (selectedTreeIndices == null)
|
||||
{
|
||||
selectedTreeIndices = new List<int>();
|
||||
}
|
||||
return selectedTreeIndices;
|
||||
}
|
||||
set
|
||||
{
|
||||
selectedTreeIndices = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<int> selectedGrassIndices;
|
||||
public List<int> SelectedGrassIndices
|
||||
{
|
||||
get
|
||||
{
|
||||
if (selectedGrassIndices == null)
|
||||
{
|
||||
selectedGrassIndices = new List<int>();
|
||||
}
|
||||
return selectedGrassIndices;
|
||||
}
|
||||
set
|
||||
{
|
||||
selectedGrassIndices = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float eraseRatio;
|
||||
public float EraseRatio
|
||||
{
|
||||
get
|
||||
{
|
||||
return eraseRatio;
|
||||
}
|
||||
set
|
||||
{
|
||||
eraseRatio = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float scaleStrength;
|
||||
public float ScaleStrength
|
||||
{
|
||||
get
|
||||
{
|
||||
return scaleStrength;
|
||||
}
|
||||
set
|
||||
{
|
||||
scaleStrength = Mathf.Max(0, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ReloadBrushMasks();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
GroupId = 0;
|
||||
Mode = GFoliagePaintingMode.PaintTree;
|
||||
BrushRadius = 50;
|
||||
BrushRadiusJitter = 0;
|
||||
BrushDensity = 1;
|
||||
BrushDensityJitter = 0;
|
||||
BrushRotation = 0;
|
||||
BrushRotationJitter = 0;
|
||||
EraseRatio = 1;
|
||||
ScaleStrength = 1;
|
||||
}
|
||||
|
||||
public void ReloadBrushMasks()
|
||||
{
|
||||
BrushMasks = new List<Texture2D>(Resources.LoadAll<Texture2D>(GCommon.BRUSH_MASK_RESOURCES_PATH));
|
||||
}
|
||||
|
||||
public void Paint(GFoliagePainterArgs args)
|
||||
{
|
||||
IGFoliagePainter p = ActivePainter;
|
||||
if (p == null)
|
||||
return;
|
||||
|
||||
args.Radius = BrushRadius;
|
||||
args.Rotation = BrushRotation;
|
||||
args.Density = BrushDensity;
|
||||
args.EraseRatio = EraseRatio;
|
||||
args.ScaleStrength = ScaleStrength;
|
||||
args.TreeIndices = SelectedTreeIndices;
|
||||
args.GrassIndices = SelectedGrassIndices;
|
||||
|
||||
args.CustomArgs = CustomPainterArgs;
|
||||
if (SelectedBrushMaskIndex >= 0 && SelectedBrushMaskIndex < BrushMasks.Count)
|
||||
{
|
||||
args.Mask = BrushMasks[SelectedBrushMaskIndex];
|
||||
}
|
||||
args.Filters = GetComponents<GSpawnFilter>();
|
||||
args.EnableTerrainMask = EnableTerrainMask;
|
||||
|
||||
ProcessBrushDynamic(ref args);
|
||||
Vector3[] corners = GCommon.GetBrushQuadCorners(args.HitPoint, args.Radius, args.Rotation);
|
||||
args.WorldPointCorners = corners;
|
||||
|
||||
List<GStylizedTerrain> overlappedTerrain = GUtilities.ExtractTerrainsFromOverlapTest(GPaintToolUtilities.OverlapTest(GroupId, args.HitPoint, args.Radius, args.Rotation));
|
||||
#if UNITY_EDITOR
|
||||
if ((args.MouseEventType == GPainterMouseEventType.Down ||
|
||||
args.MouseEventType == GPainterMouseEventType.Drag) &&
|
||||
args.ShouldCommitNow == false)
|
||||
{
|
||||
Editor_CreateInitialHistoryEntry(args, overlappedTerrain);
|
||||
}
|
||||
#endif
|
||||
|
||||
foreach (GStylizedTerrain t in overlappedTerrain)
|
||||
{
|
||||
p.Paint(t, args);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
EditedTerrains.UnionWith(overlappedTerrain);
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
Editor_CreateHistory(args);
|
||||
currentInitialBackupName = null;
|
||||
InitialRecordedTerrains.Clear();
|
||||
EditedTerrains.Clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private HashSet<GStylizedTerrain> initialRecordedTerrains;
|
||||
private HashSet<GStylizedTerrain> InitialRecordedTerrains
|
||||
{
|
||||
get
|
||||
{
|
||||
if (initialRecordedTerrains == null)
|
||||
{
|
||||
initialRecordedTerrains = new HashSet<GStylizedTerrain>();
|
||||
}
|
||||
return initialRecordedTerrains;
|
||||
}
|
||||
}
|
||||
|
||||
private HashSet<GStylizedTerrain> editedTerrains;
|
||||
private HashSet<GStylizedTerrain> EditedTerrains
|
||||
{
|
||||
get
|
||||
{
|
||||
if (editedTerrains == null)
|
||||
{
|
||||
editedTerrains = new HashSet<GStylizedTerrain>();
|
||||
}
|
||||
return editedTerrains;
|
||||
}
|
||||
}
|
||||
|
||||
private string currentInitialBackupName;
|
||||
|
||||
private void Editor_CreateInitialHistoryEntry(GFoliagePainterArgs args, List<GStylizedTerrain> overlappedTerrains)
|
||||
{
|
||||
if (!GEditorSettings.Instance.paintTools.enableHistory)
|
||||
return;
|
||||
if (overlappedTerrains.Count == 0)
|
||||
return;
|
||||
|
||||
List<GTerrainResourceFlag> flags = new List<GTerrainResourceFlag>();
|
||||
flags.AddRange(ActivePainter.GetResourceFlagForHistory(args));
|
||||
|
||||
if (InitialRecordedTerrains.Count == 0)
|
||||
{
|
||||
currentInitialBackupName = GBackup.TryCreateInitialBackup(ActivePainter.HistoryPrefix, overlappedTerrains[0], flags, false);
|
||||
if (!string.IsNullOrEmpty(currentInitialBackupName))
|
||||
{
|
||||
InitialRecordedTerrains.Add(overlappedTerrains[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(currentInitialBackupName))
|
||||
{
|
||||
for (int i = 0; i < overlappedTerrains.Count; ++i)
|
||||
{
|
||||
if (InitialRecordedTerrains.Contains(overlappedTerrains[i]))
|
||||
continue;
|
||||
GBackup.BackupTerrain(overlappedTerrains[i], currentInitialBackupName, flags);
|
||||
InitialRecordedTerrains.Add(overlappedTerrains[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Editor_CreateHistory(GFoliagePainterArgs args)
|
||||
{
|
||||
if (!GEditorSettings.Instance.paintTools.enableHistory)
|
||||
return;
|
||||
if (EditedTerrains.Count == 0)
|
||||
return;
|
||||
|
||||
List<GTerrainResourceFlag> flags = new List<GTerrainResourceFlag>();
|
||||
flags.AddRange(ActivePainter.GetResourceFlagForHistory(args));
|
||||
|
||||
List<GStylizedTerrain> terrainList = new List<GStylizedTerrain>(EditedTerrains);
|
||||
string backupName = GBackup.TryCreateBackup(ActivePainter.HistoryPrefix, terrainList[0], flags, false);
|
||||
if (!string.IsNullOrEmpty(backupName))
|
||||
{
|
||||
for (int i = 1; i < terrainList.Count; ++i)
|
||||
{
|
||||
GBackup.BackupTerrain(terrainList[i], backupName, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private Rand GetRandomGenerator()
|
||||
{
|
||||
return new Rand(Time.frameCount);
|
||||
}
|
||||
|
||||
private void ProcessBrushDynamic(ref GFoliagePainterArgs args)
|
||||
{
|
||||
Rand rand = GetRandomGenerator();
|
||||
args.Radius -= BrushRadius * BrushRadiusJitter * (float)rand.NextDouble();
|
||||
args.Rotation += Mathf.Sign((float)rand.NextDouble() - 0.5f) * BrushRotation * BrushRotationJitter * (float)rand.NextDouble();
|
||||
args.Density -= Mathf.RoundToInt(BrushDensity * BrushDensityJitter * (float)rand.NextDouble());
|
||||
|
||||
Vector3 scatterDir = new Vector3((float)(rand.NextDouble() * 2 - 1), 0, (float)(rand.NextDouble() * 2 - 1)).normalized;
|
||||
float scatterLengthMultiplier = BrushScatter - (float)rand.NextDouble() * BrushScatterJitter;
|
||||
float scatterLength = args.Radius * scatterLengthMultiplier;
|
||||
|
||||
args.HitPoint += scatterDir * scatterLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e2008cbec175ad4ebdeee8f0afc9a7e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,27 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public struct GFoliagePainterArgs
|
||||
{
|
||||
public Vector3 HitPoint { get; set; }
|
||||
public Vector3[] WorldPointCorners { get; internal set; }
|
||||
public Texture2D Mask { get; set; }
|
||||
public bool EnableTerrainMask { get; set; }
|
||||
public float Radius { get; internal set; }
|
||||
public float Rotation { get; internal set; }
|
||||
public int Density { get; internal set; }
|
||||
public float EraseRatio { get; internal set; }
|
||||
public float ScaleStrength { get; internal set; }
|
||||
public List<int> TreeIndices { get; set; }
|
||||
public List<int> GrassIndices { get; set; }
|
||||
public string CustomArgs { get; internal set; }
|
||||
public GPainterMouseEventType MouseEventType { get; set; }
|
||||
public GPainterActionType ActionType { get; set; }
|
||||
public GSpawnFilter[] Filters { get; internal set; }
|
||||
public bool ShouldCommitNow { get; set; }
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0e54795f5f5fcb4eb25ef58da3ba1b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,9 @@
|
||||
#if GRIFFIN
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public enum GFoliagePaintingMode
|
||||
{
|
||||
PaintTree, ScaleTree, PaintGrass, ScaleGrass, Custom
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea1a8b6e9c28a3c4e8aa0a0ed33395ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,352 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GGrassPainter : IGFoliagePainter
|
||||
{
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Paint grass onto the terrain.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold Ctrl & Left Mouse to erase instances of the same type.\n" +
|
||||
" - Hold Shift & Left Mouse to erase all instances in range.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Paint Grass";
|
||||
}
|
||||
}
|
||||
|
||||
public List<Type> SuitableFilterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>(new Type[]
|
||||
{
|
||||
typeof(GHeightConstraintFilter),
|
||||
typeof(GSlopeConstraintFilter),
|
||||
typeof(GRotationRandomizeFilter),
|
||||
typeof(GScaleRandomizeFilter),
|
||||
typeof(GScaleClampFilter)
|
||||
});
|
||||
GPaintToolUtilities.AddCustomSpawnFilter(types);
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GFoliagePainterArgs args)
|
||||
{
|
||||
return GCommon.GrassInstancesResourceFlags;
|
||||
}
|
||||
|
||||
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GFoliagePainterArgs args)
|
||||
{
|
||||
if (args.GrassIndices.Count == 0)
|
||||
return;
|
||||
if (terrain.TerrainData == null)
|
||||
return;
|
||||
if (terrain.TerrainData.Foliage.Grasses == null)
|
||||
return;
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up || args.ShouldCommitNow)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage);
|
||||
GRuntimeSettings.Instance.isEditingFoliage = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]);
|
||||
}
|
||||
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
|
||||
return;
|
||||
|
||||
GRuntimeSettings.Instance.isEditingFoliage = true;
|
||||
if (args.ActionType == GPainterActionType.Normal)
|
||||
{
|
||||
HandleSpawnGrass(terrain, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleEraseGrass(terrain, args);
|
||||
}
|
||||
|
||||
GUtilities.MarkCurrentSceneDirty();
|
||||
}
|
||||
|
||||
private void HandleSpawnGrass(GStylizedTerrain terrain, GFoliagePainterArgs args)
|
||||
{
|
||||
int grassIndex = -1;
|
||||
Vector3 randomPos = Vector3.zero;
|
||||
Vector3 rayOrigin = Vector3.zero;
|
||||
Vector3 rayDirection = Vector3.down;
|
||||
float sqrtTwo = Mathf.Sqrt(2);
|
||||
Ray ray = new Ray();
|
||||
RaycastHit samplePoint;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Vector2 samplePointTexcoord = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
int prototypeCount = terrain.TerrainData.Foliage.Grasses.Prototypes.Count;
|
||||
int sampleCount = args.Density;
|
||||
List<GGrassInstance> newInstances = new List<GGrassInstance>();
|
||||
for (int i = 0; i < sampleCount; ++i)
|
||||
{
|
||||
grassIndex = args.GrassIndices[Random.Range(0, args.GrassIndices.Count)];
|
||||
if (grassIndex < 0 || grassIndex >= prototypeCount)
|
||||
continue;
|
||||
GGrassPrototype proto = terrain.TerrainData.Foliage.Grasses.Prototypes[grassIndex];
|
||||
randomPos = args.HitPoint + Random.insideUnitSphere * args.Radius * sqrtTwo;
|
||||
rayOrigin.Set(
|
||||
randomPos.x,
|
||||
10000,
|
||||
randomPos.z);
|
||||
ray.origin = rayOrigin;
|
||||
ray.direction = rayDirection;
|
||||
|
||||
bool isRaycastHit = false;
|
||||
if (terrain.TerrainData.Foliage.GrassSnapMode == GSnapMode.Terrain)
|
||||
{
|
||||
isRaycastHit = terrain.Raycast(ray, out samplePoint, float.MaxValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LayerMask mask = LayerMask.GetMask(GStylizedTerrain.RAYCAST_LAYER);
|
||||
mask |= terrain.TerrainData.Foliage.GrassSnapLayerMask;
|
||||
int raycastLayer = mask.value;
|
||||
isRaycastHit = Physics.Raycast(ray, out samplePoint, float.MaxValue, raycastLayer);
|
||||
}
|
||||
|
||||
if (isRaycastHit)
|
||||
{
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(samplePoint.point.x, samplePoint.point.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(samplePoint.point.x, samplePoint.point.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//sample mask
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale)
|
||||
continue;
|
||||
}
|
||||
//sample terrain mask
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
samplePointTexcoord = samplePoint.textureCoord;
|
||||
maskColor = terrainMask.GetPixelBilinear(samplePointTexcoord.x, samplePointTexcoord.y);
|
||||
if (Random.value < maskColor.r)
|
||||
continue;
|
||||
}
|
||||
|
||||
//apply filter
|
||||
GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create();
|
||||
filterArgs.Terrain = terrain;
|
||||
filterArgs.Position = samplePoint.point;
|
||||
filterArgs.SurfaceNormal = samplePoint.normal;
|
||||
filterArgs.SurfaceTexcoord = samplePoint.textureCoord;
|
||||
|
||||
List<Type> suitableFilter = SuitableFilterTypes;
|
||||
if (args.Filters != null)
|
||||
{
|
||||
for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex)
|
||||
{
|
||||
if (args.Filters[fIndex] != null &&
|
||||
args.Filters[fIndex].Ignore != true)
|
||||
{
|
||||
if (suitableFilter.Contains(args.Filters[fIndex].GetType()))
|
||||
args.Filters[fIndex].Apply(ref filterArgs);
|
||||
}
|
||||
if (filterArgs.ShouldExclude)
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Quaternion rot = filterArgs.Rotation;
|
||||
if (proto.AlignToSurface)
|
||||
{
|
||||
Quaternion currentRotationY = Quaternion.Euler(0, rot.eulerAngles.y, 0);
|
||||
Quaternion rotationXZ = Quaternion.FromToRotation(Vector3.up, samplePoint.normal);
|
||||
rot = rotationXZ * currentRotationY;
|
||||
}
|
||||
else
|
||||
{
|
||||
Quaternion currentRotationY = Quaternion.Euler(0, rot.eulerAngles.y, 0);
|
||||
rot = currentRotationY;
|
||||
}
|
||||
filterArgs.Rotation = rot;
|
||||
|
||||
//spawn
|
||||
if (filterArgs.ShouldExclude)
|
||||
continue;
|
||||
|
||||
GGrassInstance grass = GGrassInstance.Create(grassIndex);
|
||||
grass.Position = terrain.WorldPointToNormalized(filterArgs.Position);
|
||||
grass.Rotation = filterArgs.Rotation;
|
||||
grass.Scale = filterArgs.Scale;
|
||||
newInstances.Add(grass);
|
||||
}
|
||||
}
|
||||
|
||||
terrain.TerrainData.Foliage.AddGrassInstances(newInstances);
|
||||
if (clonedMask != null)
|
||||
Object.DestroyImmediate(clonedMask);
|
||||
}
|
||||
|
||||
private void HandleEraseGrass(GStylizedTerrain terrain, GFoliagePainterArgs args)
|
||||
{
|
||||
Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]);
|
||||
}
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int grassIndex = -1;
|
||||
Vector3 terrainSize = new Vector3(
|
||||
terrain.TerrainData.Geometry.Width,
|
||||
terrain.TerrainData.Geometry.Height,
|
||||
terrain.TerrainData.Geometry.Length);
|
||||
Vector3 localPos = Vector3.zero;
|
||||
Vector3 worldPos = Vector3.zero;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
GGrassPatch[] patches = terrain.TerrainData.Foliage.GrassPatches;
|
||||
|
||||
for (int i = 0; i < patches.Length; ++i)
|
||||
{
|
||||
if (!patches[i].GetUvRange().Overlaps(dirtyRect))
|
||||
continue;
|
||||
|
||||
if (args.ActionType == GPainterActionType.Alternative)
|
||||
patches[i].RequireFullUpdate = true;
|
||||
|
||||
patches[i].RemoveInstances(grass =>
|
||||
{
|
||||
grassIndex = args.GrassIndices[Random.Range(0, args.GrassIndices.Count)];
|
||||
localPos.Set(
|
||||
grass.position.x * terrainSize.x,
|
||||
grass.position.y * terrainSize.y,
|
||||
grass.position.z * terrainSize.z);
|
||||
worldPos = terrain.transform.TransformPoint(localPos);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//sample mask
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale * args.EraseRatio)
|
||||
return false;
|
||||
}
|
||||
//sample terrain mask
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
maskColor = terrainMask.GetPixelBilinear(grass.position.x, grass.position.z);
|
||||
if (Random.value < maskColor.r)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.ActionType == GPainterActionType.Negative &&
|
||||
grass.PrototypeIndex == grassIndex)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (args.ActionType == GPainterActionType.Alternative)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (clonedMask != null)
|
||||
Object.DestroyImmediate(clonedMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6eb2bfcbecc9f74997beb3f47eb93f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,196 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GGrassScaler : IGFoliagePainter
|
||||
{
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Scale grass instances.\n" +
|
||||
" - Hold Left Mouse to scale up.\n" +
|
||||
" - Hold Ctrl & Left Mouse to scale down.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Scale Grass";
|
||||
}
|
||||
}
|
||||
|
||||
public List<Type> SuitableFilterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>(new Type[]
|
||||
{
|
||||
typeof(GScaleClampFilter)
|
||||
});
|
||||
GPaintToolUtilities.AddCustomSpawnFilter(types);
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GFoliagePainterArgs args)
|
||||
{
|
||||
return GCommon.GrassInstancesResourceFlags;
|
||||
}
|
||||
|
||||
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GFoliagePainterArgs args)
|
||||
{
|
||||
if (args.GrassIndices.Count == 0)
|
||||
return;
|
||||
if (terrain.TerrainData == null)
|
||||
return;
|
||||
if (terrain.TerrainData.Foliage.Grasses == null)
|
||||
return;
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up || args.ShouldCommitNow)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage);
|
||||
GRuntimeSettings.Instance.isEditingFoliage = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]);
|
||||
}
|
||||
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
|
||||
return;
|
||||
|
||||
GRuntimeSettings.Instance.isEditingFoliage = true;
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
int multiplier = args.ActionType == GPainterActionType.Normal ? 1 : -1;
|
||||
int grassIndex = -1;
|
||||
Vector3 terrainSize = new Vector3(
|
||||
terrain.TerrainData.Geometry.Width,
|
||||
terrain.TerrainData.Geometry.Height,
|
||||
terrain.TerrainData.Geometry.Length);
|
||||
Vector3 localPos = Vector3.zero;
|
||||
Vector3 worldPos = Vector3.zero;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
Vector3 scale = Vector3.zero;
|
||||
|
||||
GGrassPatch[] patches = terrain.TerrainData.Foliage.GrassPatches;
|
||||
for (int p = 0; p < patches.Length; ++p)
|
||||
{
|
||||
if (!patches[p].GetUvRange().Overlaps(dirtyRect))
|
||||
continue;
|
||||
|
||||
List<GGrassInstance> instances = patches[p].Instances;
|
||||
int instanceCount = instances.Count;
|
||||
for (int i = 0; i < instanceCount; ++i)
|
||||
{
|
||||
grassIndex = args.GrassIndices[Random.Range(0, args.GrassIndices.Count)];
|
||||
GGrassInstance grass = instances[i];
|
||||
if (grass.PrototypeIndex != grassIndex)
|
||||
continue;
|
||||
|
||||
localPos.Set(
|
||||
grass.position.x * terrainSize.x,
|
||||
grass.position.y * terrainSize.y,
|
||||
grass.position.z * terrainSize.z);
|
||||
worldPos = terrain.transform.TransformPoint(localPos);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale)
|
||||
continue;
|
||||
}
|
||||
//sample terrain mask
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
maskColor = terrainMask.GetPixelBilinear(grass.position.x, grass.position.z);
|
||||
if (Random.value < maskColor.r)
|
||||
continue;
|
||||
}
|
||||
|
||||
scale.Set(
|
||||
Mathf.Max(0, grass.scale.x + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME),
|
||||
Mathf.Max(0, grass.scale.y + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME),
|
||||
Mathf.Max(0, grass.scale.z + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME));
|
||||
|
||||
GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create();
|
||||
filterArgs.Terrain = terrain;
|
||||
filterArgs.Position = worldPos;
|
||||
filterArgs.Rotation = grass.Rotation;
|
||||
filterArgs.Scale = scale;
|
||||
List<Type> suitableFilter = SuitableFilterTypes;
|
||||
if (args.Filters != null)
|
||||
{
|
||||
for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex)
|
||||
{
|
||||
if (args.Filters[fIndex] != null &&
|
||||
args.Filters[fIndex].Ignore != true)
|
||||
{
|
||||
if (suitableFilter.Contains(args.Filters[fIndex].GetType()))
|
||||
args.Filters[fIndex].Apply(ref filterArgs);
|
||||
}
|
||||
if (filterArgs.ShouldExclude)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
grass.scale = filterArgs.Scale;
|
||||
instances[i] = grass;
|
||||
}
|
||||
patches[p].Changed();
|
||||
}
|
||||
|
||||
terrain.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect);
|
||||
GUtilities.MarkCurrentSceneDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3af3c0404f111ae4e81e320eb236046e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,325 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GTreePainter : IGFoliagePainter
|
||||
{
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Paint tree onto the terrain.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold Ctrl & Left Mouse to erase instances of the same type.\n" +
|
||||
" - Hold Shift & Left Mouse to erase all instances in range.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Paint Tree";
|
||||
}
|
||||
}
|
||||
|
||||
public List<Type> SuitableFilterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>(new Type[]
|
||||
{
|
||||
typeof(GHeightConstraintFilter),
|
||||
typeof(GSlopeConstraintFilter),
|
||||
typeof(GRotationRandomizeFilter),
|
||||
typeof(GScaleRandomizeFilter),
|
||||
typeof(GScaleClampFilter)
|
||||
});
|
||||
|
||||
GPaintToolUtilities.AddCustomSpawnFilter(types);
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GFoliagePainterArgs args)
|
||||
{
|
||||
return GCommon.TreeInstancesResourceFlags;
|
||||
}
|
||||
|
||||
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GFoliagePainterArgs args)
|
||||
{
|
||||
if (args.TreeIndices.Count == 0)
|
||||
return;
|
||||
if (terrain.TerrainData == null)
|
||||
return;
|
||||
if (terrain.TerrainData.Foliage.Trees == null)
|
||||
return;
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up || args.ShouldCommitNow)
|
||||
{
|
||||
GCommon.SetDirty(terrain.TerrainData.Foliage);
|
||||
terrain.UpdateTreesPosition();
|
||||
terrain.TerrainData.Foliage.ClearTreeDirtyRegions();
|
||||
GRuntimeSettings.Instance.isEditingFoliage = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]);
|
||||
}
|
||||
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
|
||||
return;
|
||||
|
||||
GRuntimeSettings.Instance.isEditingFoliage = true;
|
||||
if (args.ActionType == GPainterActionType.Normal)
|
||||
{
|
||||
HandleSpawnTree(terrain, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleEraseTree(terrain, args);
|
||||
}
|
||||
|
||||
terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage);
|
||||
GUtilities.MarkCurrentSceneDirty();
|
||||
}
|
||||
|
||||
private void HandleSpawnTree(GStylizedTerrain terrain, GFoliagePainterArgs args)
|
||||
{
|
||||
int treeIndex = -1;
|
||||
Vector3 randomPos = Vector3.zero;
|
||||
Vector3 rayOrigin = Vector3.zero;
|
||||
Vector3 rayDirection = Vector3.down;
|
||||
float sqrtTwo = Mathf.Sqrt(2);
|
||||
Ray ray = new Ray();
|
||||
RaycastHit samplePoint;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Vector2 samplePointTexcoord = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
int prototypeCount = terrain.TerrainData.Foliage.Trees.Prototypes.Count;
|
||||
List<GTreeInstance> newInstances = new List<GTreeInstance>();
|
||||
for (int i = 0; i < args.Density; ++i)
|
||||
{
|
||||
treeIndex = args.TreeIndices[Random.Range(0, args.TreeIndices.Count)];
|
||||
if (treeIndex < 0 || treeIndex >= prototypeCount)
|
||||
continue;
|
||||
randomPos = args.HitPoint + Random.insideUnitSphere * args.Radius * sqrtTwo;
|
||||
rayOrigin.Set(
|
||||
randomPos.x,
|
||||
10000,
|
||||
randomPos.z);
|
||||
ray.origin = rayOrigin;
|
||||
ray.direction = rayDirection;
|
||||
|
||||
bool isRaycastHit = false;
|
||||
if (terrain.TerrainData.Foliage.TreeSnapMode == GSnapMode.Terrain)
|
||||
{
|
||||
isRaycastHit = terrain.Raycast(ray, out samplePoint, float.MaxValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LayerMask mask = LayerMask.GetMask(GStylizedTerrain.RAYCAST_LAYER);
|
||||
mask |= terrain.TerrainData.Foliage.TreeSnapLayerMask;
|
||||
int raycastLayer = mask.value;
|
||||
isRaycastHit = Physics.Raycast(ray, out samplePoint, float.MaxValue, raycastLayer);
|
||||
}
|
||||
|
||||
if (isRaycastHit)
|
||||
{
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(samplePoint.point.x, samplePoint.point.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(samplePoint.point.x, samplePoint.point.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//sample mask
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale)
|
||||
continue;
|
||||
}
|
||||
|
||||
//sample terrain mask
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
samplePointTexcoord = samplePoint.textureCoord;
|
||||
maskColor = terrainMask.GetPixelBilinear(samplePointTexcoord.x, samplePointTexcoord.y);
|
||||
if (Random.value < maskColor.r)
|
||||
continue;
|
||||
}
|
||||
|
||||
//apply filter
|
||||
GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create();
|
||||
filterArgs.Terrain = terrain;
|
||||
filterArgs.Position = samplePoint.point;
|
||||
filterArgs.SurfaceNormal = samplePoint.normal;
|
||||
filterArgs.SurfaceTexcoord = samplePoint.textureCoord;
|
||||
|
||||
List<Type> suitableFilter = SuitableFilterTypes;
|
||||
if (args.Filters != null)
|
||||
{
|
||||
for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex)
|
||||
{
|
||||
if (args.Filters[fIndex] != null &&
|
||||
args.Filters[fIndex].Ignore != true)
|
||||
{
|
||||
if (suitableFilter.Contains(args.Filters[fIndex].GetType()))
|
||||
args.Filters[fIndex].Apply(ref filterArgs);
|
||||
}
|
||||
if (filterArgs.ShouldExclude)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//spawn
|
||||
if (filterArgs.ShouldExclude)
|
||||
continue;
|
||||
|
||||
GTreeInstance tree = GTreeInstance.Create(treeIndex);
|
||||
tree.Position = terrain.WorldPointToNormalized(filterArgs.Position);
|
||||
tree.Rotation = filterArgs.Rotation;
|
||||
tree.Scale = filterArgs.Scale;
|
||||
newInstances.Add(tree);
|
||||
}
|
||||
}
|
||||
terrain.TerrainData.Foliage.AddTreeInstances(newInstances);
|
||||
newInstances.Clear();
|
||||
|
||||
if (clonedMask != null)
|
||||
Object.DestroyImmediate(clonedMask);
|
||||
}
|
||||
|
||||
private void HandleEraseTree(GStylizedTerrain terrain, GFoliagePainterArgs args)
|
||||
{
|
||||
int treeIndex = -1;
|
||||
Vector3 terrainSize = new Vector3(
|
||||
terrain.TerrainData.Geometry.Width,
|
||||
terrain.TerrainData.Geometry.Height,
|
||||
terrain.TerrainData.Geometry.Length);
|
||||
Vector3 localPos = Vector3.zero;
|
||||
Vector3 worldPos = Vector3.zero;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
terrain.TerrainData.Foliage.RemoveTreeInstances(tree =>
|
||||
{
|
||||
treeIndex = args.TreeIndices[Random.Range(0, args.TreeIndices.Count)];
|
||||
localPos.Set(
|
||||
tree.position.x * terrainSize.x,
|
||||
tree.position.y * terrainSize.y,
|
||||
tree.position.z * terrainSize.z);
|
||||
worldPos = terrain.transform.TransformPoint(localPos);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//sample mask
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale * args.EraseRatio)
|
||||
return false;
|
||||
}
|
||||
|
||||
//sample terrain mask
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
maskColor = terrainMask.GetPixelBilinear(tree.position.x, tree.position.z);
|
||||
if (Random.value < maskColor.r)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.ActionType == GPainterActionType.Negative &&
|
||||
tree.PrototypeIndex == treeIndex)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (args.ActionType == GPainterActionType.Alternative)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (clonedMask != null)
|
||||
Object.DestroyImmediate(clonedMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7ecf6fdd323a96479394d1e960eba61
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,190 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GTreeScaler : IGFoliagePainter
|
||||
{
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Scale tree instances.\n" +
|
||||
" - Hold Left Mouse to scale up.\n" +
|
||||
" - Hold Ctrl & Left Mouse to scale down.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Scale Tree";
|
||||
}
|
||||
}
|
||||
|
||||
public List<Type> SuitableFilterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>(new Type[]
|
||||
{
|
||||
typeof(GScaleClampFilter)
|
||||
});
|
||||
GPaintToolUtilities.AddCustomSpawnFilter(types);
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GFoliagePainterArgs args)
|
||||
{
|
||||
return GCommon.TreeInstancesResourceFlags;
|
||||
}
|
||||
|
||||
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GFoliagePainterArgs args)
|
||||
{
|
||||
if (args.TreeIndices.Count == 0)
|
||||
return;
|
||||
if (terrain.TerrainData == null)
|
||||
return;
|
||||
if (terrain.TerrainData.Foliage.Trees == null)
|
||||
return;
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up || args.ShouldCommitNow)
|
||||
{
|
||||
terrain.UpdateTreesPosition();
|
||||
terrain.TerrainData.Foliage.ClearTreeDirtyRegions();
|
||||
GCommon.SetDirty(terrain.TerrainData.Foliage);
|
||||
GRuntimeSettings.Instance.isEditingFoliage = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]);
|
||||
}
|
||||
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
|
||||
return;
|
||||
|
||||
GRuntimeSettings.Instance.isEditingFoliage = true;
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
int multiplier = args.ActionType == GPainterActionType.Normal ? 1 : -1;
|
||||
int treeIndex = -1;
|
||||
Vector3 terrainSize = new Vector3(
|
||||
terrain.TerrainData.Geometry.Width,
|
||||
terrain.TerrainData.Geometry.Height,
|
||||
terrain.TerrainData.Geometry.Length);
|
||||
Vector3 localPos = Vector3.zero;
|
||||
Vector3 worldPos = Vector3.zero;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
Vector3 scale = Vector3.zero;
|
||||
List<GTreeInstance> instances = terrain.TerrainData.Foliage.TreeInstances;
|
||||
int instanceCount = instances.Count;
|
||||
for (int i = 0; i < instanceCount; ++i)
|
||||
{
|
||||
treeIndex = args.TreeIndices[Random.Range(0, args.TreeIndices.Count)];
|
||||
GTreeInstance tree = instances[i];
|
||||
if (tree.PrototypeIndex != treeIndex)
|
||||
continue;
|
||||
|
||||
localPos.Set(
|
||||
tree.position.x * terrainSize.x,
|
||||
tree.position.y * terrainSize.y,
|
||||
tree.position.z * terrainSize.z);
|
||||
worldPos = terrain.transform.TransformPoint(localPos);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale)
|
||||
continue;
|
||||
}
|
||||
//sample terrain mask
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
maskColor = terrainMask.GetPixelBilinear(tree.position.x, tree.position.z);
|
||||
if (Random.value < maskColor.r)
|
||||
continue;
|
||||
}
|
||||
|
||||
scale.Set(
|
||||
Mathf.Max(0, tree.scale.x + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME),
|
||||
Mathf.Max(0, tree.scale.y + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME),
|
||||
Mathf.Max(0, tree.scale.z + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME));
|
||||
|
||||
GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create();
|
||||
filterArgs.Terrain = terrain;
|
||||
filterArgs.Position = worldPos;
|
||||
filterArgs.Rotation = tree.Rotation;
|
||||
filterArgs.Scale = scale;
|
||||
List<Type> suitableFilter = SuitableFilterTypes;
|
||||
if (args.Filters != null)
|
||||
{
|
||||
for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex)
|
||||
{
|
||||
if (args.Filters[fIndex] != null &&
|
||||
args.Filters[fIndex].Ignore != true)
|
||||
{
|
||||
if (suitableFilter.Contains(args.Filters[fIndex].GetType()))
|
||||
args.Filters[fIndex].Apply(ref filterArgs);
|
||||
}
|
||||
if (filterArgs.ShouldExclude)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tree.scale = filterArgs.Scale;
|
||||
instances[i] = tree;
|
||||
}
|
||||
terrain.TerrainData.Foliage.TreeAllChanged();
|
||||
terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage);
|
||||
GUtilities.MarkCurrentSceneDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db6e69be87ee1bf40a74abc0b5b49946
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,15 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public interface IGFoliagePainter
|
||||
{
|
||||
string HistoryPrefix { get; }
|
||||
string Instruction { get; }
|
||||
List<System.Type> SuitableFilterTypes { get; }
|
||||
void Paint(GStylizedTerrain terrain, GFoliagePainterArgs args);
|
||||
List<GTerrainResourceFlag> GetResourceFlagForHistory(GFoliagePainterArgs args);
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71739752b5c2e58449325280ae8898e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7a5da4597a2f1f4f84776a737a31d75
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,201 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GAlbedoPainter : IGTexturePainter, IGTexturePainterWithLivePreview, IConditionalPainter
|
||||
{
|
||||
private static readonly int COLOR = Shader.PropertyToID("_Color");
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
|
||||
private static readonly int MAIN_TEX_L = Shader.PropertyToID("_MainTex_Left");
|
||||
private static readonly int MAIN_TEX_TL = Shader.PropertyToID("_MainTex_TopLeft");
|
||||
private static readonly int MAIN_TEX_T = Shader.PropertyToID("_MainTex_Top");
|
||||
private static readonly int MAIN_TEX_TR = Shader.PropertyToID("_MainTex_TopRight");
|
||||
private static readonly int MAIN_TEX_R = Shader.PropertyToID("_MainTex_Right");
|
||||
private static readonly int MAIN_TEX_RB = Shader.PropertyToID("_MainTex_BottomRight");
|
||||
private static readonly int MAIN_TEX_B = Shader.PropertyToID("_MainTex_Bottom");
|
||||
private static readonly int MAIN_TEX_BL = Shader.PropertyToID("_MainTex_BottomLeft");
|
||||
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.albedoPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Modify terrain Albedo Map color.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold Ctrl & Left Mouse to erase.\n" +
|
||||
" - Hold Shift & Left Mouse to smooth.\n" +
|
||||
"Use a material that utilizes Albedo Map to see the result.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Albedo Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.AlbedoResourceFlags;
|
||||
}
|
||||
|
||||
private void SetupTextureGrid(GStylizedTerrain t, Material mat)
|
||||
{
|
||||
mat.SetTexture(MAIN_TEX_L,
|
||||
t.LeftNeighbor && t.LeftNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_TL,
|
||||
t.LeftNeighbor && t.LeftNeighbor.TopNeighbor && t.LeftNeighbor.TopNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TopNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_TL,
|
||||
t.TopNeighbor && t.TopNeighbor.LeftNeighbor && t.TopNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.TopNeighbor.LeftNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_T,
|
||||
t.TopNeighbor && t.TopNeighbor.TerrainData ?
|
||||
t.TopNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_TR,
|
||||
t.RightNeighbor && t.RightNeighbor.TopNeighbor && t.RightNeighbor.TopNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TopNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_TR,
|
||||
t.TopNeighbor && t.TopNeighbor.RightNeighbor && t.TopNeighbor.RightNeighbor.TerrainData ?
|
||||
t.TopNeighbor.RightNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_R,
|
||||
t.RightNeighbor && t.RightNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_RB,
|
||||
t.RightNeighbor && t.RightNeighbor.BottomNeighbor && t.RightNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.RightNeighbor.BottomNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_RB,
|
||||
t.BottomNeighbor && t.BottomNeighbor.RightNeighbor && t.BottomNeighbor.RightNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.RightNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_B,
|
||||
t.BottomNeighbor && t.BottomNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_BL,
|
||||
t.LeftNeighbor && t.LeftNeighbor.BottomNeighbor && t.LeftNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.BottomNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_BL,
|
||||
t.BottomNeighbor && t.BottomNeighbor.LeftNeighbor && t.BottomNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.LeftNeighbor.TerrainData.Shading.AlbedoMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int albedoResolution = terrain.TerrainData.Shading.AlbedoMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, albedoResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Shading.AlbedoMap.ReadPixels(
|
||||
new Rect(0, 0, albedoResolution, albedoResolution), 0, 0);
|
||||
terrain.TerrainData.Shading.AlbedoMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Shading);
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
}
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Shading.AlbedoMapOrDefault;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetColor(COLOR, args.Color);
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
SetupTextureGrid(terrain, mat);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, args.Opacity);
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
args.ConditionalPaintingConfigs.SetupMaterial(terrain, mat);
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 :
|
||||
args.ActionType == GPainterActionType.Alternative ? 2 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int albedoResolution = terrain.TerrainData.Shading.AlbedoMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, albedoResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawAlbedoLivePreview(terrain, cam, rt, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afd3422bd3e4ab24ab75231a55db4a23
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,364 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[System.Serializable]
|
||||
public class GConditionalPaintingConfigs
|
||||
{
|
||||
private static readonly string BLEND_HEIGHT_KW = "BLEND_HEIGHT";
|
||||
private static readonly int HEIGHT_MAP = Shader.PropertyToID("_HeightMap");
|
||||
private static readonly int MIN_HEIGHT = Shader.PropertyToID("_MinHeight");
|
||||
private static readonly int MAX_HEIGHT = Shader.PropertyToID("_MaxHeight");
|
||||
private static readonly int HEIGHT_TRANSITION = Shader.PropertyToID("_HeightTransition");
|
||||
|
||||
private static readonly string BLEND_SLOPE_KW = "BLEND_SLOPE";
|
||||
private static readonly int NORMAL_MAP = Shader.PropertyToID("_NormalMap");
|
||||
private static readonly int MIN_SLOPE = Shader.PropertyToID("_MinSlope");
|
||||
private static readonly int MAX_SLOPE = Shader.PropertyToID("_MaxSlope");
|
||||
private static readonly int SLOPE_TRANSITION = Shader.PropertyToID("_SlopeTransition");
|
||||
|
||||
private static readonly string BLEND_NOISE_KW = "BLEND_NOISE";
|
||||
private static readonly int NOISE_ORIGIN = Shader.PropertyToID("_NoiseOrigin");
|
||||
private static readonly int NOISE_FREQUENCY = Shader.PropertyToID("_NoiseFrequency");
|
||||
private static readonly int NOISE_OCTAVES = Shader.PropertyToID("_NoiseOctaves");
|
||||
private static readonly int NOISE_LACUNARITY = Shader.PropertyToID("_NoiseLacunarity");
|
||||
private static readonly int NOISE_PERSISTENCE = Shader.PropertyToID("_NoisePersistence");
|
||||
private static readonly int NOISE_REMAP = Shader.PropertyToID("_NoiseRemap");
|
||||
private static readonly int TERRAIN_DIMENSION = Shader.PropertyToID("_TerrainDimension");
|
||||
|
||||
[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;
|
||||
|
||||
public void UpdateCurveTextures()
|
||||
{
|
||||
CleanUp();
|
||||
|
||||
heightTransitionTexture = GCommon.CreateTextureFromCurve(HeightTransition, 256, 1);
|
||||
slopeTransitionTexture = GCommon.CreateTextureFromCurve(SlopeTransition, 256, 1);
|
||||
noiseRemapTexture = GCommon.CreateTextureFromCurve(NoiseRemap, 256, 1);
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
if (heightTransitionTexture != null)
|
||||
GUtilities.DestroyObject(heightTransitionTexture);
|
||||
if (slopeTransitionTexture != null)
|
||||
GUtilities.DestroyObject(slopeTransitionTexture);
|
||||
if (noiseRemapTexture != null)
|
||||
GUtilities.DestroyObject(noiseRemapTexture);
|
||||
}
|
||||
|
||||
public GConditionalPaintingConfigs()
|
||||
{
|
||||
BlendHeight = false;
|
||||
MinHeight = 0;
|
||||
MaxHeight = 1000;
|
||||
HeightTransition = AnimationCurve.EaseInOut(0, 1, 1, 1);
|
||||
BlendSlope = false;
|
||||
MinSlope = 0;
|
||||
MaxSlope = 90;
|
||||
SlopeTransition = AnimationCurve.EaseInOut(0, 1, 1, 1);
|
||||
BlendNoise = false;
|
||||
NoiseOrigin = Vector2.zero;
|
||||
NoiseFrequency = 100f;
|
||||
NoiseOctaves = 1;
|
||||
NoiseLacunarity = 2;
|
||||
NoisePersistence = 0.5f;
|
||||
NoiseRemap = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
public void SetupMaterial(GStylizedTerrain t, Material painterMat)
|
||||
{
|
||||
int resolution = t.TerrainData.Geometry.HeightMapResolution;
|
||||
Vector3 terrainSize = t.TerrainData.Geometry.Size;
|
||||
|
||||
if (BlendHeight)
|
||||
{
|
||||
RenderTexture heightMap = t.GetHeightMap(resolution);
|
||||
painterMat.EnableKeyword(BLEND_HEIGHT_KW);
|
||||
painterMat.SetTexture(HEIGHT_MAP, heightMap);
|
||||
painterMat.SetFloat(MIN_HEIGHT, GUtilities.InverseLerpUnclamped(0, terrainSize.y, MinHeight));
|
||||
painterMat.SetFloat(MAX_HEIGHT, GUtilities.InverseLerpUnclamped(0, terrainSize.y, MaxHeight));
|
||||
painterMat.SetTexture(HEIGHT_TRANSITION, heightTransitionTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
painterMat.DisableKeyword(BLEND_HEIGHT_KW);
|
||||
}
|
||||
|
||||
if (BlendSlope)
|
||||
{
|
||||
RenderTexture normalMap =
|
||||
NormalMapMode == GNormalMapMode.Sharp ? t.GetSharpNormalMap(resolution) :
|
||||
NormalMapMode == GNormalMapMode.Interpolated ? t.GetInterpolatedNormalMap(resolution) :
|
||||
NormalMapMode == GNormalMapMode.PerPixel ? t.GetPerPixelNormalMap(resolution) : null;
|
||||
painterMat.EnableKeyword(BLEND_SLOPE_KW);
|
||||
painterMat.SetTexture(NORMAL_MAP, normalMap);
|
||||
painterMat.SetFloat(MIN_SLOPE, MinSlope * Mathf.Deg2Rad);
|
||||
painterMat.SetFloat(MAX_SLOPE, MaxSlope * Mathf.Deg2Rad);
|
||||
painterMat.SetTexture(SLOPE_TRANSITION, slopeTransitionTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
painterMat.DisableKeyword(BLEND_SLOPE_KW);
|
||||
}
|
||||
|
||||
if (BlendNoise)
|
||||
{
|
||||
painterMat.EnableKeyword(BLEND_NOISE_KW);
|
||||
painterMat.SetVector(NOISE_ORIGIN, NoiseOrigin);
|
||||
painterMat.SetFloat(NOISE_FREQUENCY, NoiseFrequency);
|
||||
painterMat.SetFloat(NOISE_OCTAVES, NoiseOctaves);
|
||||
painterMat.SetFloat(NOISE_LACUNARITY, NoiseLacunarity);
|
||||
painterMat.SetFloat(NOISE_PERSISTENCE, NoisePersistence);
|
||||
painterMat.SetTexture(NOISE_REMAP, noiseRemapTexture);
|
||||
painterMat.SetVector(TERRAIN_DIMENSION, new Vector4(t.transform.position.x, t.transform.position.z, terrainSize.x, terrainSize.z));
|
||||
}
|
||||
else
|
||||
{
|
||||
painterMat.DisableKeyword(BLEND_NOISE_KW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f47d8a1f50481b44a82642626147eca5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,211 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GElevationPainter : IGTexturePainter, IGTexturePainterWithLivePreview
|
||||
{
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
|
||||
private static readonly int MAIN_TEX_L = Shader.PropertyToID("_MainTex_Left");
|
||||
private static readonly int MAIN_TEX_TL = Shader.PropertyToID("_MainTex_TopLeft");
|
||||
private static readonly int MAIN_TEX_T = Shader.PropertyToID("_MainTex_Top");
|
||||
private static readonly int MAIN_TEX_TR = Shader.PropertyToID("_MainTex_TopRight");
|
||||
private static readonly int MAIN_TEX_R = Shader.PropertyToID("_MainTex_Right");
|
||||
private static readonly int MAIN_TEX_RB = Shader.PropertyToID("_MainTex_BottomRight");
|
||||
private static readonly int MAIN_TEX_B = Shader.PropertyToID("_MainTex_Bottom");
|
||||
private static readonly int MAIN_TEX_BL = Shader.PropertyToID("_MainTex_BottomLeft");
|
||||
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.elevationPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Gradually modifying terrain geometry.\n" +
|
||||
" - Hold Left Mouse to raise.\n" +
|
||||
" - Hold {0} & Left Mouse to lower.\n" +
|
||||
" - Hold {1} & Left Mouse to smooth.",
|
||||
"Ctrl",
|
||||
"Shift");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Elevation Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.HeightMapAndFoliageResourceFlags;
|
||||
}
|
||||
|
||||
private void SetupTextureGrid(GStylizedTerrain t, Material mat)
|
||||
{
|
||||
mat.SetTexture(MAIN_TEX_L,
|
||||
t.LeftNeighbor && t.LeftNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_TL,
|
||||
t.LeftNeighbor && t.LeftNeighbor.TopNeighbor && t.LeftNeighbor.TopNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TopNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_TL,
|
||||
t.TopNeighbor && t.TopNeighbor.LeftNeighbor && t.TopNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.TopNeighbor.LeftNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_T,
|
||||
t.TopNeighbor && t.TopNeighbor.TerrainData ?
|
||||
t.TopNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_TR,
|
||||
t.RightNeighbor && t.RightNeighbor.TopNeighbor && t.RightNeighbor.TopNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TopNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_TR,
|
||||
t.TopNeighbor && t.TopNeighbor.RightNeighbor && t.TopNeighbor.RightNeighbor.TerrainData ?
|
||||
t.TopNeighbor.RightNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_R,
|
||||
t.RightNeighbor && t.RightNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_RB,
|
||||
t.RightNeighbor && t.RightNeighbor.BottomNeighbor && t.RightNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.RightNeighbor.BottomNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_RB,
|
||||
t.BottomNeighbor && t.BottomNeighbor.RightNeighbor && t.BottomNeighbor.RightNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.RightNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_B,
|
||||
t.BottomNeighbor && t.BottomNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_BL,
|
||||
t.LeftNeighbor && t.LeftNeighbor.BottomNeighbor && t.LeftNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.BottomNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_BL,
|
||||
t.BottomNeighbor && t.BottomNeighbor.LeftNeighbor && t.BottomNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.LeftNeighbor.TerrainData.Geometry.HeightMap :
|
||||
Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.MouseEventType == GPainterMouseEventType.Down)
|
||||
{
|
||||
terrain.ForceLOD(0);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = true;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Geometry.HeightMap.ReadPixels(
|
||||
new Rect(0, 0, heightMapResolution, heightMapResolution), 0, 0);
|
||||
terrain.TerrainData.Geometry.HeightMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect);
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Geometry.HeightMap;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
SetupTextureGrid(terrain, mat);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, Mathf.Pow(args.Opacity, GTerrainTexturePainter.GEOMETRY_OPACITY_EXPONENT));
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 :
|
||||
args.ActionType == GPainterActionType.Alternative ? 2 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
terrain.ForceLOD(-1);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = false;
|
||||
terrain.UpdateTreesPosition();
|
||||
terrain.UpdateGrassPatches();
|
||||
terrain.TerrainData.Foliage.ClearTreeDirtyRegions();
|
||||
terrain.TerrainData.Foliage.ClearGrassDirtyRegions();
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawGeometryLivePreview(terrain, cam, rt, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f4e5ad81ad9ae94d810f177eef58846
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,153 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GHeightSamplingPainter : IGTexturePainter, IGTexturePainterWithLivePreview
|
||||
{
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TARGET_GRAY = Shader.PropertyToID("_TargetGray");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.heightSamplingPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Set geometry to a pre-sampled height.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold Shift & Left Mouse to sample height.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Height Sampling";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
if (args.ActionType == GPainterActionType.Normal)
|
||||
{
|
||||
return GCommon.HeightMapAndFoliageResourceFlags;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GCommon.EmptyResourceFlags;
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.ActionType != GPainterActionType.Normal)
|
||||
{
|
||||
terrain.ForceLOD(-1);
|
||||
return;
|
||||
}
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.MouseEventType == GPainterMouseEventType.Down)
|
||||
{
|
||||
terrain.ForceLOD(0);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = true;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Geometry.HeightMap.ReadPixels(
|
||||
new Rect(0, 0, heightMapResolution, heightMapResolution), 0, 0);
|
||||
terrain.TerrainData.Geometry.HeightMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect);
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Geometry.HeightMap;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Vector3 localSamplePoint = terrain.transform.InverseTransformPoint(args.SamplePoint);
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, Mathf.Pow(args.Opacity, GTerrainTexturePainter.GEOMETRY_OPACITY_EXPONENT));
|
||||
mat.SetFloat(TARGET_GRAY, Mathf.InverseLerp(0, terrain.TerrainData.Geometry.Height, localSamplePoint.y));
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
int pass = 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.ActionType != GPainterActionType.Normal)
|
||||
{
|
||||
terrain.ForceLOD(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
GRuntimeSettings.Instance.isEditingGeometry = false;
|
||||
terrain.UpdateTreesPosition();
|
||||
terrain.UpdateGrassPatches();
|
||||
terrain.TerrainData.Foliage.ClearTreeDirtyRegions();
|
||||
terrain.TerrainData.Foliage.ClearGrassDirtyRegions();
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawGeometryLivePreview(terrain, cam, rt, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 125721534eb906d4e9f1b2b41318e35c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,239 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GMaskPainter : IGTexturePainter, IGTexturePainterWithCustomParams, IGTexturePainterWithLivePreview, IConditionalPainter
|
||||
{
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.maskPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Modify terrain mask.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold {0} & Left Mouse to erase.\n" +
|
||||
" - Hold {1} & Left Mouse to smooth.",
|
||||
"Ctrl",
|
||||
"Shift");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Mask Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.MaskMapResourceFlags;
|
||||
}
|
||||
|
||||
private void SetupTextureGrid(GStylizedTerrain t, Material mat)
|
||||
{
|
||||
mat.SetTexture("_MainTex_Left",
|
||||
t.LeftNeighbor && t.LeftNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture("_MainTex_TopLeft",
|
||||
t.LeftNeighbor && t.LeftNeighbor.TopNeighbor && t.LeftNeighbor.TopNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TopNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture("_MainTex_TopLeft",
|
||||
t.TopNeighbor && t.TopNeighbor.LeftNeighbor && t.TopNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.TopNeighbor.LeftNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture("_MainTex_Top",
|
||||
t.TopNeighbor && t.TopNeighbor.TerrainData ?
|
||||
t.TopNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture("_MainTex_TopRight",
|
||||
t.RightNeighbor && t.RightNeighbor.TopNeighbor && t.RightNeighbor.TopNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TopNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture("_MainTex_TopRight",
|
||||
t.TopNeighbor && t.TopNeighbor.RightNeighbor && t.TopNeighbor.RightNeighbor.TerrainData ?
|
||||
t.TopNeighbor.RightNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture("_MainTex_Right",
|
||||
t.RightNeighbor && t.RightNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture("_MainTex_BottomRight",
|
||||
t.RightNeighbor && t.RightNeighbor.BottomNeighbor && t.RightNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.RightNeighbor.BottomNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture("_MainTex_BottomRight",
|
||||
t.BottomNeighbor && t.BottomNeighbor.RightNeighbor && t.BottomNeighbor.RightNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.RightNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture("_MainTex_Bottom",
|
||||
t.BottomNeighbor && t.BottomNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture("_MainTex_BottomLeft",
|
||||
t.LeftNeighbor && t.LeftNeighbor.BottomNeighbor && t.LeftNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.BottomNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture("_MainTex_BottomLeft",
|
||||
t.BottomNeighbor && t.BottomNeighbor.LeftNeighbor && t.BottomNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.LeftNeighbor.TerrainData.Mask.MaskMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int maskResolution = terrain.TerrainData.Mask.MaskMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, maskResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Mask.MaskMap.ReadPixels(
|
||||
new Rect(0, 0, maskResolution, maskResolution), 0, 0);
|
||||
terrain.TerrainData.Mask.MaskMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
}
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture("_MainTex", bg);
|
||||
SetupTextureGrid(terrain, mat);
|
||||
mat.SetTexture("_Mask", args.BrushMask);
|
||||
mat.SetFloat("_Opacity", args.Opacity);
|
||||
GMaskPainterParams param = GTexturePainterCustomParams.Instance.Mask;
|
||||
Vector4 channel;
|
||||
if (param.Channel == GTextureChannel.R)
|
||||
{
|
||||
channel = new Vector4(1, 0, 0, 0);
|
||||
}
|
||||
else if (param.Channel == GTextureChannel.G)
|
||||
{
|
||||
channel = new Vector4(0, 1, 0, 0);
|
||||
}
|
||||
else if (param.Channel == GTextureChannel.B)
|
||||
{
|
||||
channel = new Vector4(0, 0, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
channel = new Vector4(0, 0, 0, 1);
|
||||
}
|
||||
mat.SetVector("_Channel", channel);
|
||||
args.ConditionalPaintingConfigs.SetupMaterial(terrain, mat);
|
||||
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 :
|
||||
args.ActionType == GPainterActionType.Alternative ? 2 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (GTexturePainterCustomParams.Instance.Mask.Visualize == false)
|
||||
return;
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int maskResolution = terrain.TerrainData.Mask.MaskMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, maskResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawMask4ChannelsLivePreview(
|
||||
terrain, cam,
|
||||
rt,
|
||||
GCommon.UnitRect);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Editor_DrawCustomParamsGUI()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string label = "Mask Painting";
|
||||
string id = "mask-painter";
|
||||
|
||||
GCommonGUI.Foldout(label, true, id, () =>
|
||||
{
|
||||
GMaskPainterParams param = GTexturePainterCustomParams.Instance.Mask;
|
||||
string[] labels = new string[]
|
||||
{
|
||||
"R (Terrain Mask)",
|
||||
"G (Smooth Normal Mask)",
|
||||
"B (Water Source)",
|
||||
"A"
|
||||
};
|
||||
int[] values = new int[]
|
||||
{
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
8
|
||||
};
|
||||
|
||||
param.Channel = (GTextureChannel)EditorGUILayout.IntPopup("Channel", (int)param.Channel, labels, values);
|
||||
param.Visualize = EditorGUILayout.Toggle("Visualize", param.Visualize);
|
||||
GTexturePainterCustomParams.Instance.Mask = param;
|
||||
EditorUtility.SetDirty(GTexturePainterCustomParams.Instance);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0897186fb16d4d4fbaa728b2560c0e5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,40 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct GMaskPainterParams
|
||||
{
|
||||
[SerializeField]
|
||||
private GTextureChannel channel;
|
||||
public GTextureChannel Channel
|
||||
{
|
||||
get
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
set
|
||||
{
|
||||
channel = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool visualize;
|
||||
public bool Visualize
|
||||
{
|
||||
get
|
||||
{
|
||||
return visualize;
|
||||
}
|
||||
set
|
||||
{
|
||||
visualize = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6f20d8d839c14948b9135934d1a10e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,203 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GMetallicPainter : IGTexturePainter, IGTexturePainterWithLivePreview, IConditionalPainter
|
||||
{
|
||||
private static readonly int COLOR = Shader.PropertyToID("_Color");
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
|
||||
private static readonly int MAIN_TEX_L = Shader.PropertyToID("_MainTex_Left");
|
||||
private static readonly int MAIN_TEX_TL = Shader.PropertyToID("_MainTex_TopLeft");
|
||||
private static readonly int MAIN_TEX_T = Shader.PropertyToID("_MainTex_Top");
|
||||
private static readonly int MAIN_TEX_TR = Shader.PropertyToID("_MainTex_TopRight");
|
||||
private static readonly int MAIN_TEX_R = Shader.PropertyToID("_MainTex_Right");
|
||||
private static readonly int MAIN_TEX_RB = Shader.PropertyToID("_MainTex_BottomRight");
|
||||
private static readonly int MAIN_TEX_B = Shader.PropertyToID("_MainTex_Bottom");
|
||||
private static readonly int MAIN_TEX_BL = Shader.PropertyToID("_MainTex_BottomLeft");
|
||||
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.metallicPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Modify terrain Metallic Map Red channel.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold Ctrl & Left Mouse to erase.\n" +
|
||||
" - Hold Shift & Left Mouse to smooth.\n" +
|
||||
"This painter uses the Red channel of brush color.\n" +
|
||||
"Use a material that utilizes Metallic Map to see the result.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Metallic Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.MetallicResourceFlags;
|
||||
}
|
||||
|
||||
private void SetupTextureGrid(GStylizedTerrain t, Material mat)
|
||||
{
|
||||
mat.SetTexture(MAIN_TEX_L,
|
||||
t.LeftNeighbor && t.LeftNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_TL,
|
||||
t.LeftNeighbor && t.LeftNeighbor.TopNeighbor && t.LeftNeighbor.TopNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TopNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_TL,
|
||||
t.TopNeighbor && t.TopNeighbor.LeftNeighbor && t.TopNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.TopNeighbor.LeftNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_T,
|
||||
t.TopNeighbor && t.TopNeighbor.TerrainData ?
|
||||
t.TopNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_TR,
|
||||
t.RightNeighbor && t.RightNeighbor.TopNeighbor && t.RightNeighbor.TopNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TopNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_TR,
|
||||
t.TopNeighbor && t.TopNeighbor.RightNeighbor && t.TopNeighbor.RightNeighbor.TerrainData ?
|
||||
t.TopNeighbor.RightNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_R,
|
||||
t.RightNeighbor && t.RightNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_RB,
|
||||
t.RightNeighbor && t.RightNeighbor.BottomNeighbor && t.RightNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.RightNeighbor.BottomNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_RB,
|
||||
t.BottomNeighbor && t.BottomNeighbor.RightNeighbor && t.BottomNeighbor.RightNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.RightNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_B,
|
||||
t.BottomNeighbor && t.BottomNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_BL,
|
||||
t.LeftNeighbor && t.LeftNeighbor.BottomNeighbor && t.LeftNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.BottomNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_BL,
|
||||
t.BottomNeighbor && t.BottomNeighbor.LeftNeighbor && t.BottomNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.LeftNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int metallicResolution = terrain.TerrainData.Shading.MetallicMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, metallicResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Shading.MetallicMap.ReadPixels(
|
||||
new Rect(0, 0, metallicResolution, metallicResolution), 0, 0);
|
||||
terrain.TerrainData.Shading.MetallicMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Shading);
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
}
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Shading.MetallicMapOrDefault;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetColor(COLOR, args.Color);
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
SetupTextureGrid(terrain, mat);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, args.Opacity);
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
args.ConditionalPaintingConfigs.SetupMaterial(terrain, mat);
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 :
|
||||
args.ActionType == GPainterActionType.Alternative ? 2 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int metallicResolution = terrain.TerrainData.Shading.MetallicMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, metallicResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawMetallicSmoothnessLivePreview(terrain, cam, rt, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b464d2a81b55724384cbdb7b7a3ae72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,215 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Pinwheel.Griffin.TextureTool;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GNoisePainter : IGTexturePainter, IGTexturePainterWithCustomParams, IGTexturePainterWithLivePreview
|
||||
{
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int NOISE_MAP = Shader.PropertyToID("_NoiseMap");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
private static readonly string WORLD_SPACE_KW = "USE_WORLD_SPACE";
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.noisePainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Noise Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Raise or lower terrain surface using noise.\n" +
|
||||
" - Hold Left Mouse to raise.\n" +
|
||||
" - Hold Ctrl & Left Mouse to lower.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.HeightMapAndFoliageResourceFlags;
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.MouseEventType == GPainterMouseEventType.Down)
|
||||
{
|
||||
terrain.ForceLOD(0);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = true;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Geometry.HeightMap.ReadPixels(
|
||||
new Rect(0, 0, heightMapResolution, heightMapResolution), 0, 0);
|
||||
terrain.TerrainData.Geometry.HeightMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect);
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Geometry.HeightMap;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture noiseMap = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution, 1);
|
||||
RenderNoiseTexture(noiseMap, terrain);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, Mathf.Pow(args.Opacity, GTerrainTexturePainter.GEOMETRY_OPACITY_EXPONENT));
|
||||
mat.SetTexture(NOISE_MAP, noiseMap);
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
GCommon.SetMaterialKeywordActive(mat, WORLD_SPACE_KW, GTexturePainterCustomParams.Instance.Noise.UseWorldSpace);
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
terrain.ForceLOD(-1);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = false;
|
||||
terrain.UpdateTreesPosition();
|
||||
terrain.UpdateGrassPatches();
|
||||
terrain.TerrainData.Foliage.ClearTreeDirtyRegions();
|
||||
terrain.TerrainData.Foliage.ClearGrassDirtyRegions();
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawCustomParamsGUI()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string label = "Noise Painting";
|
||||
string id = "noise-painter";
|
||||
|
||||
GCommonGUI.Foldout(label, true, id, () =>
|
||||
{
|
||||
GNoisePainterParams param = GTexturePainterCustomParams.Instance.Noise;
|
||||
|
||||
EditorGUILayout.GetControlRect(GUILayout.Height(1));
|
||||
Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(200));
|
||||
RenderTexture preview = GTerrainTexturePainter.Internal_GetRenderTexture(null, 200, 0);
|
||||
RenderNoiseTexture(preview, null);
|
||||
EditorGUI.DrawPreviewTexture(r, preview, null, ScaleMode.ScaleToFit);
|
||||
EditorGUILayout.GetControlRect(GUILayout.Height(1));
|
||||
|
||||
param.Type = (GNoiseType)EditorGUILayout.EnumPopup("Type", param.Type);
|
||||
param.Origin = GCommonGUI.InlineVector2Field("Origin", param.Origin);
|
||||
param.Frequency = EditorGUILayout.FloatField("Frequency", param.Frequency);
|
||||
param.Lacunarity = EditorGUILayout.FloatField("Lacunarity", param.Lacunarity);
|
||||
param.Persistence = EditorGUILayout.FloatField("Persistence", param.Persistence);
|
||||
param.Octaves = EditorGUILayout.IntField("Octaves", param.Octaves);
|
||||
param.Seed = EditorGUILayout.FloatField("Seed", param.Seed);
|
||||
param.UseWorldSpace = EditorGUILayout.Toggle("World Space", param.UseWorldSpace);
|
||||
|
||||
GTexturePainterCustomParams.Instance.Noise = param;
|
||||
|
||||
EditorUtility.SetDirty(GTexturePainterCustomParams.Instance);
|
||||
});
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawGeometryLivePreview(terrain, cam, rt, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void RenderNoiseTexture(RenderTexture noiseMap, GStylizedTerrain terrain)
|
||||
{
|
||||
GNoisePainterParams param = GTexturePainterCustomParams.Instance.Noise;
|
||||
GNoiseMapGenerator gen = new GNoiseMapGenerator();
|
||||
GNoiseMapGeneratorParams genParam = new GNoiseMapGeneratorParams();
|
||||
genParam.Type = param.Type;
|
||||
if (param.UseWorldSpace && terrain != null)
|
||||
{
|
||||
Vector3 terrainSize = new Vector3(
|
||||
terrain.TerrainData.Geometry.Width,
|
||||
terrain.TerrainData.Geometry.Height,
|
||||
terrain.TerrainData.Geometry.Length);
|
||||
Vector3 terrainPos = terrain.transform.position;
|
||||
|
||||
if (genParam.Type == GNoiseType.Voronoi)
|
||||
{
|
||||
genParam.Origin = param.Origin + new Vector2(terrainPos.x / terrainSize.x, terrainPos.z / terrainSize.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
genParam.Origin = param.Origin + new Vector2(terrainPos.x * param.Frequency / terrainSize.x, terrainPos.z * param.Frequency / terrainSize.z);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
genParam.Origin = param.Origin;
|
||||
}
|
||||
genParam.Frequency = param.Frequency;
|
||||
genParam.Lacunarity = param.Lacunarity;
|
||||
genParam.Persistence = param.Persistence;
|
||||
genParam.Octaves = param.Octaves;
|
||||
genParam.Seed = param.Seed;
|
||||
gen.Generate(noiseMap, genParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69a4c5b88485c8f49b738b48dd0b766d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,123 @@
|
||||
#if GRIFFIN
|
||||
using Pinwheel.Griffin.TextureTool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct GNoisePainterParams
|
||||
{
|
||||
[SerializeField]
|
||||
private GNoiseType type;
|
||||
public GNoiseType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return type;
|
||||
}
|
||||
set
|
||||
{
|
||||
type = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private Vector2 origin;
|
||||
public Vector2 Origin
|
||||
{
|
||||
get
|
||||
{
|
||||
return origin;
|
||||
}
|
||||
set
|
||||
{
|
||||
origin = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float frequency;
|
||||
public float Frequency
|
||||
{
|
||||
get
|
||||
{
|
||||
return frequency;
|
||||
}
|
||||
set
|
||||
{
|
||||
frequency = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float laccunarity;
|
||||
public float Lacunarity
|
||||
{
|
||||
get
|
||||
{
|
||||
return laccunarity;
|
||||
}
|
||||
set
|
||||
{
|
||||
laccunarity = Mathf.Max(1, value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float persistent;
|
||||
public float Persistence
|
||||
{
|
||||
get
|
||||
{
|
||||
return persistent;
|
||||
}
|
||||
set
|
||||
{
|
||||
persistent = Mathf.Clamp(value, 0.01f, 1);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int octaves;
|
||||
public int Octaves
|
||||
{
|
||||
get
|
||||
{
|
||||
return octaves;
|
||||
}
|
||||
set
|
||||
{
|
||||
octaves = Mathf.Clamp(value, 1, 4);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float seed;
|
||||
public float Seed
|
||||
{
|
||||
get
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
set
|
||||
{
|
||||
seed = Mathf.Max(1, value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool useWorldSpace;
|
||||
public bool UseWorldSpace
|
||||
{
|
||||
get
|
||||
{
|
||||
return useWorldSpace;
|
||||
}
|
||||
set
|
||||
{
|
||||
useWorldSpace = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f86bbec0bf3c1eb40956da0829357fa8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,154 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GRemapPainter : IGTexturePainter, IGTexturePainterWithCustomParams, IGTexturePainterWithLivePreview
|
||||
{
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
private static readonly int REMAP_TEX = Shader.PropertyToID("_RemapTex");
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.remapPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Remap Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Remap evelation value by a curve.\n" +
|
||||
" - Use Left Mouse to paint.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.HeightMapAndFoliageResourceFlags;
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.MouseEventType == GPainterMouseEventType.Down)
|
||||
{
|
||||
terrain.ForceLOD(0);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = true;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Geometry.HeightMap.ReadPixels(
|
||||
new Rect(0, 0, heightMapResolution, heightMapResolution), 0, 0);
|
||||
terrain.TerrainData.Geometry.HeightMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect);
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Geometry.HeightMap;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Texture2D remapTex = GCommon.CreateTextureFromCurve(GTexturePainterCustomParams.Instance.Remap.Curve, 512, 1);
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, Mathf.Pow(args.Opacity, GTerrainTexturePainter.GEOMETRY_OPACITY_EXPONENT));
|
||||
mat.SetTexture(REMAP_TEX, remapTex);
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
int pass = 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
GUtilities.DestroyObject(remapTex);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
terrain.ForceLOD(-1);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = false;
|
||||
terrain.UpdateTreesPosition();
|
||||
terrain.UpdateGrassPatches();
|
||||
terrain.TerrainData.Foliage.ClearTreeDirtyRegions();
|
||||
terrain.TerrainData.Foliage.ClearGrassDirtyRegions();
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawCustomParamsGUI()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string label = "Remap Painting";
|
||||
string id = "remap-painter";
|
||||
|
||||
GCommonGUI.Foldout(label, true, id, () =>
|
||||
{
|
||||
GRemapPainterParams param = GTexturePainterCustomParams.Instance.Remap;
|
||||
param.Curve = EditorGUILayout.CurveField("Curve", param.Curve, Color.red, GCommon.UnitRect);
|
||||
GTexturePainterCustomParams.Instance.Remap = param;
|
||||
EditorUtility.SetDirty(GTexturePainterCustomParams.Instance);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawGeometryLivePreview(terrain, cam, rt, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bd3b2c6a74be8e4da975dd2c362f071
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,28 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct GRemapPainterParams
|
||||
{
|
||||
[SerializeField]
|
||||
private AnimationCurve curve;
|
||||
public AnimationCurve Curve
|
||||
{
|
||||
get
|
||||
{
|
||||
if (curve == null)
|
||||
{
|
||||
curve = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
||||
}
|
||||
return curve;
|
||||
}
|
||||
set
|
||||
{
|
||||
curve = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2516f4523e35ed8438b55b948c812cc0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,202 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GSmoothnessPainter : IGTexturePainter, IGTexturePainterWithLivePreview, IConditionalPainter
|
||||
{
|
||||
private static readonly int COLOR = Shader.PropertyToID("_Color");
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
|
||||
private static readonly int MAIN_TEX_L = Shader.PropertyToID("_MainTex_Left");
|
||||
private static readonly int MAIN_TEX_TL = Shader.PropertyToID("_MainTex_TopLeft");
|
||||
private static readonly int MAIN_TEX_T = Shader.PropertyToID("_MainTex_Top");
|
||||
private static readonly int MAIN_TEX_TR = Shader.PropertyToID("_MainTex_TopRight");
|
||||
private static readonly int MAIN_TEX_R = Shader.PropertyToID("_MainTex_Right");
|
||||
private static readonly int MAIN_TEX_RB = Shader.PropertyToID("_MainTex_BottomRight");
|
||||
private static readonly int MAIN_TEX_B = Shader.PropertyToID("_MainTex_Bottom");
|
||||
private static readonly int MAIN_TEX_BL = Shader.PropertyToID("_MainTex_BottomLeft");
|
||||
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.smoothnessPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Modify terrain Metallic Map Alpha channel.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold Ctrl & Left Mouse to erase.\n" +
|
||||
" - Hold Shift & Left Mouse to smooth.\n" +
|
||||
"This painter uses the Alpha channel of brush color.\n" +
|
||||
"Use a material that utilizes Metallic Map to see the result.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Smoothness Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.MetallicResourceFlags;
|
||||
}
|
||||
|
||||
private void SetupTextureGrid(GStylizedTerrain t, Material mat)
|
||||
{
|
||||
mat.SetTexture(MAIN_TEX_L,
|
||||
t.LeftNeighbor && t.LeftNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_TL,
|
||||
t.LeftNeighbor && t.LeftNeighbor.TopNeighbor && t.LeftNeighbor.TopNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.TopNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_TL,
|
||||
t.TopNeighbor && t.TopNeighbor.LeftNeighbor && t.TopNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.TopNeighbor.LeftNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_T,
|
||||
t.TopNeighbor && t.TopNeighbor.TerrainData ?
|
||||
t.TopNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_TR,
|
||||
t.RightNeighbor && t.RightNeighbor.TopNeighbor && t.RightNeighbor.TopNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TopNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_TR,
|
||||
t.TopNeighbor && t.TopNeighbor.RightNeighbor && t.TopNeighbor.RightNeighbor.TerrainData ?
|
||||
t.TopNeighbor.RightNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_R,
|
||||
t.RightNeighbor && t.RightNeighbor.TerrainData ?
|
||||
t.RightNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_RB,
|
||||
t.RightNeighbor && t.RightNeighbor.BottomNeighbor && t.RightNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.RightNeighbor.BottomNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_RB,
|
||||
t.BottomNeighbor && t.BottomNeighbor.RightNeighbor && t.BottomNeighbor.RightNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.RightNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_B,
|
||||
t.BottomNeighbor && t.BottomNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
|
||||
mat.SetTexture(MAIN_TEX_BL,
|
||||
t.LeftNeighbor && t.LeftNeighbor.BottomNeighbor && t.LeftNeighbor.BottomNeighbor.TerrainData ?
|
||||
t.LeftNeighbor.BottomNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
mat.SetTexture(MAIN_TEX_BL,
|
||||
t.BottomNeighbor && t.BottomNeighbor.LeftNeighbor && t.BottomNeighbor.LeftNeighbor.TerrainData ?
|
||||
t.BottomNeighbor.LeftNeighbor.TerrainData.Shading.MetallicMapOrDefault :
|
||||
Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int metallicResolution = terrain.TerrainData.Shading.MetallicMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, metallicResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Shading.MetallicMap.ReadPixels(
|
||||
new Rect(0, 0, metallicResolution, metallicResolution), 0, 0);
|
||||
terrain.TerrainData.Shading.MetallicMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Shading);
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
}
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Shading.MetallicMapOrDefault;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetColor(COLOR, args.Color);
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
SetupTextureGrid(terrain, mat);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, args.Opacity);
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
args.ConditionalPaintingConfigs.SetupMaterial(terrain, mat);
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 :
|
||||
args.ActionType == GPainterActionType.Alternative ? 2 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int metallicResolution = terrain.TerrainData.Shading.MetallicMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, metallicResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawMetallicSmoothnessLivePreview(terrain, cam, rt, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89d294aa45a6a494eb5e5a66c9763ad3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,170 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GSplatPainter : IGTexturePainter, IGTexturePainterWithLivePreview, IConditionalPainter
|
||||
{
|
||||
private static readonly int CHANNEL_INDEX = Shader.PropertyToID("_ChannelIndex");
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.splatPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Paint blend weight on terrain Splat Control maps.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold Ctrl & Left Mouse to erase selected layer.\n" +
|
||||
" - Hold Shift & Left Mouse to erase all layer.\n" +
|
||||
"Use a material that utilizes splat maps to see the result.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Splat Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.SplatResourceFlags;
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (terrain.TerrainData.Shading.Splats == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int splatIndex = args.SplatIndex;
|
||||
if (splatIndex < 0 || splatIndex >= terrain.TerrainData.Shading.SplatControlMapCount * 4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int controlMapResolution = terrain.TerrainData.Shading.SplatControlResolution;
|
||||
int controlMapCount = terrain.TerrainData.Shading.SplatControlMapCount;
|
||||
for (int i = 0; i < controlMapCount; ++i)
|
||||
{
|
||||
Texture2D currentSplatControl = terrain.TerrainData.Shading.GetSplatControl(i);
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, controlMapResolution, i);
|
||||
PaintOnRT(terrain, args, rt, uvCorners, i);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
currentSplatControl.ReadPixels(new Rect(0, 0, controlMapResolution, controlMapResolution), 0, 0);
|
||||
currentSplatControl.Apply();
|
||||
RenderTexture.active = null;
|
||||
}
|
||||
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Shading);
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
}
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners, int currentSplatIndex)
|
||||
{
|
||||
Texture2D currentSplatControl = terrain.TerrainData.Shading.GetSplatControl(currentSplatIndex);
|
||||
GCommon.CopyToRT(currentSplatControl, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, args.Opacity);
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
args.ConditionalPaintingConfigs.SetupMaterial(terrain, mat);
|
||||
|
||||
mat.SetTexture(MAIN_TEX, currentSplatControl);
|
||||
int selectedSplatIndex = args.SplatIndex;
|
||||
if (selectedSplatIndex / 4 == currentSplatIndex)
|
||||
{
|
||||
mat.SetInt(CHANNEL_INDEX, selectedSplatIndex % 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetInt(CHANNEL_INDEX, -1);
|
||||
}
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 :
|
||||
args.ActionType == GPainterActionType.Alternative ? 2 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.ForceUpdateGeometry)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
int splatIndex = args.SplatIndex;
|
||||
if (splatIndex < 0 || splatIndex >= terrain.TerrainData.Shading.SplatControlMapCount * 4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int controlMapResolution = terrain.TerrainData.Shading.SplatControlResolution;
|
||||
int controlMapCount = terrain.TerrainData.Shading.SplatControlMapCount;
|
||||
for (int i = 0; i < controlMapCount; ++i)
|
||||
{
|
||||
Texture2D currentSplatControl = terrain.TerrainData.Shading.GetSplatControl(i);
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, controlMapResolution, i);
|
||||
PaintOnRT(terrain, args, rt, uvCorners, i);
|
||||
}
|
||||
|
||||
Texture[] controls = new Texture[controlMapCount];
|
||||
for (int i = 0; i < controlMapCount; ++i)
|
||||
{
|
||||
controls[i] = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, controlMapResolution, i);
|
||||
}
|
||||
|
||||
GLivePreviewDrawer.DrawSplatLivePreview(terrain, cam, controls, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69c05278b4a8f114f9f45e09608b80de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,140 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GSubDivPainter : IGTexturePainter, IGTexturePainterWithLivePreview
|
||||
{
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.subdivPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Add more sub division to a particular area of the terrain.\n" +
|
||||
" - Hold Left Mouse to add.\n" +
|
||||
" - Hold {0} & Left Mouse to subtract.",
|
||||
"Ctrl");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Sub Div Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.HeightMapAndFoliageResourceFlags;
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.MouseEventType == GPainterMouseEventType.Down)
|
||||
{
|
||||
terrain.ForceLOD(0);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = true;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Geometry.HeightMap.ReadPixels(
|
||||
new Rect(0, 0, heightMapResolution, heightMapResolution), 0, 0);
|
||||
terrain.TerrainData.Geometry.HeightMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect);
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Geometry.HeightMap;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, Mathf.Pow(args.Opacity, GTerrainTexturePainter.GEOMETRY_OPACITY_EXPONENT));
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
terrain.ForceLOD(-1);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = false;
|
||||
terrain.UpdateTreesPosition();
|
||||
terrain.UpdateGrassPatches();
|
||||
terrain.TerrainData.Foliage.ClearTreeDirtyRegions();
|
||||
terrain.TerrainData.Foliage.ClearGrassDirtyRegions();
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
Matrix4x4 worldToMaskMatrix = Matrix4x4.TRS(
|
||||
args.WorldPointCorners[0],
|
||||
Quaternion.Euler(0, args.Rotation, 0),
|
||||
args.Radius * 2 * Vector3.one).inverse;
|
||||
|
||||
GLivePreviewDrawer.DrawSubdivLivePreview(terrain, cam, rt, dirtyRect, args.BrushMask, worldToMaskMatrix);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c07c7738f8146094398c400eabfebde1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,152 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GTerracePainter : IGTexturePainter, IGTexturePainterWithCustomParams, IGTexturePainterWithLivePreview
|
||||
{
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int STEP_COUNT = Shader.PropertyToID("_StepCount");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.terracePainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Paint terrace (step) effect on terrain geometry.\n" +
|
||||
" - Use Left Mouse to paint.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Terrace Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.HeightMapAndFoliageResourceFlags;
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.MouseEventType == GPainterMouseEventType.Down)
|
||||
{
|
||||
terrain.ForceLOD(0);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = true;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Geometry.HeightMap.ReadPixels(
|
||||
new Rect(0, 0, heightMapResolution, heightMapResolution), 0, 0);
|
||||
terrain.TerrainData.Geometry.HeightMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect);
|
||||
terrain.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect);
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Geometry.HeightMap;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, Mathf.Pow(args.Opacity, GTerrainTexturePainter.GEOMETRY_OPACITY_EXPONENT));
|
||||
mat.SetInt(STEP_COUNT, GTexturePainterCustomParams.Instance.Terrace.StepCount);
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
int pass = 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
terrain.ForceLOD(-1);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = false;
|
||||
terrain.UpdateTreesPosition();
|
||||
terrain.UpdateGrassPatches();
|
||||
terrain.TerrainData.Foliage.ClearTreeDirtyRegions();
|
||||
terrain.TerrainData.Foliage.ClearGrassDirtyRegions();
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawCustomParamsGUI()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
string label = "Terrace Painting";
|
||||
string id = "terrace-painter-params";
|
||||
|
||||
GCommonGUI.Foldout(label, true, id, () =>
|
||||
{
|
||||
GTerracePainterParams param = GTexturePainterCustomParams.Instance.Terrace;
|
||||
param.StepCount = EditorGUILayout.IntField("Step Count", param.StepCount);
|
||||
GTexturePainterCustomParams.Instance.Terrace = param;
|
||||
EditorUtility.SetDirty(GTexturePainterCustomParams.Instance);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
GLivePreviewDrawer.DrawGeometryLivePreview(terrain, cam, rt, dirtyRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93c2e86a56af13940b6fbe48383183bc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,24 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct GTerracePainterParams
|
||||
{
|
||||
[SerializeField]
|
||||
private int stepCount;
|
||||
public int StepCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return stepCount;
|
||||
}
|
||||
set
|
||||
{
|
||||
stepCount = Mathf.Max(1, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c6e363d854cd224e9f5f22000e124b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,735 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using Type = System.Type;
|
||||
using Rand = System.Random;
|
||||
#if UNITY_EDITOR
|
||||
using Pinwheel.Griffin.BackupTool;
|
||||
#endif
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[System.Serializable]
|
||||
[ExecuteInEditMode]
|
||||
public class GTerrainTexturePainter : MonoBehaviour
|
||||
{
|
||||
public const float GEOMETRY_OPACITY_EXPONENT = 3;
|
||||
|
||||
private static readonly List<string> BUILTIN_PAINTER_NAME = new List<string>(new string[]
|
||||
{
|
||||
"GElevationPainter",
|
||||
"GHeightSamplingPainter",
|
||||
"GTerracePainter",
|
||||
"GRemapPainter",
|
||||
"GNoisePainter",
|
||||
"GSubDivPainter",
|
||||
"GVisibilityPainter",
|
||||
"GAlbedoPainter",
|
||||
"GMetallicPainter",
|
||||
"GSmoothnessPainter",
|
||||
"GSplatPainter",
|
||||
"GMaskPainter"
|
||||
});
|
||||
|
||||
private static List<Type> customPainterTypes;
|
||||
private static List<Type> CustomPainterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (customPainterTypes == null)
|
||||
customPainterTypes = new List<Type>();
|
||||
return customPainterTypes;
|
||||
}
|
||||
set
|
||||
{
|
||||
customPainterTypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static string TexturePainterInterfaceName
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(IGTexturePainter).Name;
|
||||
}
|
||||
}
|
||||
|
||||
static GTerrainTexturePainter()
|
||||
{
|
||||
RefreshCustomPainterTypes();
|
||||
}
|
||||
|
||||
public static void RefreshCustomPainterTypes()
|
||||
{
|
||||
List<Type> loadedTypes = GCommon.GetAllLoadedTypes();
|
||||
CustomPainterTypes = loadedTypes.FindAll(
|
||||
t => t.GetInterface(TexturePainterInterfaceName) != null &&
|
||||
!BUILTIN_PAINTER_NAME.Contains(t.Name));
|
||||
}
|
||||
|
||||
public static List<Type> GetCustomPainterTypes()
|
||||
{
|
||||
return CustomPainterTypes;
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int groupId;
|
||||
public int GroupId
|
||||
{
|
||||
get
|
||||
{
|
||||
return groupId;
|
||||
}
|
||||
set
|
||||
{
|
||||
groupId = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private GTexturePaintingMode mode;
|
||||
public GTexturePaintingMode Mode
|
||||
{
|
||||
get
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
set
|
||||
{
|
||||
mode = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int customPainterIndex;
|
||||
public int CustomPainterIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return customPainterIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
customPainterIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private string customPainterArgs;
|
||||
public string CustomPainterArgs
|
||||
{
|
||||
get
|
||||
{
|
||||
return customPainterArgs;
|
||||
}
|
||||
set
|
||||
{
|
||||
customPainterArgs = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool enableTerrainMask = true;
|
||||
public bool EnableTerrainMask
|
||||
{
|
||||
get
|
||||
{
|
||||
return enableTerrainMask;
|
||||
}
|
||||
set
|
||||
{
|
||||
enableTerrainMask = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool forceUpdateGeometry;
|
||||
public bool ForceUpdateGeometry
|
||||
{
|
||||
get
|
||||
{
|
||||
return forceUpdateGeometry;
|
||||
}
|
||||
set
|
||||
{
|
||||
forceUpdateGeometry = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IGTexturePainter ActivePainter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Mode == GTexturePaintingMode.Elevation)
|
||||
{
|
||||
return new GElevationPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.HeightSampling)
|
||||
{
|
||||
return new GHeightSamplingPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Terrace)
|
||||
{
|
||||
return new GTerracePainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Remap)
|
||||
{
|
||||
return new GRemapPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Noise)
|
||||
{
|
||||
return new GNoisePainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.SubDivision)
|
||||
{
|
||||
return new GSubDivPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Visibility)
|
||||
{
|
||||
return new GVisibilityPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Albedo)
|
||||
{
|
||||
return new GAlbedoPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Metallic)
|
||||
{
|
||||
return new GMetallicPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Smoothness)
|
||||
{
|
||||
return new GSmoothnessPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Splat)
|
||||
{
|
||||
return new GSplatPainter();
|
||||
}
|
||||
else if (Mode == GTexturePaintingMode.Mask)
|
||||
{
|
||||
return new GMaskPainter();
|
||||
}
|
||||
else if (mode == GTexturePaintingMode.Custom)
|
||||
{
|
||||
if (CustomPainterIndex >= 0 && CustomPainterIndex < CustomPainterTypes.Count)
|
||||
return System.Activator.CreateInstance(CustomPainterTypes[CustomPainterIndex]) as IGTexturePainter;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRadius;
|
||||
public float BrushRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRadius;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRadius = Mathf.Max(0.01f, value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRadiusJitter;
|
||||
public float BrushRadiusJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRadiusJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRadiusJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRotation;
|
||||
public float BrushRotation
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRotation;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRotation = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRotationJitter;
|
||||
public float BrushRotationJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRotationJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRotationJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushOpacity;
|
||||
public float BrushOpacity
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushOpacity;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushOpacity = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushOpacityJitter;
|
||||
public float BrushOpacityJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushOpacityJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushOpacityJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushTargetStrength = 1;
|
||||
public float BrushTargetStrength
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushTargetStrength;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushTargetStrength = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushScatter;
|
||||
public float BrushScatter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushScatter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushScatter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushScatterJitter;
|
||||
public float BrushScatterJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushScatterJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushScatterJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private Color brushColor;
|
||||
public Color BrushColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushColor;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushColor = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<Texture2D> brushMasks;
|
||||
public List<Texture2D> BrushMasks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (brushMasks == null)
|
||||
brushMasks = new List<Texture2D>();
|
||||
return brushMasks;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushMasks = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int selectedBrushMaskIndex;
|
||||
public int SelectedBrushMaskIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return selectedBrushMaskIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (BrushMasks.Count > 0)
|
||||
selectedBrushMaskIndex = Mathf.Clamp(value, 0, BrushMasks.Count);
|
||||
else
|
||||
selectedBrushMaskIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectedSplatIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SelectedSplatIndices.Count == 0)
|
||||
{
|
||||
SelectedSplatIndices.Add(0);
|
||||
}
|
||||
return SelectedSplatIndices[0];
|
||||
}
|
||||
set
|
||||
{
|
||||
SelectedSplatIndices.Clear();
|
||||
SelectedSplatIndices.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<int> selectedSplatIndices;
|
||||
public List<int> SelectedSplatIndices
|
||||
{
|
||||
get
|
||||
{
|
||||
if (selectedSplatIndices == null)
|
||||
{
|
||||
selectedSplatIndices = new List<int>();
|
||||
}
|
||||
return selectedSplatIndices;
|
||||
}
|
||||
set
|
||||
{
|
||||
selectedSplatIndices = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private Vector3 samplePoint;
|
||||
public Vector3 SamplePoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return samplePoint;
|
||||
}
|
||||
set
|
||||
{
|
||||
samplePoint = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private GConditionalPaintingConfigs conditionalPaintingConfigs;
|
||||
public GConditionalPaintingConfigs ConditionalPaintingConfigs
|
||||
{
|
||||
get
|
||||
{
|
||||
return conditionalPaintingConfigs;
|
||||
}
|
||||
set
|
||||
{
|
||||
conditionalPaintingConfigs = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static Dictionary<string, RenderTexture> internal_RenderTextures;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ReloadBrushMasks();
|
||||
|
||||
if (conditionalPaintingConfigs != null)
|
||||
{
|
||||
conditionalPaintingConfigs.UpdateCurveTextures();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
GroupId = 0;
|
||||
Mode = GTexturePaintingMode.Elevation;
|
||||
BrushRadius = 50;
|
||||
BrushRadiusJitter = 0;
|
||||
BrushOpacity = 0.5f;
|
||||
BrushOpacityJitter = 0;
|
||||
BrushTargetStrength = 1;
|
||||
BrushRotation = 0;
|
||||
BrushRotationJitter = 0;
|
||||
BrushColor = Color.white;
|
||||
|
||||
if (conditionalPaintingConfigs != null)
|
||||
{
|
||||
conditionalPaintingConfigs.CleanUp();
|
||||
}
|
||||
conditionalPaintingConfigs = new GConditionalPaintingConfigs();
|
||||
conditionalPaintingConfigs.UpdateCurveTextures();
|
||||
}
|
||||
|
||||
public void ReloadBrushMasks()
|
||||
{
|
||||
BrushMasks = new List<Texture2D>(Resources.LoadAll<Texture2D>(GCommon.BRUSH_MASK_RESOURCES_PATH));
|
||||
}
|
||||
|
||||
public void Paint(GTexturePainterArgs args)
|
||||
{
|
||||
IGTexturePainter p = ActivePainter;
|
||||
if (p == null)
|
||||
return;
|
||||
|
||||
FillArgs(ref args);
|
||||
|
||||
List<GStylizedTerrain> overlappedTerrain = GUtilities.ExtractTerrainsFromOverlapTest(GPaintToolUtilities.OverlapTest(GroupId, args.HitPoint, args.Radius, args.Rotation));
|
||||
#if UNITY_EDITOR
|
||||
if (args.MouseEventType == GPainterMouseEventType.Down ||
|
||||
args.MouseEventType == GPainterMouseEventType.Drag)
|
||||
{
|
||||
Editor_CreateInitialHistoryEntry(args, overlappedTerrain);
|
||||
}
|
||||
#endif
|
||||
foreach (GStylizedTerrain t in overlappedTerrain)
|
||||
{
|
||||
p.BeginPainting(t, args);
|
||||
}
|
||||
|
||||
foreach (GStylizedTerrain t in overlappedTerrain)
|
||||
{
|
||||
p.EndPainting(t, args);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
EditedTerrains.UnionWith(overlappedTerrain);
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
Editor_CreateHistory(args);
|
||||
currentInitialBackupName = null;
|
||||
InitialRecordedTerrains.Clear();
|
||||
EditedTerrains.Clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private HashSet<GStylizedTerrain> initialRecordedTerrains;
|
||||
private HashSet<GStylizedTerrain> InitialRecordedTerrains
|
||||
{
|
||||
get
|
||||
{
|
||||
if (initialRecordedTerrains == null)
|
||||
{
|
||||
initialRecordedTerrains = new HashSet<GStylizedTerrain>();
|
||||
}
|
||||
return initialRecordedTerrains;
|
||||
}
|
||||
}
|
||||
|
||||
private HashSet<GStylizedTerrain> editedTerrains;
|
||||
private HashSet<GStylizedTerrain> EditedTerrains
|
||||
{
|
||||
get
|
||||
{
|
||||
if (editedTerrains == null)
|
||||
{
|
||||
editedTerrains = new HashSet<GStylizedTerrain>();
|
||||
}
|
||||
return editedTerrains;
|
||||
}
|
||||
}
|
||||
|
||||
private string currentInitialBackupName;
|
||||
|
||||
private void Editor_CreateInitialHistoryEntry(GTexturePainterArgs args, List<GStylizedTerrain> overlappedTerrains)
|
||||
{
|
||||
if (!GEditorSettings.Instance.paintTools.enableHistory)
|
||||
return;
|
||||
if (overlappedTerrains.Count == 0)
|
||||
return;
|
||||
|
||||
List<GTerrainResourceFlag> flags = new List<GTerrainResourceFlag>();
|
||||
flags.AddRange(ActivePainter.GetResourceFlagForHistory(args));
|
||||
|
||||
if (InitialRecordedTerrains.Count == 0)
|
||||
{
|
||||
currentInitialBackupName = GBackup.TryCreateInitialBackup(ActivePainter.HistoryPrefix, overlappedTerrains[0], flags, false);
|
||||
if (!string.IsNullOrEmpty(currentInitialBackupName))
|
||||
{
|
||||
InitialRecordedTerrains.Add(overlappedTerrains[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(currentInitialBackupName))
|
||||
{
|
||||
for (int i = 0; i < overlappedTerrains.Count; ++i)
|
||||
{
|
||||
if (InitialRecordedTerrains.Contains(overlappedTerrains[i]))
|
||||
continue;
|
||||
GBackup.BackupTerrain(overlappedTerrains[i], currentInitialBackupName, flags);
|
||||
InitialRecordedTerrains.Add(overlappedTerrains[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Editor_CreateHistory(GTexturePainterArgs args)
|
||||
{
|
||||
if (!GEditorSettings.Instance.paintTools.enableHistory)
|
||||
return;
|
||||
if (EditedTerrains.Count == 0)
|
||||
return;
|
||||
|
||||
List<GTerrainResourceFlag> flags = new List<GTerrainResourceFlag>();
|
||||
flags.AddRange(ActivePainter.GetResourceFlagForHistory(args));
|
||||
|
||||
List<GStylizedTerrain> terrainList = new List<GStylizedTerrain>(EditedTerrains);
|
||||
string backupName = GBackup.TryCreateBackup(ActivePainter.HistoryPrefix, terrainList[0], flags, false);
|
||||
if (!string.IsNullOrEmpty(backupName))
|
||||
{
|
||||
for (int i = 1; i < terrainList.Count; ++i)
|
||||
{
|
||||
GBackup.BackupTerrain(terrainList[i], backupName, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal static RenderTexture Internal_GetRenderTexture(GStylizedTerrain t, int resolution, int id = 0)
|
||||
{
|
||||
if (internal_RenderTextures == null)
|
||||
{
|
||||
internal_RenderTextures = new Dictionary<string, RenderTexture>();
|
||||
}
|
||||
|
||||
string key = string.Format("{0}_{1}", t != null ? t.GetInstanceID() : 0, id);
|
||||
if (!internal_RenderTextures.ContainsKey(key) ||
|
||||
internal_RenderTextures[key] == null)
|
||||
{
|
||||
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
|
||||
internal_RenderTextures[key] = rt;
|
||||
}
|
||||
else if (internal_RenderTextures[key].width != resolution ||
|
||||
internal_RenderTextures[key].height != resolution ||
|
||||
internal_RenderTextures[key].format != GGeometry.HeightMapRTFormat)
|
||||
{
|
||||
internal_RenderTextures[key].Release();
|
||||
Object.DestroyImmediate(internal_RenderTextures[key]);
|
||||
RenderTexture rt = new RenderTexture(resolution, resolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
|
||||
internal_RenderTextures[key] = rt;
|
||||
}
|
||||
|
||||
internal_RenderTextures[key].wrapMode = TextureWrapMode.Clamp;
|
||||
|
||||
return internal_RenderTextures[key];
|
||||
}
|
||||
|
||||
public static void Internal_ReleaseRenderTextures()
|
||||
{
|
||||
if (internal_RenderTextures != null)
|
||||
{
|
||||
foreach (string k in internal_RenderTextures.Keys)
|
||||
{
|
||||
RenderTexture rt = internal_RenderTextures[k];
|
||||
if (rt == null)
|
||||
continue;
|
||||
rt.Release();
|
||||
Object.DestroyImmediate(rt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Rand GetRandomGenerator()
|
||||
{
|
||||
return new Rand(System.DateTime.Now.Millisecond);
|
||||
}
|
||||
|
||||
private void ProcessBrushDynamic(ref GTexturePainterArgs args)
|
||||
{
|
||||
Rand rand = GetRandomGenerator();
|
||||
args.Radius -= BrushRadius * BrushRadiusJitter * (float)rand.NextDouble();
|
||||
args.Rotation += Mathf.Sign((float)rand.NextDouble() - 0.5f) * BrushRotation * BrushRotationJitter * (float)rand.NextDouble();
|
||||
args.Opacity -= BrushOpacity * BrushOpacityJitter * (float)rand.NextDouble();
|
||||
|
||||
Vector3 scatterDir = new Vector3((float)(rand.NextDouble() * 2 - 1), 0, (float)(rand.NextDouble() * 2 - 1)).normalized;
|
||||
float scatterLengthMultiplier = BrushScatter - (float)rand.NextDouble() * BrushScatterJitter;
|
||||
float scatterLength = args.Radius * scatterLengthMultiplier;
|
||||
|
||||
args.HitPoint += scatterDir * scatterLength;
|
||||
}
|
||||
|
||||
public void FillArgs(ref GTexturePainterArgs args, bool useBrushDynamic = true)
|
||||
{
|
||||
args.Radius = BrushRadius;
|
||||
args.Rotation = BrushRotation;
|
||||
args.Opacity = BrushOpacity * BrushTargetStrength;
|
||||
args.Color = BrushColor;
|
||||
if (SelectedSplatIndices.Count > 0)
|
||||
{
|
||||
args.SplatIndex = SelectedSplatIndices[Random.Range(0, SelectedSplatIndices.Count)];
|
||||
}
|
||||
else
|
||||
{
|
||||
args.SplatIndex = -1;
|
||||
}
|
||||
args.SamplePoint = SamplePoint;
|
||||
args.CustomArgs = CustomPainterArgs;
|
||||
args.ForceUpdateGeometry = ForceUpdateGeometry;
|
||||
args.EnableTerrainMask = EnableTerrainMask;
|
||||
if (SelectedBrushMaskIndex >= 0 && SelectedBrushMaskIndex < BrushMasks.Count)
|
||||
{
|
||||
args.BrushMask = BrushMasks[SelectedBrushMaskIndex];
|
||||
}
|
||||
|
||||
if (args.ActionType == GPainterActionType.Alternative &&
|
||||
args.MouseEventType == GPainterMouseEventType.Down)
|
||||
{
|
||||
SamplePoint = args.HitPoint;
|
||||
args.SamplePoint = args.HitPoint;
|
||||
}
|
||||
|
||||
if (useBrushDynamic)
|
||||
{
|
||||
ProcessBrushDynamic(ref args);
|
||||
}
|
||||
|
||||
Vector3[] corners = GCommon.GetBrushQuadCorners(args.HitPoint, args.Radius, args.Rotation);
|
||||
args.WorldPointCorners = corners;
|
||||
|
||||
args.ConditionalPaintingConfigs = this.ConditionalPaintingConfigs;
|
||||
}
|
||||
|
||||
public void CleanUp()
|
||||
{
|
||||
Internal_ReleaseRenderTextures();
|
||||
if (conditionalPaintingConfigs != null)
|
||||
{
|
||||
conditionalPaintingConfigs.CleanUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec1be11e0fe923b42bb2d698e52e0198
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,26 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public struct GTexturePainterArgs
|
||||
{
|
||||
public Vector3 HitPoint { get; set; }
|
||||
public Vector3[] WorldPointCorners { get; set; }
|
||||
public Texture BrushMask { get; set; }
|
||||
public float Radius { get; set; }
|
||||
public float Rotation { get; set; }
|
||||
public float Opacity { get; set; }
|
||||
public Color Color { get; set; }
|
||||
public int SplatIndex { get; set; }
|
||||
public Vector3 SamplePoint { get; set; }
|
||||
public string CustomArgs { get; set; }
|
||||
public GPainterMouseEventType MouseEventType { get; set; }
|
||||
public GPainterActionType ActionType { get; set; }
|
||||
public bool ForceUpdateGeometry { get; set; }
|
||||
public bool EnableTerrainMask { get; set; }
|
||||
public GConditionalPaintingConfigs ConditionalPaintingConfigs { get; set; }
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b70b9405f5d0824cab909b072f86618
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,83 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
//[CreateAssetMenu(menuName = "Griffin/Texture Painter Custom Params")]
|
||||
public class GTexturePainterCustomParams : ScriptableObject
|
||||
{
|
||||
private static GTexturePainterCustomParams instance;
|
||||
public static GTexturePainterCustomParams Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = Resources.Load<GTexturePainterCustomParams>("TexturePainterCustomParams");
|
||||
if (instance == null)
|
||||
{
|
||||
instance = ScriptableObject.CreateInstance<GTexturePainterCustomParams>();
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private GTerracePainterParams terrace;
|
||||
public GTerracePainterParams Terrace
|
||||
{
|
||||
get
|
||||
{
|
||||
return terrace;
|
||||
}
|
||||
set
|
||||
{
|
||||
terrace = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private GRemapPainterParams remap;
|
||||
public GRemapPainterParams Remap
|
||||
{
|
||||
get
|
||||
{
|
||||
return remap;
|
||||
}
|
||||
set
|
||||
{
|
||||
remap = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private GNoisePainterParams noise;
|
||||
public GNoisePainterParams Noise
|
||||
{
|
||||
get
|
||||
{
|
||||
return noise;
|
||||
}
|
||||
set
|
||||
{
|
||||
noise = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private GMaskPainterParams mask;
|
||||
public GMaskPainterParams Mask
|
||||
{
|
||||
get
|
||||
{
|
||||
return mask;
|
||||
}
|
||||
set
|
||||
{
|
||||
mask = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1c6f07db5b50b1429e5c9bf5274042f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,9 @@
|
||||
#if GRIFFIN
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public enum GTexturePaintingMode
|
||||
{
|
||||
Elevation, HeightSampling, Terrace, Remap, Noise, SubDivision, Visibility, Albedo, Metallic, Smoothness, Splat, Mask, Custom
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4559f3cb800a56a4783b3b7bdb34d0c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,133 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GVisibilityPainter : IGTexturePainter, IGTexturePainterWithLivePreview
|
||||
{
|
||||
private static readonly int MAIN_TEX = Shader.PropertyToID("_MainTex");
|
||||
private static readonly int MASK = Shader.PropertyToID("_Mask");
|
||||
private static readonly int OPACITY = Shader.PropertyToID("_Opacity");
|
||||
private static readonly int TERRAIN_MASK = Shader.PropertyToID("_TerrainMask");
|
||||
|
||||
private static Material painterMaterial;
|
||||
public static Material PainterMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (painterMaterial == null)
|
||||
{
|
||||
painterMaterial = new Material(GRuntimeSettings.Instance.internalShaders.visibilityPainterShader);
|
||||
}
|
||||
return painterMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
string s = string.Format(
|
||||
"Mark a particular area of terrain surface as visible or not.\n" +
|
||||
" - Hold Left Mouse to paint.\n" +
|
||||
" - Hold Ctrl & Left Mouse to erase.");
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public string HistoryPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Visibility Painting";
|
||||
}
|
||||
}
|
||||
|
||||
public List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args)
|
||||
{
|
||||
return GCommon.HeightMapAndFoliageResourceFlags;
|
||||
}
|
||||
|
||||
public void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (args.MouseEventType == GPainterMouseEventType.Down)
|
||||
{
|
||||
terrain.ForceLOD(0);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = true;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
RenderTexture.active = rt;
|
||||
terrain.TerrainData.Geometry.HeightMap.ReadPixels(
|
||||
new Rect(0, 0, heightMapResolution, heightMapResolution), 0, 0);
|
||||
terrain.TerrainData.Geometry.HeightMap.Apply();
|
||||
RenderTexture.active = null;
|
||||
|
||||
terrain.TerrainData.Geometry.SetRegionDirty(dirtyRect);
|
||||
}
|
||||
|
||||
private void PaintOnRT(GStylizedTerrain terrain, GTexturePainterArgs args, RenderTexture rt, Vector2[] uvCorners)
|
||||
{
|
||||
Texture2D bg = terrain.TerrainData.Geometry.HeightMap;
|
||||
GCommon.CopyToRT(bg, rt);
|
||||
|
||||
Material mat = PainterMaterial;
|
||||
mat.SetTexture(MAIN_TEX, bg);
|
||||
mat.SetTexture(MASK, args.BrushMask);
|
||||
mat.SetFloat(OPACITY, Mathf.Pow(args.Opacity, GTerrainTexturePainter.GEOMETRY_OPACITY_EXPONENT));
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, terrain.TerrainData.Mask.MaskMapOrDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.SetTexture(TERRAIN_MASK, Texture2D.blackTexture);
|
||||
}
|
||||
int pass =
|
||||
args.ActionType == GPainterActionType.Normal ? 0 :
|
||||
args.ActionType == GPainterActionType.Negative ? 1 : 0;
|
||||
GCommon.DrawQuad(rt, uvCorners, mat, pass);
|
||||
}
|
||||
|
||||
public void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args)
|
||||
{
|
||||
terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Geometry);
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
terrain.ForceLOD(-1);
|
||||
GRuntimeSettings.Instance.isEditingGeometry = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Vector2[] uvCorners = GPaintToolUtilities.WorldToUvCorners(terrain, args.WorldPointCorners);
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
|
||||
int heightMapResolution = terrain.TerrainData.Geometry.HeightMapResolution;
|
||||
RenderTexture rt = GTerrainTexturePainter.Internal_GetRenderTexture(terrain, heightMapResolution);
|
||||
PaintOnRT(terrain, args, rt, uvCorners);
|
||||
|
||||
Matrix4x4 worldToMaskMatrix = Matrix4x4.TRS(
|
||||
args.WorldPointCorners[0],
|
||||
Quaternion.Euler(0, args.Rotation, 0),
|
||||
args.Radius * 2 * Vector3.one).inverse;
|
||||
|
||||
GLivePreviewDrawer.DrawVisibilityLivePreview(terrain, cam, rt, dirtyRect, args.BrushMask, worldToMaskMatrix);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ec1fff30a847dd4cb516e456a3c77a3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public interface IConditionalPainter
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85dc21eb047aaaa4db54d9a3f9ed779c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,15 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public interface IGTexturePainter
|
||||
{
|
||||
string HistoryPrefix { get; }
|
||||
string Instruction { get; }
|
||||
void BeginPainting(GStylizedTerrain terrain, GTexturePainterArgs args);
|
||||
void EndPainting(GStylizedTerrain terrain, GTexturePainterArgs args);
|
||||
List<GTerrainResourceFlag> GetResourceFlagForHistory(GTexturePainterArgs args);
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8be616b830d600646b1a9cbb3492efb9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,9 @@
|
||||
#if GRIFFIN
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public interface IGTexturePainterWithCustomParams
|
||||
{
|
||||
void Editor_DrawCustomParamsGUI();
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01c5d52d49be4904a96c7c3887f728c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,11 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public interface IGTexturePainterWithLivePreview
|
||||
{
|
||||
void Editor_DrawLivePreview(GStylizedTerrain terrain, GTexturePainterArgs args, Camera cam);
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cdf524f9e719624cbabfab6c840c2d1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a34d25df79fe1214590e2849f1088432
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,435 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Rand = System.Random;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[System.Serializable]
|
||||
[ExecuteInEditMode]
|
||||
public class GObjectPainter : MonoBehaviour
|
||||
{
|
||||
private static readonly List<string> BUILTIN_PAINTER_NAME = new List<string>(new string[]
|
||||
{
|
||||
"GObjectSpawner",
|
||||
"GObjectScaler"
|
||||
});
|
||||
|
||||
private static List<Type> customPainterTypes;
|
||||
public static List<Type> CustomPainterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (customPainterTypes == null)
|
||||
customPainterTypes = new List<Type>();
|
||||
return customPainterTypes;
|
||||
}
|
||||
private set
|
||||
{
|
||||
customPainterTypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ObjectPainterInterfaceName
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(IGObjectPainter).Name;
|
||||
}
|
||||
}
|
||||
|
||||
static GObjectPainter()
|
||||
{
|
||||
RefreshCustomPainterTypes();
|
||||
}
|
||||
|
||||
public static void RefreshCustomPainterTypes()
|
||||
{
|
||||
List<Type> loadedTypes = GCommon.GetAllLoadedTypes();
|
||||
CustomPainterTypes = loadedTypes.FindAll(
|
||||
t => t.GetInterface(ObjectPainterInterfaceName) != null &&
|
||||
!BUILTIN_PAINTER_NAME.Contains(t.Name));
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int groupId;
|
||||
public int GroupId
|
||||
{
|
||||
get
|
||||
{
|
||||
return groupId;
|
||||
}
|
||||
set
|
||||
{
|
||||
groupId = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool enableTerrainMask;
|
||||
public bool EnableTerrainMask
|
||||
{
|
||||
get
|
||||
{
|
||||
return enableTerrainMask;
|
||||
}
|
||||
set
|
||||
{
|
||||
enableTerrainMask = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private GObjectPaintingMode mode;
|
||||
public GObjectPaintingMode Mode
|
||||
{
|
||||
get
|
||||
{
|
||||
return mode;
|
||||
}
|
||||
set
|
||||
{
|
||||
mode = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int customPainterIndex;
|
||||
public int CustomPainterIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return customPainterIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
customPainterIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private string customPainterArgs;
|
||||
public string CustomPainterArgs
|
||||
{
|
||||
get
|
||||
{
|
||||
return customPainterArgs;
|
||||
}
|
||||
set
|
||||
{
|
||||
customPainterArgs = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IGObjectPainter ActivePainter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Mode == GObjectPaintingMode.Spawn)
|
||||
{
|
||||
return new GObjectSpawner();
|
||||
}
|
||||
else if (Mode == GObjectPaintingMode.Scale)
|
||||
{
|
||||
return new GObjectScaler();
|
||||
}
|
||||
else if (mode == GObjectPaintingMode.Custom)
|
||||
{
|
||||
if (CustomPainterIndex >= 0 && CustomPainterIndex < CustomPainterTypes.Count)
|
||||
return System.Activator.CreateInstance(CustomPainterTypes[CustomPainterIndex]) as IGObjectPainter;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRadius;
|
||||
public float BrushRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRadius;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRadius = Mathf.Max(0.01f, value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRadiusJitter;
|
||||
public float BrushRadiusJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRadiusJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRadiusJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRotation;
|
||||
public float BrushRotation
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRotation;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRotation = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushRotationJitter;
|
||||
public float BrushRotationJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushRotationJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushRotationJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int brushDensity;
|
||||
public int BrushDensity
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushDensity;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushDensity = Mathf.Clamp(value, 1, 100);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushDensityJitter;
|
||||
public float BrushDensityJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushDensityJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushDensityJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushScatter;
|
||||
public float BrushScatter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushScatter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushScatter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float brushScatterJitter;
|
||||
public float BrushScatterJitter
|
||||
{
|
||||
get
|
||||
{
|
||||
return brushScatterJitter;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushScatterJitter = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<Texture2D> brushMasks;
|
||||
public List<Texture2D> BrushMasks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (brushMasks == null)
|
||||
brushMasks = new List<Texture2D>();
|
||||
return brushMasks;
|
||||
}
|
||||
set
|
||||
{
|
||||
brushMasks = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private int selectedBrushMaskIndex;
|
||||
public int SelectedBrushMaskIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return selectedBrushMaskIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (BrushMasks.Count > 0)
|
||||
selectedBrushMaskIndex = Mathf.Clamp(value, 0, BrushMasks.Count);
|
||||
else
|
||||
selectedBrushMaskIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<GameObject> prototypes;
|
||||
public List<GameObject> Prototypes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (prototypes == null)
|
||||
{
|
||||
prototypes = new List<GameObject>();
|
||||
}
|
||||
return prototypes;
|
||||
}
|
||||
set
|
||||
{
|
||||
prototypes = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<int> selectedPrototypeIndices;
|
||||
public List<int> SelectedPrototypeIndices
|
||||
{
|
||||
get
|
||||
{
|
||||
if (selectedPrototypeIndices == null)
|
||||
{
|
||||
selectedPrototypeIndices = new List<int>();
|
||||
}
|
||||
return selectedPrototypeIndices;
|
||||
}
|
||||
set
|
||||
{
|
||||
selectedPrototypeIndices = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float eraseRatio;
|
||||
public float EraseRatio
|
||||
{
|
||||
get
|
||||
{
|
||||
return eraseRatio;
|
||||
}
|
||||
set
|
||||
{
|
||||
eraseRatio = Mathf.Clamp01(value);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float scaleStrength;
|
||||
public float ScaleStrength
|
||||
{
|
||||
get
|
||||
{
|
||||
return scaleStrength;
|
||||
}
|
||||
set
|
||||
{
|
||||
scaleStrength = Mathf.Max(0, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ReloadBrushMasks();
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
GroupId = 0;
|
||||
Mode = GObjectPaintingMode.Spawn;
|
||||
BrushRadius = 50;
|
||||
BrushRadiusJitter = 0;
|
||||
BrushDensity = 1;
|
||||
BrushDensityJitter = 0;
|
||||
BrushRotation = 0;
|
||||
BrushRotationJitter = 0;
|
||||
EraseRatio = 1;
|
||||
ScaleStrength = 1;
|
||||
}
|
||||
|
||||
public void ReloadBrushMasks()
|
||||
{
|
||||
BrushMasks = new List<Texture2D>(Resources.LoadAll<Texture2D>(GCommon.BRUSH_MASK_RESOURCES_PATH));
|
||||
}
|
||||
|
||||
public void Paint(GObjectPainterArgs args)
|
||||
{
|
||||
IGObjectPainter p = ActivePainter;
|
||||
if (p == null)
|
||||
return;
|
||||
|
||||
args.Radius = BrushRadius;
|
||||
args.Rotation = BrushRotation;
|
||||
args.Density = BrushDensity;
|
||||
args.EraseRatio = EraseRatio;
|
||||
args.ScaleStrength = ScaleStrength;
|
||||
args.CustomArgs = CustomPainterArgs;
|
||||
args.Filters = GetComponents<GSpawnFilter>();
|
||||
if (SelectedBrushMaskIndex >= 0 && SelectedBrushMaskIndex < BrushMasks.Count)
|
||||
{
|
||||
args.Mask = BrushMasks[SelectedBrushMaskIndex];
|
||||
}
|
||||
if (SelectedPrototypeIndices.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
args.Prototypes = Prototypes;
|
||||
args.PrototypeIndices = SelectedPrototypeIndices;
|
||||
args.EnableTerrainMask = EnableTerrainMask;
|
||||
|
||||
ProcessBrushDynamic(ref args);
|
||||
Vector3[] corners = GCommon.GetBrushQuadCorners(args.HitPoint, args.Radius, args.Rotation);
|
||||
args.WorldPointCorners = corners;
|
||||
|
||||
List<GStylizedTerrain> terrains = GUtilities.ExtractTerrainsFromOverlapTest(GPaintToolUtilities.OverlapTest(groupId, args.HitPoint, args.Radius, args.Rotation));
|
||||
foreach(GStylizedTerrain t in terrains)
|
||||
{
|
||||
p.Paint(t, args);
|
||||
}
|
||||
}
|
||||
|
||||
private Rand GetRandomGenerator()
|
||||
{
|
||||
return new Rand(Time.frameCount);
|
||||
}
|
||||
|
||||
private void ProcessBrushDynamic(ref GObjectPainterArgs args)
|
||||
{
|
||||
Rand rand = GetRandomGenerator();
|
||||
args.Radius -= BrushRadius * BrushRadiusJitter * (float)rand.NextDouble();
|
||||
args.Rotation += Mathf.Sign((float)rand.NextDouble() - 0.5f) * BrushRotation * BrushRotationJitter * (float)rand.NextDouble();
|
||||
args.Density -= Mathf.RoundToInt(BrushDensity * BrushDensityJitter * (float)rand.NextDouble());
|
||||
|
||||
Vector3 scatterDir = new Vector3((float)(rand.NextDouble() * 2 - 1), 0, (float)(rand.NextDouble() * 2 - 1)).normalized;
|
||||
float scatterLengthMultiplier = BrushScatter - (float)rand.NextDouble() * BrushScatterJitter;
|
||||
float scatterLength = args.Radius * scatterLengthMultiplier;
|
||||
|
||||
args.HitPoint += scatterDir * scatterLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d026a0fb6cce7d4fa3a70b37045c798
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,26 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public struct GObjectPainterArgs
|
||||
{
|
||||
public Vector3 HitPoint { get; set; }
|
||||
public Vector3[] WorldPointCorners { get; internal set; }
|
||||
public Texture2D Mask { get; set; }
|
||||
public bool EnableTerrainMask { get; set; }
|
||||
public float Radius { get; internal set; }
|
||||
public float Rotation { get; internal set; }
|
||||
public int Density { get; internal set; }
|
||||
public float EraseRatio { get; internal set; }
|
||||
public float ScaleStrength { get; internal set; }
|
||||
public List<GameObject> Prototypes { get; set; }
|
||||
public List<int> PrototypeIndices { get; set; }
|
||||
public GSpawnFilter[] Filters { get; set; }
|
||||
public string CustomArgs { get; internal set; }
|
||||
public GPainterMouseEventType MouseEventType { get; set; }
|
||||
public GPainterActionType ActionType { get; set; }
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6cb838285c72feb47ae47162c479bfff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,9 @@
|
||||
#if GRIFFIN
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public enum GObjectPaintingMode
|
||||
{
|
||||
Spawn, Scale, Custom
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1fd9419f68c9294f9d9a933e351db36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,158 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GObjectScaler : IGObjectPainter
|
||||
{
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format(
|
||||
"Scale game object instances.\n" +
|
||||
" - Hold Left Mouse to scale up.\n" +
|
||||
" - Hold Ctrl & Left Mouse to scale down.");
|
||||
}
|
||||
}
|
||||
|
||||
public List<Type> SuitableFilterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>(new Type[]
|
||||
{
|
||||
typeof(GScaleClampFilter)
|
||||
});
|
||||
GPaintToolUtilities.AddCustomSpawnFilter(types);
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GObjectPainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]);
|
||||
}
|
||||
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
|
||||
return;
|
||||
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
int multiplier = args.ActionType == GPainterActionType.Normal ? 1 : -1;
|
||||
|
||||
int prototypeIndex = -1;
|
||||
Vector2 terrainUv = Vector2.zero;
|
||||
Vector3 worldPos = Vector3.zero;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
Vector3 scale = Vector3.zero;
|
||||
|
||||
for (int i = 0; i < args.PrototypeIndices.Count; ++i)
|
||||
{
|
||||
prototypeIndex = args.PrototypeIndices[i];
|
||||
if (prototypeIndex < 0 || prototypeIndex >= args.Prototypes.Count)
|
||||
continue;
|
||||
GameObject g = args.Prototypes[prototypeIndex];
|
||||
if (g == null)
|
||||
continue;
|
||||
GameObject root = GSpawner.GetRoot(terrain, g);
|
||||
Transform[] instances = GUtilities.GetChildrenTransforms(root.transform);
|
||||
int instanceCount = instances.Length;
|
||||
for (int j = 0; j < instanceCount; ++j)
|
||||
{
|
||||
worldPos = instances[j].position;
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale)
|
||||
continue;
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainUv = terrain.WorldPointToUV(worldPos);
|
||||
maskColor = terrainMask.GetPixelBilinear(terrainUv.x, terrainUv.y);
|
||||
if (Random.value < maskColor.r)
|
||||
continue;
|
||||
}
|
||||
|
||||
scale.Set(
|
||||
Mathf.Max(0, instances[j].transform.localScale.x + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME),
|
||||
Mathf.Max(0, instances[j].transform.localScale.y + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME),
|
||||
Mathf.Max(0, instances[j].transform.localScale.z + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME));
|
||||
|
||||
GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create();
|
||||
filterArgs.Terrain = terrain;
|
||||
filterArgs.Position = worldPos;
|
||||
filterArgs.Rotation = instances[j].transform.rotation;
|
||||
filterArgs.Scale = scale;
|
||||
List<Type> suitableFilter = SuitableFilterTypes;
|
||||
if (args.Filters != null)
|
||||
{
|
||||
for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex)
|
||||
{
|
||||
if (args.Filters[fIndex] != null &&
|
||||
args.Filters[fIndex].Ignore != true)
|
||||
{
|
||||
if (suitableFilter.Contains(args.Filters[fIndex].GetType()))
|
||||
args.Filters[fIndex].Apply(ref filterArgs);
|
||||
}
|
||||
if (filterArgs.ShouldExclude)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
instances[j].transform.localScale = filterArgs.Scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98b0f017deda5384ba9f2b94d9735693
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,268 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public class GObjectSpawner : IGObjectPainter
|
||||
{
|
||||
public string Instruction
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format(
|
||||
"Spawn game object into the scene.\n" +
|
||||
" - Hold Left Mouse to spawn.\n" +
|
||||
" - Hold Ctrl & Left Mouse to erase.");
|
||||
}
|
||||
}
|
||||
|
||||
public List<Type> SuitableFilterTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
List<Type> types = new List<Type>(new Type[]
|
||||
{
|
||||
typeof(GAlignToSurfaceFilter),
|
||||
typeof(GHeightConstraintFilter),
|
||||
typeof(GSlopeConstraintFilter),
|
||||
typeof(GRotationRandomizeFilter),
|
||||
typeof(GScaleRandomizeFilter),
|
||||
typeof(GScaleClampFilter)
|
||||
});
|
||||
GPaintToolUtilities.AddCustomSpawnFilter(types);
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GObjectPainterArgs args)
|
||||
{
|
||||
if (args.MouseEventType == GPainterMouseEventType.Up)
|
||||
return;
|
||||
|
||||
Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length];
|
||||
for (int i = 0; i < uvCorners.Length; ++i)
|
||||
{
|
||||
uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]);
|
||||
}
|
||||
|
||||
Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners);
|
||||
if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1)))
|
||||
return;
|
||||
|
||||
if (args.ActionType == GPainterActionType.Normal)
|
||||
{
|
||||
HandleSpawnObject(terrain, args);
|
||||
}
|
||||
else if (args.ActionType == GPainterActionType.Negative)
|
||||
{
|
||||
HandleEraseObject(terrain, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSpawnObject(GStylizedTerrain terrain, GObjectPainterArgs args)
|
||||
{
|
||||
int prototypeIndex = -1;
|
||||
Vector3 randomPos = Vector3.zero;
|
||||
Vector3 rayOrigin = Vector3.zero;
|
||||
Vector3 rayDirection = Vector3.down;
|
||||
float sqrtTwo = Mathf.Sqrt(2);
|
||||
Ray ray = new Ray();
|
||||
RaycastHit samplePoint;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Vector2 samplePointTexcoord = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.Density; ++i)
|
||||
{
|
||||
prototypeIndex = args.PrototypeIndices[Random.Range(0, args.PrototypeIndices.Count)];
|
||||
if (prototypeIndex < 0 || prototypeIndex >= args.Prototypes.Count)
|
||||
continue;
|
||||
GameObject g = args.Prototypes[prototypeIndex];
|
||||
if (g == null)
|
||||
continue;
|
||||
|
||||
randomPos = args.HitPoint + Random.insideUnitSphere * args.Radius * sqrtTwo;
|
||||
rayOrigin.Set(
|
||||
randomPos.x,
|
||||
10000,
|
||||
randomPos.z);
|
||||
ray.origin = rayOrigin;
|
||||
ray.direction = rayDirection;
|
||||
if (terrain.Raycast(ray, out samplePoint, float.MaxValue))
|
||||
{
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(samplePoint.point.x, samplePoint.point.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(samplePoint.point.x, samplePoint.point.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//sample mask
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale)
|
||||
continue;
|
||||
}
|
||||
//sample terrain mask
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
samplePointTexcoord = samplePoint.textureCoord;
|
||||
maskColor = terrainMask.GetPixelBilinear(samplePointTexcoord.x, samplePointTexcoord.y);
|
||||
if (Random.value < maskColor.r)
|
||||
continue;
|
||||
}
|
||||
|
||||
//apply filter
|
||||
GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create();
|
||||
filterArgs.Terrain = terrain;
|
||||
filterArgs.Position = samplePoint.point;
|
||||
filterArgs.SurfaceNormal = samplePoint.normal;
|
||||
filterArgs.SurfaceTexcoord = samplePoint.textureCoord;
|
||||
|
||||
List<Type> suitableFilter = SuitableFilterTypes;
|
||||
if (args.Filters != null)
|
||||
{
|
||||
for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex)
|
||||
{
|
||||
if (args.Filters[fIndex] != null &&
|
||||
args.Filters[fIndex].Ignore != true)
|
||||
{
|
||||
if (suitableFilter.Contains(args.Filters[fIndex].GetType()))
|
||||
args.Filters[fIndex].Apply(ref filterArgs);
|
||||
}
|
||||
if (filterArgs.ShouldExclude)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//spawn
|
||||
if (filterArgs.ShouldExclude)
|
||||
continue;
|
||||
|
||||
//spawn here
|
||||
GameObject instance = GSpawner.Spawn(terrain, g, samplePoint.point);
|
||||
instance.transform.position = filterArgs.Position;
|
||||
instance.transform.rotation = filterArgs.Rotation;
|
||||
instance.transform.localScale = filterArgs.Scale;
|
||||
}
|
||||
}
|
||||
|
||||
if (clonedMask != null)
|
||||
Object.DestroyImmediate(clonedMask);
|
||||
}
|
||||
|
||||
private void HandleEraseObject(GStylizedTerrain terrain, GObjectPainterArgs args)
|
||||
{
|
||||
int prototypeIndex = -1;
|
||||
Vector2 terrainUv = Vector3.zero;
|
||||
Vector3 worldPos = Vector3.zero;
|
||||
Vector3 bary0 = Vector3.zero;
|
||||
Vector3 bary1 = Vector3.zero;
|
||||
Vector2 maskUv = Vector2.zero;
|
||||
Color maskColor = Color.white;
|
||||
|
||||
Texture2D clonedMask = null;
|
||||
Texture2D terrainMask = null;
|
||||
if (args.Mask != null)
|
||||
{
|
||||
clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256);
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainMask = terrain.TerrainData.Mask.MaskMapOrDefault;
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.PrototypeIndices.Count; ++i)
|
||||
{
|
||||
prototypeIndex = args.PrototypeIndices[i];
|
||||
if (prototypeIndex < 0 || prototypeIndex >= args.Prototypes.Count)
|
||||
continue;
|
||||
GameObject g = args.Prototypes[prototypeIndex];
|
||||
if (g == null)
|
||||
continue;
|
||||
GSpawner.DestroyIf(terrain, g, (instance =>
|
||||
{
|
||||
worldPos = instance.transform.position;
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
ref bary0);
|
||||
GUtilities.CalculateBarycentricCoord(
|
||||
new Vector2(worldPos.x, worldPos.z),
|
||||
new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z),
|
||||
new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z),
|
||||
new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z),
|
||||
ref bary1);
|
||||
if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0)
|
||||
{
|
||||
maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one;
|
||||
}
|
||||
else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0)
|
||||
{
|
||||
maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//sample mask
|
||||
if (clonedMask != null)
|
||||
{
|
||||
maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y);
|
||||
if (Random.value > maskColor.grayscale * args.EraseRatio)
|
||||
return false;
|
||||
}
|
||||
if (args.EnableTerrainMask)
|
||||
{
|
||||
terrainUv = terrain.WorldPointToUV(worldPos);
|
||||
maskColor = terrainMask.GetPixelBilinear(terrainUv.x, terrainUv.y);
|
||||
if (Random.value < maskColor.r)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
if (clonedMask != null)
|
||||
Object.DestroyImmediate(clonedMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8952777ed5ccbef4e8e819b41bdda8f4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,13 @@
|
||||
#if GRIFFIN
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
public interface IGObjectPainter
|
||||
{
|
||||
string Instruction { get; }
|
||||
List<System.Type> SuitableFilterTypes { get; }
|
||||
void Paint(GStylizedTerrain terrain, GObjectPainterArgs args);
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5d13f18c0e50cc4b906fec0d92b36c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ee8b2e9b1ecc46479fe1a9ad410300f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,17 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[GDisplayName("Align To Surface")]
|
||||
public class GAlignToSurfaceFilter : GSpawnFilter
|
||||
{
|
||||
public override void Apply(ref GSpawnFilterArgs args)
|
||||
{
|
||||
Quaternion currentRotationY = Quaternion.Euler(0, args.Rotation.eulerAngles.y, 0);
|
||||
Quaternion rotationXZ = Quaternion.FromToRotation(Vector3.up, args.SurfaceNormal);
|
||||
args.Rotation = rotationXZ * currentRotationY;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0447f32f2703d1498a766ae0d698309
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,80 @@
|
||||
#if GRIFFIN
|
||||
//using UnityEngine;
|
||||
//using System.Collections;
|
||||
//using System.Collections.Generic;
|
||||
//using Pinwheel.Griffin.PaintTool;
|
||||
|
||||
//namespace Pinwheel.Griffin.PaintTool
|
||||
//{
|
||||
// [GDisplayName("Distance Constraint")]
|
||||
// public class GDistanceConstraintFilter : GSpawnFilter
|
||||
// {
|
||||
// [SerializeField]
|
||||
// private bool checkAllPrototype;
|
||||
// public bool CheckAllPrototype
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return checkAllPrototype;
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// checkAllPrototype = value;
|
||||
// }
|
||||
// }
|
||||
|
||||
// [SerializeField]
|
||||
// private float minimumDistance;
|
||||
// public float MinimumDistance
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return minimumDistance;
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// minimumDistance = Mathf.Max(0, value);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public override void Apply(ref GSpawnFilterArgs args)
|
||||
// {
|
||||
// float sqrDistance = 0;
|
||||
// float sqrMinimumDistance = MinimumDistance * MinimumDistance;
|
||||
// Vector3 localPos = Vector3.zero;
|
||||
// Vector3 worldPos = Vector3.zero;
|
||||
// Vector3 terrainSize = new Vector3(
|
||||
// args.Terrain.TerrainData.Geometry.Width,
|
||||
// args.Terrain.TerrainData.Geometry.Height,
|
||||
// args.Terrain.TerrainData.Geometry.Length);
|
||||
// List<GTreeInstance> instances = args.Terrain.TerrainData.Foliage.TreeInstances;
|
||||
// for (int i = instances.Count - 1; i >= 0; --i)
|
||||
// {
|
||||
// if (!CheckAllPrototype &&
|
||||
// instances[i].PrototypeIndex != args.PrototypeIndex)
|
||||
// continue;
|
||||
// localPos.Set(
|
||||
// terrainSize.x * instances[i].Position.x,
|
||||
// terrainSize.y * instances[i].Position.y,
|
||||
// terrainSize.z * instances[i].Position.z);
|
||||
// worldPos = args.Terrain.transform.TransformPoint(localPos);
|
||||
|
||||
// sqrDistance = (args.Position - worldPos).sqrMagnitude;
|
||||
// if (sqrDistance < sqrMinimumDistance)
|
||||
// {
|
||||
// args.ShouldExclude = true;
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// args.ShouldExclude = false;
|
||||
// }
|
||||
|
||||
// private void Reset()
|
||||
// {
|
||||
// CheckAllPrototype = false;
|
||||
// MinimumDistance = 1;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec6645d2bc213064e94be134d652b9c9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,74 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[GDisplayName("Height Constraint")]
|
||||
public class GHeightConstraintFilter : GSpawnFilter
|
||||
{
|
||||
[SerializeField]
|
||||
private Space space;
|
||||
public Space Space
|
||||
{
|
||||
get
|
||||
{
|
||||
return space;
|
||||
}
|
||||
set
|
||||
{
|
||||
space = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float minHeight;
|
||||
public float MinHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return minHeight;
|
||||
}
|
||||
set
|
||||
{
|
||||
minHeight = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float maxHeight;
|
||||
public float MaxHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return maxHeight;
|
||||
}
|
||||
set
|
||||
{
|
||||
maxHeight = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Apply(ref GSpawnFilterArgs args)
|
||||
{
|
||||
float h = 0;
|
||||
if (Space == Space.World)
|
||||
{
|
||||
h = args.Position.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = args.Terrain.transform.InverseTransformPoint(args.Position).y;
|
||||
}
|
||||
|
||||
args.ShouldExclude = h < MinHeight || h > MaxHeight;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
Space = Space.Self;
|
||||
MinHeight = 0;
|
||||
MaxHeight = 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6de8c0af7acc3d41be2ecaa8426ccab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,49 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[GDisplayName("Randomize Rotation")]
|
||||
public class GRotationRandomizeFilter : GSpawnFilter
|
||||
{
|
||||
[SerializeField]
|
||||
private float minAngle;
|
||||
public float MinAngle
|
||||
{
|
||||
get
|
||||
{
|
||||
return minAngle;
|
||||
}
|
||||
set
|
||||
{
|
||||
minAngle = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float maxAngle;
|
||||
public float MaxAngle
|
||||
{
|
||||
get
|
||||
{
|
||||
return maxAngle;
|
||||
}
|
||||
set
|
||||
{
|
||||
maxAngle = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Apply(ref GSpawnFilterArgs args)
|
||||
{
|
||||
args.Rotation = Quaternion.Euler(0, Random.Range(MinAngle, MaxAngle), 0);
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
MinAngle = 0;
|
||||
MaxAngle = 360;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c0a5e377418a3741979fd128755604b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,53 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[GDisplayName("Clamp Scale")]
|
||||
public class GScaleClampFilter : GSpawnFilter
|
||||
{
|
||||
[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 override void Apply(ref GSpawnFilterArgs args)
|
||||
{
|
||||
Vector3 scale = new Vector3(
|
||||
Mathf.Clamp(args.Scale.x, MinScale.x, MaxScale.x),
|
||||
Mathf.Clamp(args.Scale.y, MinScale.y, MaxScale.y),
|
||||
Mathf.Clamp(args.Scale.z, MinScale.z, MaxScale.z));
|
||||
args.Scale = scale;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
MinScale = new Vector3(0.5f, 0.5f, 0.5f);
|
||||
MaxScale = new Vector3(2f, 2f, 2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04289f35afcf6a644ab7f395bbb08b50
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,50 @@
|
||||
#if GRIFFIN
|
||||
using UnityEngine;
|
||||
|
||||
namespace Pinwheel.Griffin.PaintTool
|
||||
{
|
||||
[GDisplayName("Randomize Scale")]
|
||||
public class GScaleRandomizeFilter : GSpawnFilter
|
||||
{
|
||||
[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 override void Apply(ref GSpawnFilterArgs args)
|
||||
{
|
||||
Vector3 scale = Vector3.Lerp(MinScale, MaxScale, Random.value);
|
||||
args.Scale = scale;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
MinScale = new Vector3(0.7f, 0.8f, 0.7f);
|
||||
MaxScale = new Vector3(1.2f, 1.5f, 1.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user