Alpha Mask – 用 JPG 达到 PNG 效果
发表于2017-03-19
贴图里常用的图片格式是png和jpg,但因为jpg格式因为通道不够,而有的透明图层又需要使用缺失的那个png中的A通道,为此下面就给大家介绍下使用Alpha Mask,达到用jpg也可以实现png效果的方法。
在贴图中有常见的两种格式
PNG:使用 RGBA 四个通道
JPG:使用 RGB 三个通道
当我们需要使用到透明图层时就必须使用 A 通道
而 Alpha Mask 的主要功用
就是利用了图片的 RGB 三个通道
来作为额外的遮罩图层
将原本三张 PNG 变换为四张 JPG
使 JPG 也可以达到 PNG 的效果
製作原理
读取一至三张不同的 PNG 图片
撷取各自的像素产生出对应的 R、G、B 通道后
将三个通道合併成 Alpha Mask
接著则需要利用 Shader 来使用 Alpha Mask 作为遮罩参考来源
赋予相对应的 JPG、Alpha Mask 及 Channel
如此就能够利用 JPG 来达到 PNG 的效果
製作流程
这里的范例中使用了 R、G、B 三张不同的 PNG
PS 1:范例中的 JPG 并不是自动产生的,需要另外对 PNG 做处理
PS 2:在使用工具前,必须先勾选 Texture 设定中的 Read/Write Enabled
PS 3:打包图档的长宽必须一致
1.点选 Tools/Alpha Mask Maker
2.赋予对应的贴图素材
3.点选 Create Alpha Mask 按钮,并选择储存路径产生出 Alpha Mask
4.生成 Alpha Masked 材质球并做相对应设定
Base:赋予 JPG 图片
Alpha:赋予 Alpha Mask 图片
Channel:选择使用的通道
5.完成利用JPG来达到PNG效果
工具程式码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | using UnityEngine; using UnityEditor; using System.Collections; using System.IO; public class AlphaMaskWindow : EditorWindow { private Texture2D m_textureR; private Texture2D m_textureG; private Texture2D m_textureB; private int m_arrayLength; private int m_width; private int m_height; private Texture2D m_alphaMask; [MenuItem( "Tools/Alpha Mask Maker" )] private static void OpenWindow() { EditorWindow.GetWindow ().Show (); } void OnGUI() { GUILayout.BeginVertical (); m_textureR = EditorGUILayout.ObjectField( "Reference Texture R" , m_textureR, typeof ( object ), false )asTexture2D; m_textureG = EditorGUILayout.ObjectField( "Reference Texture G" , m_textureG, typeof ( object ), false )asTexture2D; m_textureB = EditorGUILayout.ObjectField( "Reference Texture B" , m_textureB, typeof ( object ), false )asTexture2D; if (m_textureR != null || m_textureG != null || m_textureB != null ) { if (CheckSize()) DisplayButtons(); else EditorGUILayout.LabelField( "Textures should have the same size." ); } EditorGUILayout.EndVertical (); } private void DisplayButtons() { if (GUILayout.Button ( "Create Alpha Mask" )) CreateAlphaMask (); } private void CreateAlphaMask() { m_alphaMask = null ; m_arrayLength = 0; Initialize (m_textureR); Initialize (m_textureG); Initialize (m_textureB); Color[] channelR = GetChannel (m_textureR, Color.red); Color[] channelG = GetChannel (m_textureG, Color.green); Color[] channelB = GetChannel (m_textureB, Color.blue); Color[] finalColor = new Color[m_arrayLength]; for ( int cnt = 0; cnt < finalColor.Length; cnt++) { finalColor[cnt] = new Color(channelR[cnt].r, channelG[cnt].g, channelB[cnt].b); } m_alphaMask.SetPixels (0, 0, m_width, m_height, finalColor); SaveAlphaMask (); } private void Initialize(Texture2D texture) { if (m_alphaMask != null ) return ; if (texture != null ) { m_arrayLength = texture.GetPixels().Length; m_alphaMask = new Texture2D (texture.width, texture.height, TextureFormat.RGBA32, false ); } } private Color[] GetChannel(Texture2D texture, Color color) { Color[] channel = new Color[m_arrayLength]; if (texture != null ) { channel = texture.GetPixels(); for ( int cnt = 0; cnt < m_arrayLength; cnt++) { if (channel[cnt].a != 0) channel[cnt] = color; else channel[cnt] = new Color(0, 0, 0, 0); } } else { for ( int cnt = 0; cnt < m_arrayLength; cnt++) { channel[cnt] = new Color(0, 0, 0, 0); } } return channel; } private bool CheckSize() { m_width = 0; m_height = 0; SetSize (m_textureR); SetSize (m_textureG); SetSize (m_textureB); bool result = true ; result &= CheckTextureSize (m_textureR); result &= CheckTextureSize (m_textureG); result &= CheckTextureSize (m_textureB); return result; } private void SetSize(Texture2D texture) { if (texture == null ) return ; m_width = texture.width; m_height = texture.height; } private bool CheckTextureSize(Texture2D texture) { if (texture != null ) return m_width == texture.width && m_height == texture.height; else return true ; } private void SaveAlphaMask() { string path = EditorUtility.SaveFilePanelInProject ( "Save Alpha Mask" , "" , "jpg" , "Select folder and choose file name." ); byte [] bytes = m_alphaMask.EncodeToJPG(); File.WriteAllBytes(path, bytes); AssetDatabase.Refresh (); } } |
Shader 程式码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | Shader "Unlit/Transparent Colored Alpha Masked" { Properties { _MainTex ( "Base (RGB)" , 2D) = "black" {} _MaskTex ( "Alpha (RGB)" , 2D) = "white" {} _Channel ( "Channel" , Vector) = (1, 0, 0, 0) } SubShader { LOD 100 Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" } Cull Off Lighting Off ZWrite Off Fog { Mode Off } Offset -1, -1 Blend SrcAlpha OneMinusSrcAlpha Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma only_renderers opengl d3d9 gles gles3 metal #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; fixed4 color : COLOR; }; struct v2f { float4 vertex : SV_POSITION; float2 texcoord : TEXCOORD0; fixed4 color : COLOR; }; uniform sampler2D _MainTex; uniform sampler2D _MaskTex; float4 _MainTex_ST; fixed4 _Channel; v2f vert (appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); o.color = v.color; return o; } fixed4 frag (v2f i) : COLOR { fixed4 mask = tex2D(_MaskTex, i.texcoord) * _Channel; fixed alpha = mask.x + mask.y + mask.z; fixed4 col = fixed4(tex2D(_MainTex, i.texcoord).rgb * i.color.rgb, alpha * i.color.a); return col; } ENDCG } } } |