diff --git a/Assets/Scripts/UIImageAlphaMask.cs b/Assets/Scripts/UIImageAlphaMask.cs new file mode 100644 index 0000000..6789ea0 --- /dev/null +++ b/Assets/Scripts/UIImageAlphaMask.cs @@ -0,0 +1,199 @@ +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +[ExecuteInEditMode] +[RequireComponent(typeof(Image))] +public class UIImageAlphaMask : MonoBehaviour +{ + private Image m_MaskImage; + private Canvas m_Canvas; + private RectTransform m_RectTransform; + private Image[] m_TargetImageList; + private Material m_Material; + + private Material Material + { + get + { + if (m_Material == null) + { + m_Material = new Material(Shader.Find("Hidden/UI/AlphaMask")); + } + return m_Material; + } + } + + private Image MaskImage + { + get + { + if (m_MaskImage == null) + { + m_MaskImage = GetComponent(); + } + return m_MaskImage; + } + } + + private RectTransform SelfRect + { + get + { + if (m_RectTransform == null) + { + m_RectTransform = GetComponent(); + } + return m_RectTransform; + } + } + + private Canvas RootCanvas + { + get + { + if (m_Canvas == null) + { + var canvas = GetComponentInParent(); + if (canvas != null) + { + if (canvas.rootCanvas != null) + { + m_Canvas = canvas.rootCanvas; + } + else + { + m_Canvas = canvas; + } + } + } + return m_Canvas; + } + } + + + private void SetMaterial(Image[] imageList, Material material) + { + if (imageList == null) + { + return; + } + + for (int i = 0; i < imageList.Length; i++) + { + var image = imageList[i]; + image.material = material; + } + } + + private void Update() + { + if (!IsValid()) + { + return; + } + + if (m_TargetImageList == null || m_TargetImageList.Length <= 0) + { + m_TargetImageList = GetComponentsInChildren(true); + m_TargetImageList = m_TargetImageList.Where(o => o.transform != this.transform).ToArray(); + SetMaterial(m_TargetImageList, Material); + } + + SetProperties(); + } + + private bool IsValid() + { + if (RootCanvas == null) + { + return false; + } + + if (RootCanvas.renderMode == RenderMode.ScreenSpaceOverlay) + { + return false; + } + + if (MaskImage.sprite == null) + { + return false; + } + + return true; + } + + private void SetProperties() + { + var camera = GetCamera(); + if (camera == null) + { + return; + } + + var matrix = CalculateMatrix(camera); + + Material.SetTexture("_MaskTex", MaskImage.sprite.texture); + Material.SetMatrix("_MaskMatrix", matrix); + } + + private Camera GetCamera() + { + return RootCanvas.worldCamera; + } + + private Matrix4x4 CalculateMatrix(Camera camera) + { + var rect = CalcurateViewportRect(camera); + + Matrix4x4 result = Matrix4x4.identity; + + var halfSize = rect.size * 0.5f; + result = Matrix4x4.Ortho( + rect.center.x - halfSize.x, + rect.center.x + halfSize.x, + rect.center.y - halfSize.y, + rect.center.y + halfSize.y, + camera.nearClipPlane, + camera.farClipPlane + ); + result = Matrix4x4.TRS(Vector3.one * 0.5f, Quaternion.identity, Vector3.one * 0.5f) * GL.GetGPUProjectionMatrix(result, false) * camera.worldToCameraMatrix; + return result; + } + + private Rect CalcurateViewportRect(Camera camera) + { + var corners = new Vector3[4]; + + SelfRect.GetWorldCorners(corners); + + var p1 = RectTransformUtility.WorldToScreenPoint(camera, corners[1]); + var p3 = RectTransformUtility.WorldToScreenPoint(camera, corners[3]); + + var x = p1.x - (Screen.width * 0.5f); + var y = p3.y - (Screen.height * 0.5f); + var width = p3.x - p1.x; + var height = p1.y - p3.y; + + x /= (Screen.width * 0.5f); + width /= (Screen.width * 0.5f); + y /= (Screen.height * 0.5f); + height /= (Screen.height * 0.5f); + + var size = camera.orthographicSize; + var aspect = Screen.width / (float)Screen.height; + x *= size * aspect; + width *= size * aspect; + y *= size; + height *= size; + + var rect = new Rect() + { + x = x, + width = width, + y = y, + height = height + }; + return rect; + } +} diff --git a/Assets/Scripts/UIImageAlphaMask.cs.meta b/Assets/Scripts/UIImageAlphaMask.cs.meta new file mode 100644 index 0000000..c162c46 --- /dev/null +++ b/Assets/Scripts/UIImageAlphaMask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8fd4dba1064bc642874d75100ae59fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Mobile/Mobile_High.asset b/Assets/Settings/Mobile/Mobile_High.asset index 4790f49..cb462a5 100644 --- a/Assets/Settings/Mobile/Mobile_High.asset +++ b/Assets/Settings/Mobile/Mobile_High.asset @@ -40,7 +40,7 @@ MonoBehaviour: m_MainLightShadowmapResolution: 2048 m_AdditionalLightsRenderingMode: 2 m_AdditionalLightsPerObjectLimit: 4 - m_AdditionalLightShadowsSupported: 0 + m_AdditionalLightShadowsSupported: 1 m_AdditionalLightsShadowmapResolution: 2048 m_AdditionalLightsShadowResolutionTierLow: 256 m_AdditionalLightsShadowResolutionTierMedium: 512 diff --git a/Assets/Shaders.meta b/Assets/Shaders.meta new file mode 100644 index 0000000..c44b19a --- /dev/null +++ b/Assets/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 20aee86cb7a762843aa7fd2e76903f53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Shaders/UI-AlphaMask.shader b/Assets/Shaders/UI-AlphaMask.shader new file mode 100644 index 0000000..da3ff7e --- /dev/null +++ b/Assets/Shaders/UI-AlphaMask.shader @@ -0,0 +1,119 @@ +Shader "Hidden/UI/AlphaMask" +{ + Properties + { + [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} + _Color ("Tint", Color) = (1,1,1,1) + + _StencilComp ("Stencil Comparison", Float) = 8 + _Stencil ("Stencil ID", Float) = 0 + _StencilOp ("Stencil Operation", Float) = 0 + _StencilWriteMask ("Stencil Write Mask", Float) = 255 + _StencilReadMask ("Stencil Read Mask", Float) = 255 + + _ColorMask ("Color Mask", Float) = 15 + + [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 + } + + SubShader + { + Tags + { + "Queue"="Transparent" + "IgnoreProjector"="True" + "RenderType"="Transparent" + "PreviewType"="Plane" + "CanUseSpriteAtlas"="True" + } + + Stencil + { + Ref [_Stencil] + Comp [_StencilComp] + Pass [_StencilOp] + ReadMask [_StencilReadMask] + WriteMask [_StencilWriteMask] + } + + Cull Off + Lighting Off + ZWrite Off + ZTest [unity_GUIZTestMode] + Blend SrcAlpha OneMinusSrcAlpha + ColorMask [_ColorMask] + + Pass + { + Name "Default" + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma target 2.0 + + #include "UnityCG.cginc" + #include "UnityUI.cginc" + + #pragma multi_compile __ UNITY_UI_ALPHACLIP + + struct appdata_t + { + float4 vertex : POSITION; + float4 color : COLOR; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f + { + float4 vertex : SV_POSITION; + fixed4 color : COLOR; + float2 texcoord : TEXCOORD0; + float4 worldPosition : TEXCOORD1; + float2 maskUv : TEXCOORD2; + UNITY_VERTEX_OUTPUT_STEREO + }; + + fixed4 _Color; + fixed4 _TextureSampleAdd; + float4 _ClipRect; + float4x4 _MaskMatrix; + + v2f vert(appdata_t IN) + { + v2f OUT; + UNITY_SETUP_INSTANCE_ID(IN); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); + OUT.worldPosition = IN.vertex; + + float4 wp = mul(unity_ObjectToWorld, IN.vertex); + OUT.vertex = mul(UNITY_MATRIX_VP, wp); + OUT.maskUv = mul(_MaskMatrix, wp).xy; + + OUT.texcoord = IN.texcoord; + + OUT.color = IN.color * _Color; + return OUT; + } + + sampler2D _MainTex; + sampler2D _MaskTex; + + fixed4 frag(v2f IN) : SV_Target + { + half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color; + half4 mask = tex2D(_MaskTex, IN.maskUv); + + color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect); + color.a *= mask.a; + + #ifdef UNITY_UI_ALPHACLIP + clip (color.a - 0.001); + #endif + + return color; + } + ENDCG + } + } +} diff --git a/Assets/Shaders/UI-AlphaMask.shader.meta b/Assets/Shaders/UI-AlphaMask.shader.meta new file mode 100644 index 0000000..7dfcaf9 --- /dev/null +++ b/Assets/Shaders/UI-AlphaMask.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5c547192ffda6db41ab2c9d23f79b171 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SharedAssets/Textures/Ballon01.png b/Assets/SharedAssets/Textures/Ballon01.png new file mode 100644 index 0000000..c5cb907 Binary files /dev/null and b/Assets/SharedAssets/Textures/Ballon01.png differ diff --git a/Assets/SharedAssets/Textures/Ballon01.png.meta b/Assets/SharedAssets/Textures/Ballon01.png.meta new file mode 100644 index 0000000..3d638c3 --- /dev/null +++ b/Assets/SharedAssets/Textures/Ballon01.png.meta @@ -0,0 +1,114 @@ +fileFormatVersion: 2 +guid: a3178569a950efc42a31ec01a5756b01 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SharedAssets/Textures/Mask.png b/Assets/SharedAssets/Textures/Mask.png new file mode 100644 index 0000000..81fa3e2 Binary files /dev/null and b/Assets/SharedAssets/Textures/Mask.png differ diff --git a/Assets/SharedAssets/Textures/Mask.png.meta b/Assets/SharedAssets/Textures/Mask.png.meta new file mode 100644 index 0000000..4daf34c --- /dev/null +++ b/Assets/SharedAssets/Textures/Mask.png.meta @@ -0,0 +1,114 @@ +fileFormatVersion: 2 +guid: 2c0de1bad5aed9d4fa2e54bdf034e619 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: