443 lines
17 KiB
C#
443 lines
17 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
|
|
namespace DigitalOpus.MB.Core
|
|
{
|
|
// Only works for Standard and Specular material types, blends basic properties: tint, metallic, smoothness, specular color, emmisive color
|
|
public class TextureBlenderHDRPLit : TextureBlender
|
|
{
|
|
|
|
private enum Prop
|
|
{
|
|
doColor,
|
|
doMask,
|
|
doSpecular,
|
|
doEmission,
|
|
doNone,
|
|
}
|
|
|
|
// TODO add support for other material types besides standard and specular
|
|
private enum MaterialType
|
|
{
|
|
unknown,
|
|
subsurfaceScattering,
|
|
standard,
|
|
anisotropy,
|
|
iridescence,
|
|
specularColor,
|
|
translucent,
|
|
}
|
|
|
|
// This is used to cache the non texture property values. If all non-texutre property values are the same for a property for all source textures
|
|
// then the source value will be re-used
|
|
TextureBlenderMaterialPropertyCacheHelper sourceMaterialPropertyCache = new TextureBlenderMaterialPropertyCacheHelper();
|
|
|
|
MaterialType m_materialType = MaterialType.unknown;
|
|
|
|
// These are cached values read in OnBeforeTintTexture and used when blending pixels.
|
|
Color m_tintColor;
|
|
bool m_hasMaskMap;
|
|
float m_smoothness; // Used if no mask map
|
|
float m_metallic; // Used if no mask map
|
|
bool m_hasSpecMap;
|
|
Color m_specularColor;
|
|
Color m_emissiveColor;
|
|
|
|
// This just makes things more efficient so we arn't doing a string comparison for each pixel.
|
|
Prop propertyToDo = Prop.doNone;
|
|
|
|
// These are the property values that will be assigned to the result material if
|
|
// generating an atlas for those properties.
|
|
Color m_generatingTintedAtlaColor = Color.white;
|
|
Color m_generatingTintedAtlaSpecular = Color.white;
|
|
Color m_generatingTintedAtlaEmission = Color.white;
|
|
|
|
// These are the default property values that will be assigned to the result materials if
|
|
// none of the source materials have a value for these properties.
|
|
Color m_notGeneratingAtlasDefaultColor = Color.white;
|
|
float m_notGeneratingAtlasDefaultMetallic = 0;
|
|
float m_notGeneratingAtlasDefaultSmoothness = 0.5f;
|
|
Color m_notGeneratingAtlasDefaultSpecular = Color.white;
|
|
Color m_notGeneratingAtlasDefaultEmissiveColor = Color.black;
|
|
|
|
public bool DoesShaderNameMatch(string shaderName)
|
|
{
|
|
return shaderName.Equals("HDRP/Lit");
|
|
}
|
|
|
|
private MaterialType _MapFloatToMaterialType(float materialType)
|
|
{
|
|
if (materialType == 0f)
|
|
{
|
|
return MaterialType.subsurfaceScattering;
|
|
}
|
|
if (materialType == 1f)
|
|
{
|
|
return MaterialType.standard;
|
|
}
|
|
if (materialType == 2f)
|
|
{
|
|
return MaterialType.anisotropy;
|
|
}
|
|
if (materialType == 3f)
|
|
{
|
|
return MaterialType.iridescence;
|
|
}
|
|
if (materialType == 4f)
|
|
{
|
|
return MaterialType.specularColor;
|
|
}
|
|
if (materialType == 5f)
|
|
{
|
|
return MaterialType.translucent;
|
|
}
|
|
else
|
|
{
|
|
return MaterialType.unknown;
|
|
}
|
|
}
|
|
|
|
private float _MapMaterialTypeToFloat(MaterialType materialType)
|
|
{
|
|
if (materialType == MaterialType.subsurfaceScattering)
|
|
{
|
|
return 0f;
|
|
}
|
|
if (materialType == MaterialType.standard)
|
|
{
|
|
return 1f;
|
|
}
|
|
if (materialType == MaterialType.anisotropy)
|
|
{
|
|
return 2f;
|
|
}
|
|
if (materialType == MaterialType.iridescence)
|
|
{
|
|
return 3f;
|
|
}
|
|
if (materialType == MaterialType.specularColor)
|
|
{
|
|
return 4f;
|
|
}
|
|
if (materialType == MaterialType.translucent)
|
|
{
|
|
return 5f;
|
|
}
|
|
else
|
|
{
|
|
return -1f;
|
|
}
|
|
}
|
|
|
|
public void OnBeforeTintTexture(Material sourceMat, string shaderTexturePropertyName)
|
|
{
|
|
if (m_materialType == MaterialType.unknown)
|
|
{
|
|
if (sourceMat.HasProperty("_MaterialID"))
|
|
{
|
|
m_materialType = _MapFloatToMaterialType(sourceMat.GetFloat("_MaterialID"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (sourceMat.HasProperty("_MaterialID") && _MapFloatToMaterialType(sourceMat.GetFloat("_MaterialID")) != m_materialType)
|
|
{
|
|
Debug.LogError("Using the High Definition Render Pipeline TextureBlender to blend non-texture-properties. Some of the source materials use different 'MaterialType'. These " +
|
|
" cannot be blended properly. Results will be unpredictable.");
|
|
}
|
|
}
|
|
|
|
if (shaderTexturePropertyName.Equals("_BaseColorMap"))
|
|
{
|
|
propertyToDo = Prop.doColor;
|
|
if (sourceMat.HasProperty("_BaseColor"))
|
|
{
|
|
m_tintColor = sourceMat.GetColor("_BaseColor");
|
|
}
|
|
else
|
|
{
|
|
m_tintColor = m_notGeneratingAtlasDefaultColor;
|
|
}
|
|
}
|
|
else if (shaderTexturePropertyName.Equals("_MaskMap"))
|
|
{
|
|
propertyToDo = Prop.doMask;
|
|
if (sourceMat.HasProperty("_MaskMap") && sourceMat.GetTexture("_MaskMap") != null)
|
|
{
|
|
m_hasMaskMap = true;
|
|
}
|
|
else
|
|
{
|
|
m_hasMaskMap = false;
|
|
|
|
// No maskmap means sliders
|
|
if (m_materialType == MaterialType.standard && sourceMat.HasProperty("_Metallic"))
|
|
{
|
|
m_metallic = sourceMat.GetFloat("_Metallic");
|
|
}
|
|
else
|
|
{
|
|
m_metallic = m_notGeneratingAtlasDefaultMetallic;
|
|
}
|
|
|
|
if (sourceMat.HasProperty("_Smoothness"))
|
|
{
|
|
m_smoothness = sourceMat.GetFloat("_Smoothness");
|
|
}
|
|
else
|
|
{
|
|
m_smoothness = m_notGeneratingAtlasDefaultSmoothness;
|
|
}
|
|
}
|
|
}
|
|
else if (shaderTexturePropertyName.Equals("_SpecularColorMap") && m_materialType == MaterialType.specularColor)
|
|
{
|
|
propertyToDo = Prop.doSpecular;
|
|
if (sourceMat.HasProperty("_SpecularColorMap") && sourceMat.GetTexture("_SpecularColorMap") != null)
|
|
{
|
|
m_hasSpecMap = true;
|
|
}
|
|
else
|
|
{
|
|
m_hasSpecMap = false;
|
|
}
|
|
if (sourceMat.HasProperty("_SpecularColor"))
|
|
{
|
|
m_specularColor = sourceMat.GetColor("_SpecularColor");
|
|
}
|
|
}
|
|
else if (shaderTexturePropertyName.Equals("_EmissiveColorMap"))
|
|
{
|
|
// Does not handle LDR Emissive colors
|
|
propertyToDo = Prop.doEmission;
|
|
if (sourceMat.HasProperty("_EmissiveColor")) {
|
|
m_emissiveColor = sourceMat.GetColor("_EmissiveColor");
|
|
} else
|
|
{
|
|
m_emissiveColor = m_notGeneratingAtlasDefaultEmissiveColor;
|
|
}
|
|
} else
|
|
{
|
|
propertyToDo = Prop.doNone;
|
|
}
|
|
}
|
|
|
|
public Color OnBlendTexturePixel(string propertyToDoshaderPropertyName, Color pixelColor)
|
|
{
|
|
if (propertyToDo == Prop.doColor)
|
|
{
|
|
return new Color(pixelColor.r * m_tintColor.r, pixelColor.g * m_tintColor.g, pixelColor.b * m_tintColor.b, pixelColor.a * m_tintColor.a);
|
|
}
|
|
else if (propertyToDo == Prop.doMask)
|
|
{
|
|
|
|
if (m_hasMaskMap)
|
|
{
|
|
return new Color(pixelColor.r * m_metallic, pixelColor.g, pixelColor.b, pixelColor.a * m_smoothness);
|
|
}
|
|
else
|
|
{
|
|
return new Color(m_metallic, 0, 0, m_smoothness);
|
|
}
|
|
}
|
|
else if (propertyToDo == Prop.doSpecular)
|
|
{
|
|
if (m_hasSpecMap)
|
|
{
|
|
return new Color(pixelColor.r * m_specularColor.r, pixelColor.g * m_specularColor.g, pixelColor.b * m_specularColor.g, pixelColor.a * m_specularColor.a);
|
|
}
|
|
else
|
|
{
|
|
return m_specularColor;
|
|
}
|
|
}
|
|
else if (propertyToDo == Prop.doEmission)
|
|
{
|
|
return new Color(pixelColor.r * m_emissiveColor.r, pixelColor.g * m_emissiveColor.g, pixelColor.b * m_emissiveColor.b, pixelColor.a * m_emissiveColor.a);
|
|
}
|
|
return pixelColor;
|
|
}
|
|
|
|
public bool NonTexturePropertiesAreEqual(Material a, Material b)
|
|
{
|
|
if (!TextureBlenderFallback._compareColor(a, b, m_generatingTintedAtlaColor, "_BaseColor"))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool aHasMaskMapTex = a.HasProperty("_MaskMap") && a.GetTexture("_MaskMap") != null;
|
|
bool bHasMaskMapTex = b.HasProperty("_MaskMap") && b.GetTexture("_MaskMap") != null;
|
|
|
|
if (!aHasMaskMapTex && !bHasMaskMapTex)
|
|
{
|
|
if (!TextureBlenderFallback._compareFloat(a, b, m_notGeneratingAtlasDefaultMetallic, "_Metallic") &&
|
|
!TextureBlenderFallback._compareFloat(a, b, m_notGeneratingAtlasDefaultSmoothness, "_Smoothness"))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (m_materialType == MaterialType.specularColor)
|
|
{
|
|
if (!TextureBlenderFallback._compareColor(a, b, m_notGeneratingAtlasDefaultSpecular, "_SpecularColor"))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!TextureBlenderFallback._compareColor(a, b, m_notGeneratingAtlasDefaultEmissiveColor, "_EmissiveColor"))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void SetNonTexturePropertyValuesOnResultMaterial(Material resultMaterial)
|
|
{
|
|
if (m_materialType != MaterialType.unknown)
|
|
{
|
|
resultMaterial.SetFloat("_MaterialID", _MapMaterialTypeToFloat(m_materialType));
|
|
}
|
|
|
|
if (resultMaterial.GetTexture("_BaseColorMap") != null)
|
|
{
|
|
resultMaterial.SetColor("_BaseColor", m_generatingTintedAtlaColor);
|
|
}
|
|
else
|
|
{
|
|
resultMaterial.SetColor("_BaseColor", (Color)sourceMaterialPropertyCache.GetValueIfAllSourceAreTheSameOrDefault("_BaseColor", m_notGeneratingAtlasDefaultColor));
|
|
}
|
|
|
|
if (resultMaterial.GetTexture("_MaskMap") != null)
|
|
{
|
|
// MaskMap atlas has been generated, no metallic and smoothness property
|
|
}
|
|
else
|
|
{
|
|
resultMaterial.SetFloat("_Metallic", (float)sourceMaterialPropertyCache.GetValueIfAllSourceAreTheSameOrDefault("_Metallic", m_notGeneratingAtlasDefaultMetallic));
|
|
resultMaterial.SetFloat("_Smoothness", m_notGeneratingAtlasDefaultSmoothness);
|
|
}
|
|
|
|
if (m_materialType == MaterialType.specularColor)
|
|
{
|
|
if (resultMaterial.GetTexture("_SpecularColorMap") != null)
|
|
{
|
|
resultMaterial.SetColor("_SpecularColor", m_generatingTintedAtlaSpecular);
|
|
// Easier to set the Ambient Occlusion remap than to try to change the mask map after the fact, otherwise spec colors with no textures display improperly
|
|
resultMaterial.SetFloat("_AORemapMin", 1);
|
|
}
|
|
else
|
|
{
|
|
resultMaterial.SetColor("_SpecularColor", (Color)sourceMaterialPropertyCache.GetValueIfAllSourceAreTheSameOrDefault("_SpecularColor", m_notGeneratingAtlasDefaultSpecular));
|
|
resultMaterial.SetFloat("_AORemapMin", 1);
|
|
}
|
|
}
|
|
|
|
if (resultMaterial.GetTexture("_EmissiveColorMap") != null)
|
|
{
|
|
resultMaterial.SetColor("_EmissiveColor", m_generatingTintedAtlaEmission);
|
|
}
|
|
else
|
|
{
|
|
resultMaterial.SetColor("_EmissiveColor", (Color)sourceMaterialPropertyCache.GetValueIfAllSourceAreTheSameOrDefault("_EmissiveColor", m_notGeneratingAtlasDefaultEmissiveColor));
|
|
}
|
|
}
|
|
|
|
|
|
public Color GetColorIfNoTexture(Material mat, ShaderTextureProperty texPropertyName)
|
|
{
|
|
if (texPropertyName.name.Equals("_BaseColorMap"))
|
|
{
|
|
if (mat != null && mat.HasProperty("_BaseColor"))
|
|
{
|
|
/*
|
|
try
|
|
{ //need try because can't garantee _Color is a color
|
|
Color c = mat.GetColor("_BaseColor");
|
|
sourceMaterialPropertyCache.CacheMaterialProperty(mat, "_BaseColor", c);
|
|
}
|
|
catch (Exception) { }
|
|
*/
|
|
// Why don't we return _BaseColor here?
|
|
// Source object has: no-texture, _BaseColor ==> look like _BaseColor
|
|
// Atlas needs:
|
|
// CORRECT: whiteBlock, _BaseColor ==> look like _BaseColor
|
|
// WRONG: solidTex_Color, _BaseColor ==> look like _Color * _BaseColor
|
|
return m_notGeneratingAtlasDefaultColor;
|
|
}
|
|
}
|
|
else if (texPropertyName.name.Equals("_Metallic"))
|
|
{
|
|
if (mat != null && mat.HasProperty("_Metallic"))
|
|
{
|
|
try
|
|
{ //need try because can't garantee _Metallic is a float
|
|
float v = mat.GetFloat("_Metallic");
|
|
sourceMaterialPropertyCache.CacheMaterialProperty(mat, "_Metallic", v);
|
|
}
|
|
catch (Exception) { }
|
|
return new Color(0f, 0f, 0f, m_notGeneratingAtlasDefaultSmoothness);
|
|
}
|
|
else
|
|
{
|
|
return new Color(0f, 0f, 0f, m_notGeneratingAtlasDefaultSmoothness);
|
|
}
|
|
}
|
|
else if (texPropertyName.name.Equals("_Smoothness"))
|
|
{
|
|
if (mat != null && mat.HasProperty("_Smoothness"))
|
|
{
|
|
try
|
|
{ // need try because can't guarantee _Smoothness is a float
|
|
float a = mat.GetFloat("_Smoothness");
|
|
sourceMaterialPropertyCache.CacheMaterialProperty(mat, "_Smoothness", a);
|
|
}
|
|
catch (Exception) { }
|
|
return new Color(0f, 0f, 0f, m_notGeneratingAtlasDefaultSmoothness);
|
|
}
|
|
else
|
|
{
|
|
return new Color(0f, 0f, 0f, m_notGeneratingAtlasDefaultSmoothness);
|
|
}
|
|
}
|
|
else if (texPropertyName.name.Equals("_SpecularColorMap"))
|
|
{
|
|
if (mat != null && mat.HasProperty("_SpecularColor"))
|
|
{
|
|
try
|
|
{ // need try because can't garantee _SpecularColor is a color
|
|
Color c = mat.GetColor("_SpecularColor");
|
|
sourceMaterialPropertyCache.CacheMaterialProperty(mat, "_SpecularColor", c);
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
return m_notGeneratingAtlasDefaultSpecular;
|
|
}
|
|
else if (texPropertyName.name.Equals("_EmissiveColorMap"))
|
|
{
|
|
if (mat != null)
|
|
{
|
|
if (mat.HasProperty("_EmissiveColor"))
|
|
{
|
|
try
|
|
{ // need try because can't garantee _EmissiveColor is a color
|
|
Color c = mat.GetColor("_EmissiveColor");
|
|
sourceMaterialPropertyCache.CacheMaterialProperty(mat, "_EmissiveColor", c);
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
else
|
|
{
|
|
return m_notGeneratingAtlasDefaultEmissiveColor;
|
|
}
|
|
}
|
|
}
|
|
return new Color(1f, 1f, 1f, 0f);
|
|
}
|
|
|
|
}
|
|
}
|