544 lines
21 KiB
C#
544 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 MicroSplatTextureClusters : FeatureDescriptor
|
|
{
|
|
const string sDefine = "__MICROSPLAT_TEXTURECLUSTERS__";
|
|
static MicroSplatTextureClusters()
|
|
{
|
|
MicroSplatDefines.InitDefine(sDefine);
|
|
}
|
|
[PostProcessSceneAttribute (0)]
|
|
public static void OnPostprocessScene()
|
|
{
|
|
MicroSplatDefines.InitDefine(sDefine);
|
|
}
|
|
public override string ModuleName()
|
|
{
|
|
return "Texture Clusters";
|
|
}
|
|
|
|
public override string GetHelpPath ()
|
|
{
|
|
return "https://docs.google.com/document/d/1Yrx8-2yE5BUDLlnRKE_4sVCkPV68KJZ-Ez4XLhvef0Y/edit?usp=sharing";
|
|
}
|
|
|
|
public enum DefineFeature
|
|
{
|
|
_TEXTURECLUSTER2,
|
|
_TEXTURECLUSTER3,
|
|
_PERTEXCLUSTERCONTRAST,
|
|
_PERTEXCLUSTERBOOST,
|
|
_TEXTURECLUSTERTRIPLANARNOISE,
|
|
_TEXTURECLUSTERNOISE2,
|
|
_STOCHASTIC,
|
|
_PERTEXSTOCHASTIC,
|
|
kNumFeatures,
|
|
}
|
|
|
|
public enum ClusterMode
|
|
{
|
|
None,
|
|
TwoVariants,
|
|
ThreeVariants,
|
|
Stochastic
|
|
}
|
|
|
|
public enum ClusterNoiseUV
|
|
{
|
|
UV,
|
|
Triplanar
|
|
}
|
|
|
|
public ClusterMode clusterMode = ClusterMode.None;
|
|
public ClusterNoiseUV clusterNoiseUV = ClusterNoiseUV.UV;
|
|
public bool perTexClusterContrast;
|
|
public bool perTexClusterBoost;
|
|
public bool perTexStochastic;
|
|
public bool secondNoise;
|
|
|
|
public TextAsset properties;
|
|
public TextAsset functions;
|
|
public TextAsset stochasticFunctions;
|
|
public TextAsset cbuffer;
|
|
public TextAsset stochasticCBuffer;
|
|
public TextAsset stochasticShared;
|
|
public TextAsset stochasticProperties;
|
|
|
|
GUIContent CShaderClusters = new GUIContent("Texture Cluster Mode", "Number of parallel arrays to sample for clustering, or use Stochastic sampler");
|
|
GUIContent CClusterNoiseUVs = new GUIContent("Cluster Noise UV Mode", "The noise for clusetrs can be triplanar, which can be useful when UVs are not continuous");
|
|
GUIContent CClusterNoise2 = new GUIContent("Use secondary cluster noise", "On very large worlds, cluster noise tile may be visible. You can use a second noise, combined with the first, to prevent this");
|
|
// 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 void DrawFeatureGUI(MicroSplatKeywords keywords)
|
|
{
|
|
clusterMode = (ClusterMode)EditorGUILayout.EnumPopup(CShaderClusters, clusterMode);
|
|
if (clusterMode != ClusterMode.None && clusterMode != ClusterMode.Stochastic)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
clusterNoiseUV = (ClusterNoiseUV)EditorGUILayout.EnumPopup(CClusterNoiseUVs, clusterNoiseUV);
|
|
secondNoise = EditorGUILayout.Toggle(CClusterNoise2, secondNoise);
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
}
|
|
|
|
public override int CompileSortOrder()
|
|
{
|
|
return -100; // first, so we can redefine sampling macros..
|
|
}
|
|
|
|
static GUIContent CAlbedoTex2 = new GUIContent("Albedo2", "Second Albedo array");
|
|
static GUIContent CNormalTex2 = new GUIContent("Normal2", "Second Normal array");
|
|
static GUIContent CAlbedoTex3 = new GUIContent("Albedo3", "Third Albedo array");
|
|
static GUIContent CNormalTex3 = new GUIContent("Normal3", "Third Normal array");
|
|
static GUIContent CNoiseTex = new GUIContent("Cluster Noise", "Cluster Noise texture, with weights for each texture in RGB");
|
|
static GUIContent CInterpContrast = new GUIContent("Cluster Contrast", "Interpolation contrast for texture clusters");
|
|
static GUIContent CClusterScale = new GUIContent("Scale Variation", "Variation in scale of cluster layers");
|
|
static GUIContent CClusterBoost = new GUIContent("Noise Boost", "Increase or reduce the amount of blending between textures in the cluster");
|
|
static GUIContent CEmis2 = new GUIContent("Emissive2", "Second Emissive Array");
|
|
static GUIContent CEmis3 = new GUIContent("Emissive3", "Third Emissive Array");
|
|
|
|
static GUIContent CSmoothAO2 = new GUIContent("Smoothness/AO2", "Second smoothness/ao array");
|
|
static GUIContent CSmoothAO3 = new GUIContent("Smoothness/AO3", "Third smoothness/ao array");
|
|
|
|
public override void DrawShaderGUI(MicroSplatShaderGUI shaderGUI, MicroSplatKeywords keywords, Material mat, MaterialEditor materialEditor, MaterialProperty[] props)
|
|
{
|
|
if (clusterMode != ClusterMode.None)
|
|
{
|
|
if (MicroSplatUtilities.DrawRollup("Texture Clustering"))
|
|
{
|
|
if (clusterMode == ClusterMode.Stochastic)
|
|
{
|
|
if (mat.HasProperty("_StochasticContrast"))
|
|
{
|
|
materialEditor.RangeProperty(shaderGUI.FindProp("_StochasticContrast", props), "Blend Contrast");
|
|
}
|
|
if (mat.HasProperty("_StochasticScale"))
|
|
{
|
|
materialEditor.RangeProperty(shaderGUI.FindProp("_StochasticScale", props), "Noise Scale");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mat.HasProperty("_ClusterNoise"))
|
|
{
|
|
var noiseMap = shaderGUI.FindProp("_ClusterNoise", props);
|
|
var albedoMap = shaderGUI.FindProp("_ClusterDiffuse2", props);
|
|
var normalMap = shaderGUI.FindProp("_ClusterNormal2", props);
|
|
var noiseParams = shaderGUI.FindProp("_ClusterParams", props);
|
|
|
|
|
|
materialEditor.TexturePropertySingleLine(CAlbedoTex2, albedoMap);
|
|
materialEditor.TexturePropertySingleLine(CNormalTex2, normalMap);
|
|
|
|
if (mat.HasProperty("_ClusterSmoothAO2"))
|
|
{
|
|
var smoothAO = shaderGUI.FindProp("_ClusterSmoothAO2", props);
|
|
materialEditor.TexturePropertySingleLine(CSmoothAO2, smoothAO);
|
|
}
|
|
|
|
if (mat.HasProperty("_ClusterEmissiveMetal2"))
|
|
{
|
|
var emis2 = shaderGUI.FindProp("_ClusterEmissiveMetal2", props);
|
|
materialEditor.TexturePropertySingleLine(CEmis2, emis2);
|
|
}
|
|
|
|
|
|
|
|
if (clusterMode == ClusterMode.ThreeVariants)
|
|
{
|
|
var albedoMap3 = shaderGUI.FindProp("_ClusterDiffuse3", props);
|
|
var normalMap3 = shaderGUI.FindProp("_ClusterNormal3", props);
|
|
|
|
materialEditor.TexturePropertySingleLine(CAlbedoTex3, albedoMap3);
|
|
materialEditor.TexturePropertySingleLine(CNormalTex3, normalMap3);
|
|
|
|
if (mat.HasProperty("_ClusterSmoothAO3"))
|
|
{
|
|
var smoothAO = shaderGUI.FindProp("_ClusterSmoothAO3", props);
|
|
materialEditor.TexturePropertySingleLine(CSmoothAO3, smoothAO);
|
|
}
|
|
|
|
|
|
if (mat.HasProperty("_ClusterEmissiveMetal3"))
|
|
{
|
|
var emis3 = shaderGUI.FindProp("_ClusterEmissiveMetal3", props);
|
|
materialEditor.TexturePropertySingleLine(CEmis3, emis3);
|
|
}
|
|
}
|
|
|
|
materialEditor.TexturePropertySingleLine(CNoiseTex, noiseMap);
|
|
MicroSplatUtilities.EnforceDefaultTexture(noiseMap, "microsplat_def_clusternoise");
|
|
if (secondNoise && mat.HasProperty("_ClusterNoise2"))
|
|
{
|
|
var noiseMap2 = shaderGUI.FindProp("_ClusterNoise2", props);
|
|
materialEditor.TexturePropertySingleLine(CNoiseTex, noiseMap2);
|
|
MicroSplatUtilities.EnforceDefaultTexture(noiseMap, "microsplat_def_clusternoise");
|
|
}
|
|
|
|
bool enabled = GUI.enabled;
|
|
if (perTexClusterContrast)
|
|
{
|
|
GUI.enabled = false;
|
|
}
|
|
var contrastProp = shaderGUI.FindProp("_ClusterContrast", props);
|
|
contrastProp.floatValue = EditorGUILayout.Slider(CInterpContrast, contrastProp.floatValue, 1.0f, 0.0001f);
|
|
if (perTexClusterContrast)
|
|
{
|
|
GUI.enabled = enabled;
|
|
}
|
|
|
|
if (perTexClusterBoost)
|
|
{
|
|
GUI.enabled = false;
|
|
}
|
|
var boostProp = shaderGUI.FindProp("_ClusterBoost", props);
|
|
boostProp.floatValue = EditorGUILayout.Slider(CClusterBoost, boostProp.floatValue, 0.5f, 4.0f);
|
|
if (perTexClusterBoost)
|
|
{
|
|
GUI.enabled = enabled;
|
|
}
|
|
|
|
|
|
var skew = shaderGUI.FindProp("_ClusterScaleVar", props);
|
|
skew.floatValue = EditorGUILayout.Slider(CClusterScale, skew.floatValue, 0.0f, 0.2f);
|
|
|
|
|
|
{
|
|
Vector4 vec = noiseParams.vectorValue;
|
|
EditorGUI.BeginChangeCheck();
|
|
Vector2 scale = new Vector2(vec.x, vec.y);
|
|
Vector2 offset = new Vector2(vec.z, vec.w);
|
|
|
|
scale = EditorGUILayout.Vector2Field("Scale", scale);
|
|
offset = EditorGUILayout.Vector2Field("Offset", offset);
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
vec.x = scale.x;
|
|
vec.y = scale.y;
|
|
vec.z = offset.x;
|
|
vec.w = offset.y;
|
|
noiseParams.vectorValue = vec;
|
|
}
|
|
}
|
|
if (mat.HasProperty("_ClusterParams2"))
|
|
{
|
|
EditorGUILayout.LabelField("Second Octave Noise");
|
|
var noiseParams2 = shaderGUI.FindProp("_ClusterParams2", props);
|
|
Vector4 vec = noiseParams2.vectorValue;
|
|
EditorGUI.BeginChangeCheck();
|
|
Vector2 scale = new Vector2(vec.x, vec.y);
|
|
Vector2 offset = new Vector2(vec.z, vec.w);
|
|
|
|
scale = EditorGUILayout.Vector2Field("Scale", scale);
|
|
offset = EditorGUILayout.Vector2Field("Offset", offset);
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
vec.x = scale.x;
|
|
vec.y = scale.y;
|
|
vec.z = offset.x;
|
|
vec.w = offset.y;
|
|
noiseParams2.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_clusters.txt"))
|
|
{
|
|
properties = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_func_clusters.txt"))
|
|
{
|
|
functions = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_cbuffer_clusters.txt"))
|
|
{
|
|
cbuffer = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_func_stochastic.txt"))
|
|
{
|
|
stochasticFunctions = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_cbuffer_stochastic.txt"))
|
|
{
|
|
stochasticCBuffer = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_properties_stochastic.txt"))
|
|
{
|
|
stochasticProperties = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
if (p.EndsWith("microsplat_func_stochastic_shared.txt"))
|
|
{
|
|
stochasticShared = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteProperties(string[] features, System.Text.StringBuilder sb)
|
|
{
|
|
if (clusterMode != ClusterMode.None)
|
|
{
|
|
if (clusterMode != ClusterMode.Stochastic)
|
|
{
|
|
|
|
sb.AppendLine(properties.text);
|
|
if (clusterMode == ClusterMode.ThreeVariants)
|
|
{
|
|
sb.AppendLine("[NoScaleOffset]_ClusterDiffuse3 (\"Diffuse Array\", 2DArray) = \"white\" {}");
|
|
sb.AppendLine("[NoScaleOffset]_ClusterNormal3 (\"Normal Array\", 2DArray) = \"bump\" {}");
|
|
}
|
|
if (features.Contains("_USEEMISSIVEMETAL"))
|
|
{
|
|
sb.AppendLine("[NoScaleOffset]_ClusterEmissiveMetal2 (\"Emissive Array\", 2DArray) = \"black\" {}");
|
|
if (clusterMode == ClusterMode.ThreeVariants)
|
|
{
|
|
sb.AppendLine("[NoScaleOffset]_ClusterEmissiveMetal3 (\"Emissive Array\", 2DArray) = \"black\" {}");
|
|
}
|
|
}
|
|
if (features.Contains("_PACKINGHQ"))
|
|
{
|
|
sb.AppendLine(" [NoScaleOffset]_ClusterSmoothAO2 (\"Smooth AO Array\", 2DArray) = \"black\" {}");
|
|
if (clusterMode == ClusterMode.ThreeVariants)
|
|
{
|
|
sb.AppendLine(" [NoScaleOffset]_ClusterSmoothAO3 (\"Smooth AO Array\", 2DArray) = \"black\" {}");
|
|
}
|
|
}
|
|
if (secondNoise)
|
|
{
|
|
sb.AppendLine("_ClusterNoise2(\"Cluster Noise2\", 2D) = \"white\" { }");
|
|
sb.AppendLine("_ClusterParams2(\"Cluster Params\", Vector) = (3, 3, 0, 0)");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine(stochasticProperties.text);
|
|
if (features.Contains("_USEEMISSIVEMETAL"))
|
|
{
|
|
sb.AppendLine("[NoScaleOffset]_EmissiveMetalInv (\"Emissive Array\", 2DArray) = \"black\" {}");
|
|
}
|
|
if (features.Contains("_PACKINGHQ"))
|
|
{
|
|
sb.AppendLine(" [NoScaleOffset]_ClusterSmoothAOInv (\"Smooth AO Array\", 2DArray) = \"black\" {}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void ComputeSampleCounts(string[] features, ref int arraySampleCount, ref int textureSampleCount, ref int maxSamples, ref int tessellationSamples, ref int depTexReadLevel)
|
|
{
|
|
if (clusterMode == ClusterMode.TwoVariants)
|
|
{
|
|
arraySampleCount *= 2;
|
|
}
|
|
else if (clusterMode == ClusterMode.ThreeVariants)
|
|
{
|
|
arraySampleCount *= 3;
|
|
}
|
|
else if (clusterMode == ClusterMode.Stochastic)
|
|
{
|
|
arraySampleCount *= 3;
|
|
}
|
|
if (clusterMode != ClusterMode.None)
|
|
{
|
|
textureSampleCount++;
|
|
if (secondNoise)
|
|
{
|
|
textureSampleCount++;
|
|
}
|
|
if (clusterNoiseUV == ClusterNoiseUV.Triplanar)
|
|
{
|
|
textureSampleCount += 2;
|
|
if (secondNoise)
|
|
textureSampleCount += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override string[] Pack()
|
|
{
|
|
List<string> features = new List<string>();
|
|
if (clusterMode == ClusterMode.TwoVariants)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._TEXTURECLUSTER2));
|
|
}
|
|
else if (clusterMode == ClusterMode.ThreeVariants)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._TEXTURECLUSTER3));
|
|
}
|
|
else if (clusterMode == ClusterMode.Stochastic)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._STOCHASTIC));
|
|
if (perTexStochastic)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXSTOCHASTIC));
|
|
}
|
|
}
|
|
|
|
if (clusterNoiseUV == ClusterNoiseUV.Triplanar)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._TEXTURECLUSTERTRIPLANARNOISE));
|
|
}
|
|
|
|
if (perTexClusterContrast)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXCLUSTERCONTRAST));
|
|
}
|
|
if (perTexClusterBoost)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._PERTEXCLUSTERBOOST));
|
|
}
|
|
if (secondNoise)
|
|
{
|
|
features.Add(GetFeatureName(DefineFeature._TEXTURECLUSTERNOISE2));
|
|
}
|
|
return features.ToArray();
|
|
}
|
|
|
|
public override void WriteSharedFunctions(string[] features, StringBuilder sb)
|
|
{
|
|
// include shared code every time in case a module needs it. It will get stripped if not used.
|
|
sb.AppendLine(stochasticShared.text);
|
|
}
|
|
|
|
public override void WritePerMaterialCBuffer (string[] features, StringBuilder sb)
|
|
{
|
|
if (clusterMode != ClusterMode.None)
|
|
{
|
|
if (clusterMode == ClusterMode.Stochastic)
|
|
{
|
|
sb.AppendLine(stochasticCBuffer.text);
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine(cbuffer.text);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WriteFunctions(string [] features, System.Text.StringBuilder sb)
|
|
{
|
|
if (clusterMode != ClusterMode.None)
|
|
{
|
|
if (clusterMode == ClusterMode.Stochastic)
|
|
{
|
|
sb.AppendLine(stochasticFunctions.text);
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine(functions.text);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Unpack(string[] keywords)
|
|
{
|
|
clusterMode = ClusterMode.None;
|
|
if (HasFeature(keywords, DefineFeature._TEXTURECLUSTER2))
|
|
{
|
|
clusterMode = ClusterMode.TwoVariants;
|
|
}
|
|
else if (HasFeature(keywords, DefineFeature._TEXTURECLUSTER3))
|
|
{
|
|
clusterMode = ClusterMode.ThreeVariants;
|
|
}
|
|
else if (HasFeature(keywords, DefineFeature._STOCHASTIC))
|
|
{
|
|
clusterMode = ClusterMode.Stochastic;
|
|
perTexStochastic = HasFeature(keywords, DefineFeature._PERTEXSTOCHASTIC);
|
|
}
|
|
|
|
if (clusterMode != ClusterMode.None)
|
|
{
|
|
clusterNoiseUV = HasFeature(keywords, DefineFeature._TEXTURECLUSTERTRIPLANARNOISE) ? ClusterNoiseUV.Triplanar : ClusterNoiseUV.UV;
|
|
perTexClusterContrast = HasFeature(keywords, DefineFeature._PERTEXCLUSTERCONTRAST);
|
|
perTexClusterBoost = HasFeature(keywords, DefineFeature._PERTEXCLUSTERBOOST);
|
|
secondNoise = HasFeature(keywords, DefineFeature._TEXTURECLUSTERNOISE2);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
static GUIContent CPerTexClusterContrast = new GUIContent("Cluster Contrast", "Contrast for height blending of cluster data");
|
|
static GUIContent CPerTextureClusterBoost = new GUIContent("Cluster Boost", "Contrast the noise texture used for choosing textures");
|
|
static GUIContent CPerTexStochastic = new GUIContent("Stochastic Disabled", "Allows you to disable stochastic on a specific texture (set to 1)");
|
|
|
|
public override void DrawPerTextureGUI(int index, MicroSplatKeywords keywords, Material mat, MicroSplatPropData propData)
|
|
{
|
|
if (clusterMode != ClusterMode.None && clusterMode != ClusterMode.Stochastic)
|
|
{
|
|
perTexClusterContrast = DrawPerTexFloatSlider(index, 10, GetFeatureName(DefineFeature._PERTEXCLUSTERCONTRAST),
|
|
keywords, propData, Channel.R, CPerTexClusterContrast, 1.0f, 0.01f);
|
|
|
|
perTexClusterBoost = DrawPerTexFloatSlider(index, 10, GetFeatureName(DefineFeature._PERTEXCLUSTERBOOST),
|
|
keywords, propData, Channel.G, CPerTextureClusterBoost, 0.5f, 4.0f);
|
|
}
|
|
|
|
if (clusterMode == ClusterMode.Stochastic)
|
|
{
|
|
perTexStochastic = DrawPerTexFloatSlider(index, 9, GetFeatureName(DefineFeature._PERTEXSTOCHASTIC),
|
|
keywords, propData, Channel.B, CPerTexStochastic, 0.0f, 1.0f);
|
|
|
|
perTexClusterContrast = DrawPerTexFloatSlider(index, 10, GetFeatureName(DefineFeature._PERTEXCLUSTERCONTRAST),
|
|
keywords, propData, Channel.R, CPerTexClusterContrast, 0.01f, 1.0f);
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
} |