551 lines
21 KiB
C#
551 lines
21 KiB
C#
//////////////////////////////////////////////////////
|
|
// MicroSplat
|
|
// Copyright (c) Jason Booth
|
|
//////////////////////////////////////////////////////
|
|
|
|
|
|
using UnityEngine;
|
|
using System.Collections;
|
|
using UnityEditor;
|
|
using UnityEditor.Callbacks;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace JBooth.MicroSplat
|
|
{
|
|
#if __MICROSPLAT__
|
|
[InitializeOnLoad]
|
|
public class MicroSplatTessellation : FeatureDescriptor
|
|
{
|
|
const string sGlobalTess = "__MICROSPLAT_TESSELLATION__";
|
|
static MicroSplatTessellation()
|
|
{
|
|
MicroSplatDefines.InitDefine(sGlobalTess);
|
|
}
|
|
[PostProcessSceneAttribute (0)]
|
|
public static void OnPostprocessScene()
|
|
{
|
|
MicroSplatDefines.InitDefine(sGlobalTess);
|
|
}
|
|
public override string ModuleName()
|
|
{
|
|
return "Tessellation & Parallax";
|
|
}
|
|
|
|
public override string GetHelpPath ()
|
|
{
|
|
return "https://docs.google.com/document/d/1F94JgR2y8zyaxJLVQ4K77tXzRGwfeLJyyX5kgD_BoTU/edit?usp=sharing";
|
|
}
|
|
|
|
public enum DefineFeature
|
|
{
|
|
_TESSDISTANCE,
|
|
_PERTEXTESSDISPLACE,
|
|
_PERTEXTESSUPBIAS,
|
|
_PERTEXTESSOFFSET,
|
|
_PERTEXTESSMIPLEVEL,
|
|
_PERTEXTESSSHAPING,
|
|
_PARALLAX,
|
|
_POM,
|
|
_PERTEXPARALLAX,
|
|
_TESSFADEHOLES,
|
|
_TESSONLYDISPLACE,
|
|
kNumFeatures,
|
|
}
|
|
|
|
public enum ParallaxMode
|
|
{
|
|
None = 0,
|
|
Offset,
|
|
POM
|
|
}
|
|
|
|
public enum DisplacementMode
|
|
{
|
|
None = 0,
|
|
OnlyDisplacement,
|
|
Tessellation
|
|
}
|
|
|
|
public bool isTessellated = false;
|
|
public bool isDisplaced = false;
|
|
public DisplacementMode displacementMode = DisplacementMode.None;
|
|
public bool perTexDisplace;
|
|
public bool perTexUpBias;
|
|
public bool perTexOffset;
|
|
public ParallaxMode parallax = ParallaxMode.None;
|
|
public bool perTexParallax;
|
|
public bool perTexShaping;
|
|
public bool perTexMipLevel;
|
|
public bool fadeNearHoles;
|
|
|
|
public TextAsset properties_tess;
|
|
public TextAsset func_tess;
|
|
public TextAsset func_parallax;
|
|
public TextAsset func_pom;
|
|
|
|
public TextAsset cbuffer_tess;
|
|
public TextAsset cbuffer_parallax;
|
|
public TextAsset cbuffer_pom;
|
|
|
|
GUIContent CShaderDisplacementOptions = new GUIContent("Displacement Mode", "Displace Original or Tessellated vertices?");
|
|
|
|
GUIContent CTessUpBias = new GUIContent("Up Bias", "How much to bias displacement along the normal, or up");
|
|
GUIContent CTessDisplacement = new GUIContent("Displacement", "How far to displace the surface from it's original position");
|
|
GUIContent CTessMipBias = new GUIContent("Mip Bias", "Allows you to use lower mip map levels for displacement, which often produces a better looking result and is slightly faster");
|
|
GUIContent CTessShaping = new GUIContent("Shaping", "A seperate contrast blend for tessellation, lower values tend to look best");
|
|
GUIContent CTessMinDistance = new GUIContent("Min Distance", "Distance in which distance based tessellation is at maximum. Also acts as the distance in which tessellation amount begins to fade when fade tessellation is on");
|
|
GUIContent CTessMaxDistance = new GUIContent("Max Distance", "Distance in which distance based tessellation is at minimum. Also acts as the distance in which tessellation amount begins is completely faded when fade tessellation is on");
|
|
GUIContent CTessTessellation = new GUIContent("Tessellation", "How much to tesselate the mesh at min distance, lower values are more performant");
|
|
GUIContent CParallax = new GUIContent("Parallax", "Parallax mapping, which does an extra height map lookup to create a deeper looking texture effect. Offset requires one extra sample, POM uses many but creates a better effect");
|
|
|
|
// Can we template these somehow?
|
|
static Dictionary<DefineFeature, string> sFeatureNames = new Dictionary<DefineFeature, string>();
|
|
public static string GetFeatureName(DefineFeature feature)
|
|
{
|
|
string ret;
|
|
if (sFeatureNames.TryGetValue(feature, out ret))
|
|
{
|
|
return ret;
|
|
}
|
|
string fn = System.Enum.GetName(typeof(DefineFeature), feature);
|
|
sFeatureNames[feature] = fn;
|
|
return fn;
|
|
}
|
|
|
|
public static bool HasFeature(string[] keywords, DefineFeature feature)
|
|
{
|
|
string f = GetFeatureName(feature);
|
|
for (int i = 0; i < keywords.Length; ++i)
|
|
{
|
|
if (keywords[i] == f)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
public override string GetVersion()
|
|
{
|
|
return "3.9";
|
|
}
|
|
|
|
public override bool RequiresShaderModel46()
|
|
{
|
|
return isTessellated;
|
|
}
|
|
|
|
public override int CompileSortOrder()
|
|
{
|
|
return 1; // after most stuff, so variables, etc, can all be declared..
|
|
}
|
|
|
|
public override void DrawFeatureGUI(MicroSplatKeywords keywords)
|
|
{
|
|
if (!keywords.IsKeywordEnabled ("_MICROVERTEXMESH"))
|
|
{
|
|
displacementMode = (DisplacementMode)EditorGUILayout.EnumPopup(CShaderDisplacementOptions, displacementMode);
|
|
switch(displacementMode)
|
|
{
|
|
case DisplacementMode.None:
|
|
isTessellated = isDisplaced = false;
|
|
break;
|
|
case DisplacementMode.OnlyDisplacement:
|
|
isTessellated = false; isDisplaced = true; break;
|
|
case DisplacementMode.Tessellation:
|
|
isTessellated = true; isDisplaced = false; break;
|
|
}
|
|
fadeNearHoles = EditorGUILayout.Toggle(new GUIContent("Fade Near Holes", "Fades tessellation around terrain holes"), fadeNearHoles);
|
|
}
|
|
parallax = (ParallaxMode)EditorGUILayout.EnumPopup(CParallax, parallax);
|
|
}
|
|
|
|
public override void DrawShaderGUI(MicroSplatShaderGUI shaderGUI, MicroSplatKeywords keywords, Material mat, MaterialEditor materialEditor, MaterialProperty[] props)
|
|
{
|
|
if ((isTessellated || isDisplaced) && mat.HasProperty("_TessData1") && MicroSplatUtilities.DrawRollup("Tessellation"))
|
|
{
|
|
var td1 = shaderGUI.FindProp("_TessData1", props);
|
|
var td2 = shaderGUI.FindProp("_TessData2", props);
|
|
EditorGUI.BeginChangeCheck();
|
|
var td1v = td1.vectorValue;
|
|
var td2v = td2.vectorValue;
|
|
td1v.y = EditorGUILayout.Slider(CTessDisplacement, td1v.y, 0, 3);
|
|
td1v.z = (float)EditorGUILayout.IntSlider(CTessMipBias, (int)td1v.z, 0, 6);
|
|
td2v.z = 1.0f - (float)EditorGUILayout.Slider(CTessShaping, 1.0f - td2v.z, 0.0f, 0.999f);
|
|
if (!perTexUpBias)
|
|
{
|
|
td2v.w = (float)EditorGUILayout.Slider(CTessUpBias, td2v.w, 0.0f, 1);
|
|
}
|
|
|
|
if (isTessellated)
|
|
{
|
|
td1v.x = EditorGUILayout.Slider(CTessTessellation, td1v.x, 1, 32);
|
|
td2v.x = EditorGUILayout.FloatField(CTessMinDistance, td2v.x);
|
|
td2v.y = EditorGUILayout.FloatField(CTessMaxDistance, td2v.y);
|
|
}
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
td1.vectorValue = td1v;
|
|
td2.vectorValue = td2v;
|
|
}
|
|
}
|
|
if (parallax == ParallaxMode.Offset && MicroSplatUtilities.DrawRollup("Parallax") && mat.HasProperty("_ParallaxParams"))
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
var parprop = shaderGUI.FindProp("_ParallaxParams", props);
|
|
|
|
Vector4 vec = parprop.vectorValue;
|
|
vec.x = EditorGUILayout.Slider("Parallax Height", vec.x, 0.0f, 0.12f);
|
|
vec.y = EditorGUILayout.FloatField("Parallax Fade Start", vec.y);
|
|
vec.z = EditorGUILayout.FloatField("Parallax Fade Distance", vec.z);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
parprop.vectorValue = vec;
|
|
}
|
|
}
|
|
|
|
if (parallax == ParallaxMode.POM && MicroSplatUtilities.DrawRollup("POM") && mat.HasProperty("_POMParams"))
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
var parprop = shaderGUI.FindProp("_POMParams", props);
|
|
|
|
Vector4 vec = parprop.vectorValue;
|
|
vec.x = EditorGUILayout.Slider("POM Height", vec.x, 0.0f, 0.4f);
|
|
vec.y = EditorGUILayout.FloatField("POM Fade Start", vec.y);
|
|
vec.z = EditorGUILayout.FloatField("POM Fade Distance", vec.z);
|
|
vec.w = (int)EditorGUILayout.IntSlider("Steps", (int)vec.w, 2, 32);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
parprop.vectorValue = vec;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void InitCompiler(string[] paths)
|
|
{
|
|
for (int i = 0; i < paths.Length; ++i)
|
|
{
|
|
string p = paths[i];
|
|
if (p.EndsWith("microsplat_properties_tess.txt"))
|
|
{
|
|
properties_tess = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_func_tess.txt"))
|
|
{
|
|
func_tess = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_cbuffer_tess.txt"))
|
|
{
|
|
cbuffer_tess = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_func_parallax.txt"))
|
|
{
|
|
func_parallax = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_func_pom.txt"))
|
|
{
|
|
func_pom = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_cbuffer_parallax.txt"))
|
|
{
|
|
cbuffer_parallax = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_cbuffer_pom.txt"))
|
|
{
|
|
cbuffer_pom = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteProperties(string[] features, System.Text.StringBuilder sb)
|
|
{
|
|
if (isTessellated || isDisplaced)
|
|
{
|
|
sb.Append(properties_tess.text);
|
|
}
|
|
if (parallax == ParallaxMode.Offset)
|
|
{
|
|
sb.AppendLine(" _ParallaxParams(\"Parallax Height\", Vector) = (0.08, 30, 30, 0)");
|
|
}
|
|
|
|
if (parallax == ParallaxMode.POM)
|
|
{
|
|
sb.AppendLine(" _POMParams(\"POM Params\", Vector) = (0.08, 30, 30, 8)");
|
|
}
|
|
}
|
|
|
|
public override void ComputeSampleCounts(string[] features, ref int arraySampleCount, ref int textureSampleCount, ref int maxSamples, ref int tessellationSamples, ref int depTexReadLevel)
|
|
{
|
|
if (parallax == ParallaxMode.Offset)
|
|
{
|
|
arraySampleCount += 2;
|
|
if (!features.Contains<string>(MicroSplatBaseFeatures.GetFeatureName(MicroSplatBaseFeatures.DefineFeature._MAX2LAYER)))
|
|
{
|
|
arraySampleCount += 1;
|
|
}
|
|
if (!features.Contains<string>(MicroSplatBaseFeatures.GetFeatureName(MicroSplatBaseFeatures.DefineFeature._MAX3LAYER)))
|
|
{
|
|
arraySampleCount += 1;
|
|
}
|
|
}
|
|
|
|
if (parallax == ParallaxMode.POM)
|
|
{
|
|
arraySampleCount += 2 * 8; // would need to read this from the material
|
|
}
|
|
|
|
if (isTessellated)
|
|
{
|
|
if (features.Contains<string>(MicroSplatBaseFeatures.GetFeatureName(MicroSplatBaseFeatures.DefineFeature._MAX2LAYER)))
|
|
{
|
|
tessellationSamples += 2;
|
|
}
|
|
else if (features.Contains<string>(MicroSplatBaseFeatures.GetFeatureName(MicroSplatBaseFeatures.DefineFeature._MAX3LAYER)))
|
|
{
|
|
tessellationSamples += 3;
|
|
}
|
|
else
|
|
{
|
|
tessellationSamples += 4;
|
|
}
|
|
|
|
textureSampleCount += 4; // control textures
|
|
}
|
|
}
|
|
|
|
public override string[] Pack()
|
|
{
|
|
List<string> features = new List<string>();
|
|
if (isTessellated) features.Add(GetFeatureName(DefineFeature._TESSDISTANCE));
|
|
if (isDisplaced) features.Add(GetFeatureName(DefineFeature._TESSONLYDISPLACE));
|
|
if (isTessellated || isDisplaced)
|
|
{
|
|
if (perTexDisplace)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXTESSDISPLACE));
|
|
}
|
|
if (perTexUpBias)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXTESSUPBIAS));
|
|
}
|
|
if (perTexOffset)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXTESSOFFSET));
|
|
}
|
|
if (perTexMipLevel)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXTESSMIPLEVEL));
|
|
}
|
|
if (perTexShaping)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXTESSSHAPING));
|
|
}
|
|
if (fadeNearHoles)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._TESSFADEHOLES));
|
|
}
|
|
}
|
|
if (parallax != ParallaxMode.None)
|
|
{
|
|
if (parallax == ParallaxMode.Offset)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PARALLAX));
|
|
if (perTexParallax)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXPARALLAX));
|
|
}
|
|
}
|
|
if (parallax == ParallaxMode.POM)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._POM));
|
|
if (perTexParallax)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXPARALLAX));
|
|
}
|
|
}
|
|
}
|
|
|
|
return features.ToArray();
|
|
}
|
|
|
|
public override void WritePerMaterialCBuffer (string[] features, StringBuilder sb)
|
|
{
|
|
if (isTessellated || isDisplaced)
|
|
{
|
|
sb.AppendLine(cbuffer_tess.text);
|
|
}
|
|
if (parallax == ParallaxMode.Offset)
|
|
{
|
|
sb.AppendLine(cbuffer_parallax.text);
|
|
}
|
|
if (parallax == ParallaxMode.POM)
|
|
{
|
|
sb.AppendLine(cbuffer_pom.text);
|
|
}
|
|
}
|
|
|
|
public override void WriteFunctions(string [] features, System.Text.StringBuilder sb)
|
|
{
|
|
if (isTessellated || isDisplaced)
|
|
{
|
|
sb.AppendLine(func_tess.text);
|
|
}
|
|
if (parallax == ParallaxMode.Offset)
|
|
{
|
|
sb.AppendLine(func_parallax.text);
|
|
}
|
|
if (parallax == ParallaxMode.POM)
|
|
{
|
|
sb.AppendLine(func_pom.text);
|
|
}
|
|
|
|
}
|
|
public override void WriteAfterVetrexFunctions(StringBuilder sb)
|
|
{
|
|
|
|
}
|
|
|
|
public override void Unpack(string[] keywords)
|
|
{
|
|
isTessellated = (HasFeature(keywords, DefineFeature._TESSDISTANCE));
|
|
isDisplaced = (HasFeature(keywords, DefineFeature._TESSONLYDISPLACE));
|
|
displacementMode = isTessellated ? DisplacementMode.Tessellation : isDisplaced ? DisplacementMode.OnlyDisplacement : DisplacementMode.None;
|
|
perTexDisplace = (HasFeature(keywords, DefineFeature._PERTEXTESSDISPLACE));
|
|
perTexUpBias = (HasFeature(keywords, DefineFeature._PERTEXTESSUPBIAS));
|
|
perTexOffset = (HasFeature(keywords, DefineFeature._PERTEXTESSOFFSET));
|
|
perTexShaping = (HasFeature(keywords, DefineFeature._PERTEXTESSSHAPING));
|
|
perTexMipLevel = (HasFeature(keywords, DefineFeature._PERTEXTESSMIPLEVEL));
|
|
fadeNearHoles = (HasFeature(keywords, DefineFeature._TESSFADEHOLES));
|
|
if (HasFeature(keywords, DefineFeature._PARALLAX))
|
|
{
|
|
parallax = ParallaxMode.Offset;
|
|
perTexParallax = HasFeature(keywords, DefineFeature._PERTEXPARALLAX);
|
|
}
|
|
|
|
if (HasFeature(keywords, DefineFeature._POM))
|
|
{
|
|
parallax = ParallaxMode.POM;
|
|
perTexParallax = HasFeature(keywords, DefineFeature._PERTEXPARALLAX);
|
|
}
|
|
}
|
|
|
|
// for combined tessellation
|
|
public static float IdealOffset(Texture2D src, int channel)
|
|
{
|
|
RenderTexture rt = new RenderTexture(128, 128, 0, RenderTextureFormat.ARGB32);
|
|
Graphics.Blit(src, rt);
|
|
RenderTexture.active = rt;
|
|
Texture2D tex = new Texture2D(128, 128);
|
|
tex.ReadPixels(new Rect(0, 0, 128, 128), 0, 0);
|
|
tex.Apply();
|
|
RenderTexture.active = null;
|
|
rt.Release();
|
|
GameObject.DestroyImmediate(rt);
|
|
|
|
var colors = tex.GetPixels();
|
|
GameObject.DestroyImmediate(tex);
|
|
float h = 0;
|
|
for (int i = 0; i < colors.Length; ++i)
|
|
{
|
|
h += colors [i] [channel];
|
|
}
|
|
h /= (float)colors.Length;
|
|
|
|
return -h;
|
|
}
|
|
|
|
float IdealOffset(Texture2DArray ta, int index)
|
|
{
|
|
Material mat = new Material(Shader.Find("Hidden/MicroSplat/ExtractHeight"));
|
|
mat.SetInt("index", index);
|
|
RenderTexture rt = new RenderTexture(128, 128, 0, RenderTextureFormat.ARGB32);
|
|
Graphics.Blit(ta, rt, mat);
|
|
RenderTexture.active = rt;
|
|
Texture2D tex = new Texture2D(128, 128);
|
|
tex.ReadPixels(new Rect(0, 0, 128, 128), 0, 0);
|
|
tex.Apply();
|
|
RenderTexture.active = null;
|
|
rt.Release();
|
|
GameObject.DestroyImmediate(rt);
|
|
GameObject.DestroyImmediate(mat);
|
|
|
|
var colors = tex.GetPixels();
|
|
GameObject.DestroyImmediate(tex);
|
|
float h = 0;
|
|
for (int i = 0; i < colors.Length; ++i)
|
|
{
|
|
h += colors[i].a;
|
|
}
|
|
h /= (float)colors.Length;
|
|
|
|
return -h;
|
|
}
|
|
|
|
static GUIContent CPerTexDisplace = new GUIContent("Displacement", "Scale for tessellation displacement");
|
|
static GUIContent CPerTexUpBias = new GUIContent("Tess Up Bias", "Bias displacement from normal angle to up");
|
|
static GUIContent CPerTexOffset = new GUIContent("Tess Offset", "Offset displacement center, to push this texture up and down along the displacement vector");
|
|
static GUIContent CPerTexMipLevel = new GUIContent("Tess Mip Bias", "Biases mip map selection in tessellation stage");
|
|
static GUIContent CPerTexShaping = new GUIContent("Tess Shaping", "Adjusts tessellation shaping for individual texture");
|
|
static GUIContent CPerTexParallax = new GUIContent("Parallax Height", "Parallax height for given texture");
|
|
static GUIContent CComputeIdeal = new GUIContent("Compute Ideal Offset", "Compute per-texture offsets based on the texture data - the idea is to get the majority of the terrain as close to the collider as possible");
|
|
static GUIContent CComputeIdealAll = new GUIContent("Compute All", "Compute per-texture offsets for all textures based on the texture data - the idea is to get the majority of the terrain as close to the collider as possible");
|
|
|
|
|
|
|
|
public override void DrawPerTextureGUI(int index, MicroSplatKeywords keywords, Material mat, MicroSplatPropData propData)
|
|
{
|
|
if (isTessellated || isDisplaced)
|
|
{
|
|
InitPropData(6, propData, new Color(1.0f, 0.0f, 0.0f, 0.5f)); // displace, up, offset
|
|
|
|
perTexDisplace = DrawPerTexFloatSlider(index, 6, GetFeatureName(DefineFeature._PERTEXTESSDISPLACE),
|
|
keywords, propData, Channel.R, CPerTexDisplace, 0, 2);
|
|
|
|
perTexUpBias = DrawPerTexFloatSlider(index, 6, GetFeatureName(DefineFeature._PERTEXTESSUPBIAS),
|
|
keywords, propData, Channel.G, CPerTexUpBias, 0, 1);
|
|
|
|
perTexOffset = DrawPerTexFloatSlider(index, 6, GetFeatureName(DefineFeature._PERTEXTESSOFFSET),
|
|
keywords, propData, Channel.B, CPerTexOffset, -1, 1);
|
|
|
|
perTexMipLevel = DrawPerTexFloatSlider(index, 4, GetFeatureName(DefineFeature._PERTEXTESSMIPLEVEL),
|
|
keywords, propData, Channel.A, CPerTexMipLevel, 0, 6);
|
|
|
|
perTexShaping = DrawPerTexFloatSlider(index, 14, GetFeatureName(DefineFeature._PERTEXTESSSHAPING),
|
|
keywords, propData, Channel.A, CPerTexShaping, 0.001f, 0.999f);
|
|
|
|
if (perTexOffset)
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
if (GUILayout.Button(CComputeIdeal))
|
|
{
|
|
float h = IdealOffset(mat.GetTexture("_Diffuse") as Texture2DArray, index);
|
|
propData.SetValue(index, 6, (int)Channel.B, h);
|
|
AssetDatabase.Refresh();
|
|
}
|
|
if (GUILayout.Button(CComputeIdealAll))
|
|
{
|
|
var ta = mat.GetTexture("_Diffuse") as Texture2DArray;
|
|
for (int i = 0; i < 16; ++i)
|
|
{
|
|
float h = IdealOffset(ta, i);
|
|
propData.SetValue(i, 6, (int)Channel.B, h);
|
|
}
|
|
}
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
}
|
|
|
|
if (parallax == ParallaxMode.Offset || parallax == ParallaxMode.POM)
|
|
{
|
|
perTexParallax = DrawPerTexFloatSlider(index, 6, GetFeatureName(DefineFeature._PERTEXPARALLAX),
|
|
keywords, propData, Channel.A, CPerTexParallax, 0, 1);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
} |