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; } } }