508 lines
15 KiB
C#
508 lines
15 KiB
C#
![]() |
//////////////////////////////////////////////////////
|
|||
|
// MicroSplat
|
|||
|
// Copyright (c) Jason Booth
|
|||
|
//////////////////////////////////////////////////////
|
|||
|
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
// layout
|
|||
|
// 0 perTex UV Scale and Offset
|
|||
|
// 1 PerTex Tint and interpolation contrast (a)
|
|||
|
// 2 Normal Strength, Smoothness, AO, Metallic
|
|||
|
// 3 Brightness, Contrast, porosity, foam
|
|||
|
// 4 DetailNoiseStrength, distance Noise Strength, Distance Resample, DisplaceMip
|
|||
|
// 5 geoTex, tint strength, normal strength, SmoothAOMetal strength
|
|||
|
// 6 displace, bias, offset, global emis strength
|
|||
|
// 7 Noise 0, Noise 1, Noise 2, Wind Particulate Strength
|
|||
|
// 8 Snow (R), Glitter (G), GeoHeightFilter(B), (A) GeoHeightFilterStrength
|
|||
|
// 9 Triplanar, trplanar contrast, stochastic enabled, (A) Saturation
|
|||
|
// 10 Texture Cluster Contrast, boost, Height Offset, Height Contrast
|
|||
|
// 11 Open
|
|||
|
// 12 Open
|
|||
|
// 13 Open
|
|||
|
// 14 AntiTileArray (R)Normal Str, (G) Detail Strength, (B) Distance Strength (A) DisplaceShaping
|
|||
|
// 15 Reserved for initialization marking
|
|||
|
// 16 UV Rotation, Triplanar rot, triplanar rot, (A) GlobalSpecularStrength
|
|||
|
// 17 FuzzyShading Core, Edge, Power, (A) MicroShadow
|
|||
|
// 18 SSS Tint, (A) SSS thickness
|
|||
|
// 19 (R) Curve Interpolator
|
|||
|
// 20 Trax Dig Depth, opacity, normal strength (A) Open
|
|||
|
// 21 Trax Tint (A) open
|
|||
|
// 22 Noise Height Frequency, Amplitude, NoiseUV Frequency, Amplitude
|
|||
|
// 23 ColorIntensity(R)
|
|||
|
// 24 Scatter UV Scale (RG), blendMode (B), Alpha Mult (A)
|
|||
|
// 25 Scatter Height Filter (RG), Scatter SlopeFilter (BA)
|
|||
|
// 26 Scatter Distance Fade (R), RimLight Power (G), ScatterWeight (B)
|
|||
|
// 27 Rim Light Color, intensity (A)
|
|||
|
// 28 Outline Color and intensity
|
|||
|
// 29 Slope Texture Angle (R), Contrast (G)
|
|||
|
namespace JBooth.MicroSplat
|
|||
|
{
|
|||
|
// because unity's HDR import pipeline is broke (assumes gamma, so breaks data in textures)
|
|||
|
public class MicroSplatPropData : ScriptableObject
|
|||
|
{
|
|||
|
|
|||
|
public enum PerTexVector2
|
|||
|
{
|
|||
|
SplatUVScale = 0,
|
|||
|
SplatUVOffset = 2,
|
|||
|
}
|
|||
|
|
|||
|
public enum PerTexColor
|
|||
|
{
|
|||
|
Tint = 1 * 4,
|
|||
|
SSSRTint = 18 * 4,
|
|||
|
TraxTint = 21 * 4,
|
|||
|
RimLightColor = 27*4,
|
|||
|
OutlineColor = 28*4,
|
|||
|
}
|
|||
|
|
|||
|
public enum PerTexFloat
|
|||
|
{
|
|||
|
InterpolationContrast = 1 * 4 + 1,
|
|||
|
NormalStrength = 2 * 4,
|
|||
|
Smoothness = 2 * 4 + 1,
|
|||
|
AO = 2 * 4 + 2,
|
|||
|
Metallic = 2 * 4 + 3,
|
|||
|
|
|||
|
Brightness = 3 * 4,
|
|||
|
Contrast = 3 * 4 + 1,
|
|||
|
Porosity = 3 * 4 + 2,
|
|||
|
Foam = 3 * 4 + 3,
|
|||
|
|
|||
|
DetailNoiseStrength = 4 * 4,
|
|||
|
DistanceNoiseStrength = 4 * 4 + 1,
|
|||
|
DistanceResample = 4 * 4 + 2,
|
|||
|
DisplacementMip = 4 * 4 + 3,
|
|||
|
|
|||
|
GeoTexStrength = 5 * 4,
|
|||
|
GeoTintStrength = 5 * 4 + 1,
|
|||
|
GeoNormalStrength = 5 * 4 + 2,
|
|||
|
GlobalSmoothMetalAOStength = 5 * 4 + 3,
|
|||
|
|
|||
|
DisplacementStength = 6 * 4,
|
|||
|
DisplacementBias = 6 * 4 + 1,
|
|||
|
DisplacementOffset = 6 * 4 + 2,
|
|||
|
GlobalEmisStength = 6 * 4 + 3,
|
|||
|
|
|||
|
NoiseNormal0Strength = 7 * 4,
|
|||
|
NoiseNormal1Strength = 7 * 4 + 1,
|
|||
|
NoiseNormal2Strength = 7 * 4 + 2,
|
|||
|
WindParticulateStrength = 7 * 4 + 3,
|
|||
|
|
|||
|
SnowAmount = 8 * 4,
|
|||
|
GlitterAmount = 8 * 4 + 1,
|
|||
|
GeoHeightFilter = 8 * 4 + 2,
|
|||
|
GeoHeightFilterStrength = 8 * 4 + 3,
|
|||
|
|
|||
|
TriplanarMode = 9 * 4,
|
|||
|
TriplanarContrast = 9 * 4 + 1,
|
|||
|
StochatsicEnabled = 9 * 4 + 2,
|
|||
|
Saturation = 9 * 4 + 3,
|
|||
|
|
|||
|
TextureClusterContrast = 10 * 4,
|
|||
|
TextureClusterBoost = 10 * 4 + 1,
|
|||
|
HeightOffset = 10 * 4 + 2,
|
|||
|
HeightContrast = 10 * 4 + 3,
|
|||
|
|
|||
|
AntiTileArrayNormalStrength = 14 * 4,
|
|||
|
AntiTileArrayDetailStrength = 14 * 4 + 1,
|
|||
|
AntiTileArrayDistanceStrength = 14 * 4 + 2,
|
|||
|
DisplaceShaping = 14 * 4 + 3,
|
|||
|
|
|||
|
UVRotation = 16 * 4,
|
|||
|
TriplanarRotationX = 16 * 4 + 1,
|
|||
|
TriplanarRotationY = 16 * 4 + 2,
|
|||
|
|
|||
|
FuzzyShadingCore = 17 * 4,
|
|||
|
FuzzyShadingEdge = 17 * 4 + 1,
|
|||
|
FuzzyShadingPower = 17 * 4 + 2,
|
|||
|
|
|||
|
SSSThickness = 18 * 4 + 3,
|
|||
|
CurveInterpolator = 19 * 4,
|
|||
|
TraxDigDepth = 20 * 4,
|
|||
|
TraxOpacity = 20 * 4 + 1,
|
|||
|
TraxNormalStrength = 20 * 4 + 2,
|
|||
|
|
|||
|
NoiseHeightFrequency = 22 * 4,
|
|||
|
NoiseHeightAmplitude = 22 * 4 + 1,
|
|||
|
NoiseUVFrequency = 22 * 4 + 2,
|
|||
|
NoiseUVAmplitude = 22 * 4 + 3,
|
|||
|
|
|||
|
ColorIntensity = 23 * 4,
|
|||
|
ScatterBlendMode = 24 * 4 + 2,
|
|||
|
ScatterAlphaMult = 24 * 4 + 3,
|
|||
|
ScatterDistanceFade = 26 * 4,
|
|||
|
RimPower = 26 * 4 + 1,
|
|||
|
RimIntensity = 27 * 4 + 3,
|
|||
|
OutlineIntensity = 28 * 4 + 3,
|
|||
|
SlopeTextureAngle = 29 * 4,
|
|||
|
SlopeTextureContrast = 29 * 4 + 1,
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
public const int sMaxAttributes = 32;
|
|||
|
[HideInInspector]
|
|||
|
public Color[] values = new Color[32 * sMaxAttributes];
|
|||
|
|
|||
|
[HideInInspector]
|
|||
|
public Texture2D propTex;
|
|||
|
|
|||
|
[HideInInspector]
|
|||
|
public AnimationCurve geoCurve = AnimationCurve.Linear(0, 0.0f, 0, 0.0f);
|
|||
|
[HideInInspector]
|
|||
|
public Texture2D geoTex;
|
|||
|
|
|||
|
[HideInInspector]
|
|||
|
public AnimationCurve geoSlopeFilter = AnimationCurve.Linear(0, 0.2f, 0.4f, 1.0f);
|
|||
|
[HideInInspector]
|
|||
|
public Texture2D geoSlopeTex;
|
|||
|
|
|||
|
[HideInInspector]
|
|||
|
public AnimationCurve globalSlopeFilter = AnimationCurve.Linear(0, 0.2f, 0.4f, 1.0f);
|
|||
|
[HideInInspector]
|
|||
|
public Texture2D globalSlopeTex;
|
|||
|
|
|||
|
void ClearPropTex()
|
|||
|
{
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
|
|||
|
Object[] objs = UnityEditor.AssetDatabase.LoadAllAssetRepresentationsAtPath(UnityEditor.AssetDatabase.GetAssetPath(this));
|
|||
|
for (int i = 0; i < objs.Length; ++i)
|
|||
|
{
|
|||
|
if (objs[i] != null && objs[i].name == "PropTex")
|
|||
|
{
|
|||
|
DestroyImmediate(objs[i], true);
|
|||
|
}
|
|||
|
}
|
|||
|
propTex = null;
|
|||
|
#else
|
|||
|
if (propTex != null)
|
|||
|
{
|
|||
|
DestroyImmediate(propTex);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
[HideInInspector]
|
|||
|
public int maxTextures = 32; // can be set to 256 or 32
|
|||
|
|
|||
|
public void RevisionData()
|
|||
|
{
|
|||
|
Debug.Assert(maxTextures == 32 || maxTextures == 256);
|
|||
|
// revision from 16 to 32 max textures
|
|||
|
if (values.Length == (16 * 16))
|
|||
|
{
|
|||
|
ClearPropTex();
|
|||
|
Color[] c = new Color[maxTextures * sMaxAttributes];
|
|||
|
for (int x = 0; x < 16; ++x)
|
|||
|
{
|
|||
|
for (int y = 0; y < 16; ++y)
|
|||
|
{
|
|||
|
c[y * maxTextures + x] = values[y * sMaxAttributes + x];
|
|||
|
}
|
|||
|
}
|
|||
|
values = c;
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(this);
|
|||
|
#endif
|
|||
|
}
|
|||
|
else if (values.Length == (32 * 16))
|
|||
|
{
|
|||
|
ClearPropTex();
|
|||
|
Color[] c = new Color[maxTextures * sMaxAttributes];
|
|||
|
for (int x = 0; x < 32; ++x)
|
|||
|
{
|
|||
|
for (int y = 0; y < 16; ++y)
|
|||
|
{
|
|||
|
c[y * maxTextures + x] = values[y * sMaxAttributes + x];
|
|||
|
}
|
|||
|
}
|
|||
|
values = c;
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(this);
|
|||
|
#endif
|
|||
|
}
|
|||
|
// handle switch from mega -> regular
|
|||
|
else if (values.Length == 32 * 256 && maxTextures == 32)
|
|||
|
{
|
|||
|
ClearPropTex();
|
|||
|
Color[] c = new Color[maxTextures * sMaxAttributes];
|
|||
|
for (int x = 0; x < 32; ++x)
|
|||
|
{
|
|||
|
for (int y = 0; y < 32; ++y)
|
|||
|
{
|
|||
|
c[y * maxTextures + x] = values[y * sMaxAttributes + x];
|
|||
|
}
|
|||
|
}
|
|||
|
values = c;
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(this);
|
|||
|
#endif
|
|||
|
}
|
|||
|
// switch from regular -> mega
|
|||
|
else if (values.Length == 32 * 32 && maxTextures == 256)
|
|||
|
{
|
|||
|
ClearPropTex();
|
|||
|
Color [] c = new Color [maxTextures * sMaxAttributes];
|
|||
|
for (int x = 0; x < 32; ++x)
|
|||
|
{
|
|||
|
for (int y = 0; y < 32; ++y)
|
|||
|
{
|
|||
|
c [y * maxTextures + x] = values [y * sMaxAttributes + x];
|
|||
|
}
|
|||
|
}
|
|||
|
// copy first pixel into remaining.
|
|||
|
for (int x = 32; x < 256; ++x)
|
|||
|
{
|
|||
|
for (int y = 0; y < 32; ++y)
|
|||
|
{
|
|||
|
c[y * maxTextures + x] = values[y * sMaxAttributes];
|
|||
|
}
|
|||
|
}
|
|||
|
values = c;
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty (this);
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public Color GetValue(int x, int y)
|
|||
|
{
|
|||
|
RevisionData();
|
|||
|
return values[y * maxTextures + x];
|
|||
|
}
|
|||
|
|
|||
|
public void SetValue(int x, int y, Color c)
|
|||
|
{
|
|||
|
RevisionData();
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.Undo.RecordObject(this, "Changed Value");
|
|||
|
#endif
|
|||
|
|
|||
|
values[y * maxTextures + x] = c;
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(this);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
public void SetValue(int x, int y, int channel, float value)
|
|||
|
{
|
|||
|
RevisionData();
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.Undo.RecordObject(this, "Changed Value");
|
|||
|
#endif
|
|||
|
int index = y * maxTextures + x;
|
|||
|
Color c = values[index];
|
|||
|
c[channel] = value;
|
|||
|
values[index] = c;
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(this);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
public void SetValue(int x, int y, int channel, Vector2 value)
|
|||
|
{
|
|||
|
RevisionData();
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.Undo.RecordObject(this, "Changed Value");
|
|||
|
#endif
|
|||
|
int index = y * maxTextures + x;
|
|||
|
Color c = values[index];
|
|||
|
if (channel == 0)
|
|||
|
{
|
|||
|
c.r = value.x;
|
|||
|
c.g = value.y;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
c.b = value.x;
|
|||
|
c.a = value.y;
|
|||
|
}
|
|||
|
|
|||
|
values[index] = c;
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(this);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
public void SetValue(int textureIndex, PerTexFloat channel, float value)
|
|||
|
{
|
|||
|
float e = ((float)channel) / 4.0f;
|
|||
|
int x = (int)e;
|
|||
|
int y = Mathf.RoundToInt((e - x) * 4);
|
|||
|
|
|||
|
SetValue(textureIndex, x, y, value);
|
|||
|
}
|
|||
|
|
|||
|
public void SetValue(int textureIndex, PerTexColor channel, Color value)
|
|||
|
{
|
|||
|
float e = ((float)channel) / 4.0f;
|
|||
|
int x = (int)e;
|
|||
|
|
|||
|
SetValue(textureIndex, x, value);
|
|||
|
}
|
|||
|
|
|||
|
public void SetValue(int textureIndex, PerTexVector2 channel, Vector2 value)
|
|||
|
{
|
|||
|
float e = ((float)channel) / 4.0f;
|
|||
|
int x = (int)e;
|
|||
|
int y = Mathf.RoundToInt((e - x) * 4);
|
|||
|
|
|||
|
SetValue(textureIndex, x, y, value);
|
|||
|
}
|
|||
|
|
|||
|
public Color[] GetAllValues(int textureIndex)
|
|||
|
{
|
|||
|
RevisionData();
|
|||
|
Color[] c = new Color[sMaxAttributes];
|
|||
|
for (int i = 0; i < sMaxAttributes; ++i)
|
|||
|
{
|
|||
|
c[i] = GetValue(textureIndex, i);
|
|||
|
}
|
|||
|
return c;
|
|||
|
}
|
|||
|
|
|||
|
public void SetAllValues( int textureIndex, Color[] c)
|
|||
|
{
|
|||
|
RevisionData();
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.Undo.RecordObject(this, "Changed Value");
|
|||
|
#endif
|
|||
|
for (int i = 0; i < c.Length; ++i)
|
|||
|
{
|
|||
|
SetValue(textureIndex, i, c[i]);
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(this);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
public Texture2D GetTexture()
|
|||
|
{
|
|||
|
RevisionData();
|
|||
|
|
|||
|
if (propTex == null)
|
|||
|
{
|
|||
|
if (SystemInfo.SupportsTextureFormat(TextureFormat.RGBAFloat))
|
|||
|
{
|
|||
|
propTex = new Texture2D(maxTextures, sMaxAttributes, TextureFormat.RGBAFloat, false, true);
|
|||
|
}
|
|||
|
else if (SystemInfo.SupportsTextureFormat(TextureFormat.RGBAHalf))
|
|||
|
{
|
|||
|
propTex = new Texture2D(maxTextures, sMaxAttributes, TextureFormat.RGBAHalf, false, true);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Debug.LogError("Could not create RGBAFloat or RGBAHalf format textures, per texture properties will be clamped to 0-1 range, which will break things");
|
|||
|
propTex = new Texture2D(maxTextures, sMaxAttributes, TextureFormat.RGBA32, false, true);
|
|||
|
}
|
|||
|
//tex.hideFlags = HideFlags.HideAndDontSave;
|
|||
|
propTex.wrapMode = TextureWrapMode.Clamp;
|
|||
|
propTex.filterMode = FilterMode.Point;
|
|||
|
propTex.hideFlags = HideFlags.None;
|
|||
|
#if UNITY_EDITOR
|
|||
|
propTex.name = "PropTex";
|
|||
|
UnityEditor.AssetDatabase.AddObjectToAsset(propTex, this);
|
|||
|
UnityEditor.AssetDatabase.ImportAsset(UnityEditor.AssetDatabase.GetAssetPath(propTex));
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
propTex.SetPixels(values);
|
|||
|
propTex.Apply();
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(propTex);
|
|||
|
#endif
|
|||
|
|
|||
|
return propTex;
|
|||
|
}
|
|||
|
|
|||
|
public Texture2D GetGeoCurve()
|
|||
|
{
|
|||
|
if (geoTex == null)
|
|||
|
{
|
|||
|
geoTex = new Texture2D(256, 1, TextureFormat.RHalf, false, true);
|
|||
|
#if UNITY_EDITOR
|
|||
|
geoTex.name = "geoTex";
|
|||
|
UnityEditor.AssetDatabase.AddObjectToAsset(geoTex, this);
|
|||
|
UnityEditor.AssetDatabase.ImportAsset(UnityEditor.AssetDatabase.GetAssetPath(geoTex));
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
for (int i = 0; i < 256; ++i)
|
|||
|
{
|
|||
|
float v = geoCurve.Evaluate((float)i / 255.0f);
|
|||
|
geoTex.SetPixel(i, 0, new Color(v, v, v, v));
|
|||
|
}
|
|||
|
geoTex.Apply();
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(geoTex);
|
|||
|
#endif
|
|||
|
|
|||
|
return geoTex;
|
|||
|
}
|
|||
|
|
|||
|
public Texture2D GetGeoSlopeFilter()
|
|||
|
{
|
|||
|
if (geoSlopeTex == null)
|
|||
|
{
|
|||
|
geoSlopeTex = new Texture2D(256, 1, TextureFormat.Alpha8, false, true);
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
geoSlopeTex.name = "geoSlopeTex";
|
|||
|
UnityEditor.AssetDatabase.AddObjectToAsset(geoSlopeTex, this);
|
|||
|
UnityEditor.AssetDatabase.ImportAsset(UnityEditor.AssetDatabase.GetAssetPath(geoSlopeTex));
|
|||
|
#endif
|
|||
|
}
|
|||
|
for (int i = 0; i < 256; ++i)
|
|||
|
{
|
|||
|
float v = geoSlopeFilter.Evaluate((float)i / 255.0f);
|
|||
|
geoSlopeTex.SetPixel(i, 0, new Color(v, v, v, v));
|
|||
|
}
|
|||
|
geoSlopeTex.Apply();
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(geoSlopeTex);
|
|||
|
#endif
|
|||
|
return geoSlopeTex;
|
|||
|
}
|
|||
|
|
|||
|
public Texture2D GetGlobalSlopeFilter()
|
|||
|
{
|
|||
|
if (globalSlopeTex == null)
|
|||
|
{
|
|||
|
globalSlopeTex = new Texture2D(256, 1, TextureFormat.Alpha8, false, true);
|
|||
|
#if UNITY_EDITOR
|
|||
|
globalSlopeTex.name = "globalSlopeTex";
|
|||
|
UnityEditor.AssetDatabase.AddObjectToAsset(globalSlopeTex, this);
|
|||
|
UnityEditor.AssetDatabase.ImportAsset(UnityEditor.AssetDatabase.GetAssetPath(globalSlopeTex));
|
|||
|
#endif
|
|||
|
}
|
|||
|
for (int i = 0; i < 256; ++i)
|
|||
|
{
|
|||
|
float v = globalSlopeFilter.Evaluate((float)i / 255.0f);
|
|||
|
globalSlopeTex.SetPixel(i, 0, new Color(v, v, v, v));
|
|||
|
}
|
|||
|
globalSlopeTex.Apply();
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
UnityEditor.EditorUtility.SetDirty(globalSlopeTex);
|
|||
|
#endif
|
|||
|
|
|||
|
return globalSlopeTex;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|