using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BrainFailProductions.PolyFew.AsImpL
{
///
/// Utility class for model import
///
public class ModelUtil
{
///
/// Blend mode for Unity Material
///
public enum MtlBlendMode { OPAQUE, CUTOUT, FADE, TRANSPARENT }
///
/// Set up a Material for the given mode.
///
/// Here is replicated what is done when choosing a blend mode from Inspector.
/// material to be changed
/// mode to be set
public static void SetupMaterialWithBlendMode(Material mtl, MtlBlendMode mode)
{
switch (mode)
{
case MtlBlendMode.OPAQUE:
mtl.SetOverrideTag("RenderType", "Opaque");
mtl.SetFloat("_Mode", 0);
mtl.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
mtl.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
mtl.SetInt("_ZWrite", 1);
mtl.DisableKeyword("_ALPHATEST_ON");
mtl.DisableKeyword("_ALPHABLEND_ON");
mtl.DisableKeyword("_ALPHAPREMULTIPLY_ON");
mtl.renderQueue = -1;
break;
case MtlBlendMode.CUTOUT:
mtl.SetOverrideTag("RenderType", "TransparentCutout");
mtl.SetFloat("_Mode", 1);
mtl.SetFloat("_Mode", 1);
mtl.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
mtl.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
mtl.SetInt("_ZWrite", 1);
mtl.EnableKeyword("_ALPHATEST_ON");
mtl.DisableKeyword("_ALPHABLEND_ON");
mtl.DisableKeyword("_ALPHAPREMULTIPLY_ON");
mtl.renderQueue = 2450;
break;
case MtlBlendMode.FADE:
mtl.SetOverrideTag("RenderType", "Transparent");
mtl.SetFloat("_Mode", 2);
mtl.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
mtl.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
mtl.SetInt("_ZWrite", 0);
mtl.DisableKeyword("_ALPHATEST_ON");
mtl.EnableKeyword("_ALPHABLEND_ON");
mtl.DisableKeyword("_ALPHAPREMULTIPLY_ON");
mtl.renderQueue = 3000;
break;
case MtlBlendMode.TRANSPARENT:
mtl.SetOverrideTag("RenderType", "Transparent");
mtl.SetFloat("_Mode", 3);
mtl.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
mtl.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
mtl.SetInt("_ZWrite", 0);
mtl.DisableKeyword("_ALPHATEST_ON");
mtl.DisableKeyword("_ALPHABLEND_ON");
mtl.EnableKeyword("_ALPHAPREMULTIPLY_ON");
mtl.renderQueue = 3000;
break;
}
}
///
/// Scan a texture looking for transparent pixels and trying to guess the correct blend mode needed.
///
/// input rexture (it must be set to readable)
/// blend mode set to FADE or CUTOUT if transparent pixels are found.
/// Return true if transparent pixels were found.
public static bool ScanTransparentPixels(Texture2D texture, ref MtlBlendMode mode)
{
bool texCanBeTransparent = texture != null
&& (texture.format == TextureFormat.ARGB32
|| texture.format == TextureFormat.RGBA32
|| texture.format == TextureFormat.DXT5
|| texture.format == TextureFormat.ARGB4444
|| texture.format == TextureFormat.BGRA32
// Only for DirectX support
#if UNITY_STANDALONE_WIN
|| texture.format == TextureFormat.DXT5Crunched
#endif
//|| texture.format == ... (all alpha formats)
);
if (texCanBeTransparent)
{
bool stop = false;
int pixelScanFrequency = 1;
for (int x = 0; x < texture.width && !stop; x += pixelScanFrequency)
{
for (int y = 0; y < texture.height && !stop; y += pixelScanFrequency)
{
float a = texture.GetPixel(x, y).a;
DetectMtlBlendFadeOrCutout(a, ref mode, ref stop);
if (stop)
{
return mode == MtlBlendMode.FADE || mode == MtlBlendMode.CUTOUT;
}
}
}
}
return mode == MtlBlendMode.FADE || mode == MtlBlendMode.CUTOUT;
}
///
/// Detect if the blend mode must be set to FADE or CUTOUT
/// according to the given alpha value and the current value of mode.
///
/// input alpha value
/// blend mode set to FADE or CUTOUT
/// flag set to true if the mode is finally detected (it can be used to break from a scan loop)
public static void DetectMtlBlendFadeOrCutout(float alpha, ref MtlBlendMode mode, ref bool noDoubt)
{
if (noDoubt)
{
return;
}
if (alpha < 1.0f)
{
//mode = MtlBlendMode.TRANSPARENT;
if (alpha == 0.0f)
{
// assume there is a "cutout texture"
mode = MtlBlendMode.CUTOUT;
} // else 0
/// Convert a bump map to a normal map
///
/// input bump map
/// optionally adjust the bump effect with the normal map
/// The new normal map
public static Texture2D HeightToNormalMap(Texture2D bumpMap, float amount = 1f)
{
int h = bumpMap.height;
int w = bumpMap.width;
float changeNeg, changePos;
float /*h0,*/ h1, h2, h3/*, h4*/;
Texture2D normalMap = new Texture2D(w, h, TextureFormat.ARGB32, true);
Color col = Color.black;
for (int y = 0; y < bumpMap.height; y++)
{
for (int x = 0; x < bumpMap.width; x++)
{
Vector3 n = Vector3.zero;
// CHANGE IN X
//h0 = height_map.GetPixel( WrapInt(x-2, w),y).grayscale;
h1 = bumpMap.GetPixel(WrapInt(x - 1, w), y).grayscale;
h2 = bumpMap.GetPixel(x, y).grayscale;
h3 = bumpMap.GetPixel(WrapInt(x + 1, w), y).grayscale;
//h4 = height_map.GetPixel(WrapInt(x+2, w) , y).grayscale;
//changeNeg = 0.7f*(h1 - h0)+0.2f*(h2 - h1);
//changePos = 0.2f*(h3 - h2)+0.7f*(h4 - h3);
changeNeg = h2 - h1;
changePos = h3 - h2;
n.x = -(changePos + changeNeg) / 255.0f;
// CHANGE IN Y
//h0 = height_map.GetPixel(x, WrapInt(y-2, h)).grayscale;
h1 = bumpMap.GetPixel(x, WrapInt(y - 1, h)).grayscale;
h2 = bumpMap.GetPixel(x, y).grayscale;
h3 = bumpMap.GetPixel(x, WrapInt(y + 1, h)).grayscale;
//h4 = height_map.GetPixel(x, WrapInt(y+2, h).grayscale);
//changeNeg = 0.7f*(h1 - h0)+0.2f*(h2 - h1);
//changePos = 0.2f*(h3 - h2)+0.7f*(h4 - h3);
changeNeg = h2 - h1;
changePos = h3 - h2;
n.y = -(changePos + changeNeg);
// SCALE OF BUMPINESS
if (amount != 1.0f) n *= amount;
/// Get depth component
n.z = Mathf.Sqrt(1.0f - (n.x * n.x + n.y * n.y));
// Scale in (0..0.5);
n *= 0.5f;
// set the pixel
col.r = Mathf.Clamp01(n.x + 0.5f);
col.g = Mathf.Clamp01(n.y + 0.5f);
col.b = Mathf.Clamp01(n.z + 0.5f);
col.a = col.r;
normalMap.SetPixel(x, y, col);
}
}
normalMap.Apply();
return normalMap;
}
///
/// Wrap the given value pos inside the range (0..boundary).
///
/// input value
/// range boundary
/// the wrapped value
private static int WrapInt(int pos, int boundary)
{
if (pos < 0)
pos = boundary + pos;
else if (pos >= boundary)
pos -= boundary;
return pos;
}
}
}