1.0.0-preview.1

# [1.0.0-preview.1](https://github.com/mob-sakai/SoftMaskForUGUI/compare/v0.10.0-preview.3...v1.0.0-preview.1) (2020-05-11)

### Bug Fixes

* Unintentional material destruction ([bf17b19](bf17b19ef2))

### change

* change namespace ([0347b04](0347b04fb7))

### Features

* support graphic connector ([3451521](34515216a3)), closes [#75](https://github.com/mob-sakai/SoftMaskForUGUI/issues/75) [#76](https://github.com/mob-sakai/SoftMaskForUGUI/issues/76) [#80](https://github.com/mob-sakai/SoftMaskForUGUI/issues/80)

### BREAKING CHANGES

* If your code contained the SoftMask API, it would fail to compile. Please change the namespace from  to .
* The name of the custom SoftMaskable shader must be changed. For more information, see the ‘Support soft masks with your custom shaders’ section of the README.
pull/87/head
semantic-release-bot 2020-05-11 07:34:22 +00:00
parent b9eb1a9b95
commit 60ce6997e0
28 changed files with 1696 additions and 1988 deletions

View File

@ -1,3 +1,26 @@
# [1.0.0-preview.1](https://github.com/mob-sakai/SoftMaskForUGUI/compare/v0.10.0-preview.3...v1.0.0-preview.1) (2020-05-11)
### Bug Fixes
* Unintentional material destruction ([bf17b19](https://github.com/mob-sakai/SoftMaskForUGUI/commit/bf17b19ef29ea35b54cbaf5473611ad58136540a))
### change
* change namespace ([0347b04](https://github.com/mob-sakai/SoftMaskForUGUI/commit/0347b04fb70d970b3558ebb454ecd2dbbd3dfce0))
### Features
* support graphic connector ([3451521](https://github.com/mob-sakai/SoftMaskForUGUI/commit/34515216a39d69601595dffbbac1803da3a27379)), closes [#75](https://github.com/mob-sakai/SoftMaskForUGUI/issues/75) [#76](https://github.com/mob-sakai/SoftMaskForUGUI/issues/76) [#80](https://github.com/mob-sakai/SoftMaskForUGUI/issues/80)
### BREAKING CHANGES
* If your code contained the SoftMask API, it would fail to compile. Please change the namespace from `Coffee.UIExtensions` to `Coffee.UISoftMask`.
* The name of the custom SoftMaskable shader must be changed. For more information, see the Support soft masks with your custom shaders section of the README.
# [0.10.0-preview.3](https://github.com/mob-sakai/SoftMaskForUGUI/compare/v0.10.0-preview.2...v0.10.0-preview.3) (2020-05-08)

View File

@ -155,8 +155,20 @@ Or, add a SoftMaskable components from the inspector of the SoftMask component.
<br><br><br><br>
## Support soft masks with your custom shaders
<b>With just three additional lines,</b> you can now support softmasks in your custom shaders!
Only a few steps are needed to support soft mask in your custom shaders!
1. Duplicate your shader file and add the ` (SoftMaskable)` suffix to the file name.
```
Your_Custom_Shader.shader
-> Your_Custom_Shader (SoftMaskable).shader
```
1. Modify the shader name (defined at the beginning of the shader file) as follows:
- Add `Hidden/` prefix
- Add ` (SoftMaskable)` suffix
```
Shader "UI/Your_Custom_Shader"
-> Shader "Hidden/UI/Your_Custom_Shader (SoftMaskable)"
```
1. Add `#pragma` and `#include` directives, where `SOFTMASK_EDITOR` is an editor-only keyword and is not included in the build.
If you didn't use package manager to install, include `SoftMask.cginc` in the appropriate path instead.
```

View File

@ -1,10 +1,9 @@
fileFormatVersion: 2
guid: 3ad57d818b4f448a190e524e494130b0
timeCreated: 1539763439
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 1
@ -12,6 +11,8 @@ TextureImporter:
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
@ -20,6 +21,8 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@ -27,10 +30,13 @@ TextureImporter:
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 16
mipBias: -1
wrapMode: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
@ -39,62 +45,88 @@ TextureImporter:
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
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
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 1a57a60f7f37742a2bb34df8b6da51de
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,7 +3,7 @@ guid: dee1cb6c2ee294c6087ea9d89d368417
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
@ -21,6 +21,8 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@ -31,7 +33,7 @@ TextureImporter:
serializedVersion: 2
filterMode: 1
aniso: -1
mipBias: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
@ -51,11 +53,13 @@ TextureImporter:
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@ -65,7 +69,8 @@ TextureImporter:
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: Standalone
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@ -75,7 +80,8 @@ TextureImporter:
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: iPhone
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@ -85,7 +91,8 @@ TextureImporter:
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: Android
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@ -95,7 +102,8 @@ TextureImporter:
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- buildTarget: WebGL
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@ -110,7 +118,15 @@ TextureImporter:
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 2775f4bfe28684615aa97cccf30fd220
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,10 +1,9 @@
fileFormatVersion: 2
guid: f3749669408984358921fc148ed3aa83
timeCreated: 1542628474
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
@ -22,6 +21,8 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@ -32,7 +33,7 @@ TextureImporter:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
@ -44,63 +45,88 @@ TextureImporter:
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 31, y: 0, z: 31, w: 0}
spritePixelsToUnits: 100
spriteBorder: {x: 31, y: 0, z: 31, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: af5cd8d820f234217a321d94198ab089
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,10 +1,9 @@
fileFormatVersion: 2
guid: 801e306fcae92475592a6d3511bf58d7
timeCreated: 1540708816
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
@ -22,6 +21,8 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@ -32,7 +33,7 @@ TextureImporter:
serializedVersion: 2
filterMode: 1
aniso: -1
mipBias: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
@ -44,63 +45,88 @@ TextureImporter:
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
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
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 8058b3f596fe543db9d4d736085b08b5
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,10 +1,9 @@
fileFormatVersion: 2
guid: 0f125745ff7d640519fb2300ed8a96c7
timeCreated: 1542628487
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
@ -22,6 +21,8 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@ -32,7 +33,7 @@ TextureImporter:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
@ -44,63 +45,88 @@ TextureImporter:
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 31, z: 0, w: 31}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 31, z: 0, w: 31}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: cf7ce3728c4c646cf88a7a642c89aa74
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,61 +3,57 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Coffee.UIExtensions.Demos
namespace Coffee.UISoftMask.Demos
{
public class SoftMask_Demo : MonoBehaviour
{
[SerializeField] RawImage[] softMaskBufferViewer;
[SerializeField] SoftMask[] softMask;
[SerializeField] Text text;
public class SoftMask_Demo : MonoBehaviour
{
[SerializeField] RawImage[] softMaskBufferViewer;
[SerializeField] SoftMask[] softMask;
[SerializeField] Text text;
[SerializeField] GameObject title;
// Use this for initialization
void OnEnable()
{
text.text = string.Format("GPU: {0}\nDeviceType: {1}\nShaderLevel: {2}\nUVStartsAtTop: {3}",
// Use this for initialization
void OnEnable()
{
title.SetActive(true);
text.text = string.Format("GPU: {0}\nDeviceType: {1}\nShaderLevel: {2}\nUVStartsAtTop: {3}",
SystemInfo.graphicsDeviceName,
SystemInfo.graphicsDeviceType,
SystemInfo.graphicsShaderLevel,
SystemInfo.graphicsUVStartsAtTop);
for (int i = 0; i < softMask.Length; i++)
{
softMaskBufferViewer[i].texture = softMask[i].softMaskBuffer;
}
for (int i = 0; i < softMask.Length; i++)
{
softMaskBufferViewer[i].texture = softMask[i].softMaskBuffer;
}
}
}
// Update is called once per frame
void Update()
{
}
public void SetWorldSpase(bool flag)
{
if (flag)
{
GetComponent<Canvas>().renderMode = RenderMode.ScreenSpaceCamera;
GetComponent<Canvas>().renderMode = RenderMode.WorldSpace;
transform.rotation = Quaternion.Euler(new Vector3(0, 6, 0));
}
}
public void SetWorldSpase(bool flag)
{
if(flag)
{
GetComponent<Canvas> ().renderMode = RenderMode.ScreenSpaceCamera;
GetComponent<Canvas> ().renderMode = RenderMode.WorldSpace;
transform.rotation = Quaternion.Euler (new Vector3 (0, 6, 0));
}
}
public void SetScreenSpase(bool flag)
{
if (flag)
{
GetComponent<Canvas>().renderMode = RenderMode.ScreenSpaceCamera;
}
}
public void SetScreenSpase (bool flag)
{
if (flag)
{
GetComponent<Canvas> ().renderMode = RenderMode.ScreenSpaceCamera;
}
}
public void SetOverlay (bool flag)
{
if (flag)
{
GetComponent<Canvas> ().renderMode = RenderMode.ScreenSpaceOverlay;
}
}
}
}
public void SetOverlay(bool flag)
{
if (flag)
{
GetComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,9 @@
fileFormatVersion: 2
guid: e5a8e8d861f62472d8f99611cf9d12c5
timeCreated: 1539763439
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 1
@ -12,6 +11,8 @@ TextureImporter:
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
@ -20,6 +21,8 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@ -27,10 +30,13 @@ TextureImporter:
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: 16
mipBias: -1
wrapMode: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
@ -39,62 +45,88 @@ TextureImporter:
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
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
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: WebGL
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 351a811034e0f411db84265dae66b273
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,57 @@
#if UNITY_2018_3_OR_NEWER
using UnityEditor.Experimental.SceneManagement;
#endif
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace Coffee.UISoftMask
{
internal static class EditorUtils
{
internal static void MarkPrefabDirty()
{
#if UNITY_2018_3_OR_NEWER
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage == null) return;
EditorSceneManager.MarkSceneDirty(prefabStage.scene);
#endif
}
/// <summary>
/// Verify whether it can be converted to the specified component.
/// </summary>
internal static bool CanConvertTo<T>(Object context) where T : MonoBehaviour
{
return context && context.GetType() != typeof(T);
}
/// <summary>
/// Convert to the specified component.
/// </summary>
internal static void ConvertTo<T>(Object context) where T : MonoBehaviour
{
var target = context as MonoBehaviour;
var so = new SerializedObject(target);
so.Update();
bool oldEnable = target.enabled;
target.enabled = false;
// Find MonoScript of the specified component.
foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
{
if (script.GetClass() != typeof(T))
continue;
// Set 'm_Script' to convert.
so.FindProperty("m_Script").objectReferenceValue = script;
so.ApplyModifiedProperties();
break;
}
(so.targetObject as MonoBehaviour).enabled = oldEnable;
}
}
}

View File

@ -4,9 +4,9 @@ using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
namespace Coffee.UIExtensions
namespace Coffee.UISoftMask
{
public static class ImportSampleMenu_UISoftMask
public static class ImportSampleMenu
{
[MenuItem("Assets/Samples/Import UISoftMask Sample")]
private static void ImportSample()

View File

@ -5,130 +5,103 @@ using UnityEditor;
using System.Linq;
namespace Coffee.UIExtensions.Editors
namespace Coffee.UISoftMask
{
/// <summary>
/// SoftMask editor.
/// </summary>
[CustomEditor(typeof(SoftMask))]
[CanEditMultipleObjects]
public class SoftMaskEditor : Editor
{
const string k_PrefsPreview = "SoftMaskEditor_Preview";
static readonly List<Graphic> s_Graphics = new List<Graphic> ();
static bool s_Preview;
/// <summary>
/// SoftMask editor.
/// </summary>
[CustomEditor(typeof(SoftMask))]
[CanEditMultipleObjects]
public class SoftMaskEditor : Editor
{
const string k_PrefsPreview = "SoftMaskEditor_Preview";
static readonly List<Graphic> s_Graphics = new List<Graphic>();
static bool s_Preview;
private void OnEnable ()
{
s_Preview = EditorPrefs.GetBool (k_PrefsPreview, false);
}
private void OnEnable()
{
s_Preview = EditorPrefs.GetBool(k_PrefsPreview, false);
}
public override void OnInspectorGUI ()
{
base.OnInspectorGUI ();
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var current = target as SoftMask;
current.GetComponentsInChildren<Graphic> (true, s_Graphics);
var fixTargets = s_Graphics.Where (x => x.gameObject != current.gameObject && !x.GetComponent<SoftMaskable> () && (!x.GetComponent<Mask> () || x.GetComponent<Mask> ().showMaskGraphic)).ToList ();
if (0 < fixTargets.Count)
{
GUILayout.BeginHorizontal ();
EditorGUILayout.HelpBox ("There are child Graphics that does not have a SoftMaskable component.\nAdd SoftMaskable component to them.", MessageType.Warning);
GUILayout.BeginVertical ();
if (GUILayout.Button ("Fix"))
{
foreach (var p in fixTargets)
{
p.gameObject.AddComponent<SoftMaskable> ();
}
Utils.MarkPrefabDirty ();
}
if (GUILayout.Button ("Ping"))
{
EditorGUIUtility.PingObject (fixTargets[0]);
}
GUILayout.EndVertical ();
GUILayout.EndHorizontal ();
}
var current = target as SoftMask;
current.GetComponentsInChildren<Graphic>(true, s_Graphics);
var fixTargets = s_Graphics.Where(x =>
x.gameObject != current.gameObject && !x.GetComponent<SoftMaskable>() &&
(!x.GetComponent<Mask>() || x.GetComponent<Mask>().showMaskGraphic)).ToList();
if (0 < fixTargets.Count)
{
GUILayout.BeginHorizontal();
EditorGUILayout.HelpBox(
"There are child Graphics that does not have a SoftMaskable component.\nAdd SoftMaskable component to them.",
MessageType.Warning);
GUILayout.BeginVertical();
if (GUILayout.Button("Fix"))
{
foreach (var p in fixTargets)
{
p.gameObject.AddComponent<SoftMaskable>();
}
// Preview buffer.
GUILayout.BeginHorizontal (EditorStyles.helpBox);
if (s_Preview != (s_Preview = EditorGUILayout.ToggleLeft ("Preview Buffer", s_Preview, GUILayout.MaxWidth (EditorGUIUtility.labelWidth))))
{
EditorPrefs.SetBool (k_PrefsPreview, s_Preview);
}
if (s_Preview)
{
var tex = current.softMaskBuffer;
var width = tex.width * 64 / tex.height;
EditorGUI.DrawPreviewTexture (GUILayoutUtility.GetRect (width, 64), tex, null, ScaleMode.ScaleToFit);
Repaint ();
}
GUILayout.FlexibleSpace ();
GUILayout.EndHorizontal ();
}
EditorUtils.MarkPrefabDirty();
}
if (GUILayout.Button("Ping"))
{
EditorGUIUtility.PingObject(fixTargets[0]);
}
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
// Preview buffer.
GUILayout.BeginHorizontal(EditorStyles.helpBox);
if (s_Preview != (s_Preview = EditorGUILayout.ToggleLeft("Preview Buffer", s_Preview,
GUILayout.MaxWidth(EditorGUIUtility.labelWidth))))
{
EditorPrefs.SetBool(k_PrefsPreview, s_Preview);
}
if (s_Preview)
{
var tex = current.softMaskBuffer;
var width = tex.width * 64 / tex.height;
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(width, 64), tex, null, ScaleMode.ScaleToFit);
Repaint();
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
//%%%% Context menu for editor %%%%
[MenuItem("CONTEXT/Mask/Convert To SoftMask", true)]
static bool _ConvertToSoftMask(MenuCommand command)
{
return CanConvertTo<SoftMask>(command.context);
}
//%%%% Context menu for editor %%%%
[MenuItem("CONTEXT/Mask/Convert To SoftMask", true)]
static bool _ConvertToSoftMask(MenuCommand command)
{
return EditorUtils.CanConvertTo<SoftMask>(command.context);
}
[MenuItem("CONTEXT/Mask/Convert To SoftMask", false)]
static void ConvertToSoftMask(MenuCommand command)
{
ConvertTo<SoftMask>(command.context);
}
[MenuItem("CONTEXT/Mask/Convert To SoftMask", false)]
static void ConvertToSoftMask(MenuCommand command)
{
EditorUtils.ConvertTo<SoftMask>(command.context);
}
[MenuItem("CONTEXT/Mask/Convert To Mask", true)]
static bool _ConvertToMask(MenuCommand command)
{
return CanConvertTo<Mask>(command.context);
}
[MenuItem("CONTEXT/Mask/Convert To Mask", true)]
static bool _ConvertToMask(MenuCommand command)
{
return EditorUtils.CanConvertTo<Mask>(command.context);
}
[MenuItem("CONTEXT/Mask/Convert To Mask", false)]
static void ConvertToMask(MenuCommand command)
{
ConvertTo<Mask>(command.context);
}
/// <summary>
/// Verify whether it can be converted to the specified component.
/// </summary>
protected static bool CanConvertTo<T>(Object context)
where T : MonoBehaviour
{
return context && context.GetType() != typeof(T);
}
/// <summary>
/// Convert to the specified component.
/// </summary>
protected static void ConvertTo<T>(Object context) where T : MonoBehaviour
{
var target = context as MonoBehaviour;
var so = new SerializedObject(target);
so.Update();
bool oldEnable = target.enabled;
target.enabled = false;
// Find MonoScript of the specified component.
foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
{
if (script.GetClass() != typeof(T))
continue;
// Set 'm_Script' to convert.
so.FindProperty("m_Script").objectReferenceValue = script;
so.ApplyModifiedProperties();
break;
}
(so.targetObject as MonoBehaviour).enabled = oldEnable;
}
}
}
[MenuItem("CONTEXT/Mask/Convert To Mask", false)]
static void ConvertToMask(MenuCommand command)
{
EditorUtils.ConvertTo<Mask>(command.context);
}
}
}

View File

@ -9,405 +9,176 @@ using Object = UnityEngine.Object;
using MaskIntr = UnityEngine.SpriteMaskInteraction;
using System.IO;
namespace Coffee.UIExtensions.Editors
namespace Coffee.UISoftMask
{
/// <summary>
/// SoftMaskable editor.
/// </summary>
[CustomEditor (typeof (SoftMaskable))]
[CanEditMultipleObjects]
public class SoftMaskableEditor : Editor
{
//################################
// Constant or Static Members.
//################################
public enum MaskInteraction : int
{
VisibleInsideMask = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6),
VisibleOutsideMask = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6),
Custom = -1,
}
/// <summary>
/// SoftMaskable editor.
/// </summary>
[CustomEditor(typeof(SoftMaskable))]
[CanEditMultipleObjects]
public class SoftMaskableEditor : Editor
{
public enum MaskInteraction : int
{
VisibleInsideMask = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6),
VisibleOutsideMask = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6),
Custom = -1,
}
MaskInteraction maskInteraction
{
get
{
int value = _spMaskInteraction.intValue;
return _custom
? MaskInteraction.Custom
: System.Enum.IsDefined(typeof(MaskInteraction), value)
? (MaskInteraction)value
: MaskInteraction.Custom;
}
set
{
_custom = (value == MaskInteraction.Custom);
if (!_custom)
{
_spMaskInteraction.intValue = (int)value;
}
}
}
bool _custom = false;
MaskInteraction maskInteraction
{
get
{
int value = _spMaskInteraction.intValue;
return _custom
? MaskInteraction.Custom
: System.Enum.IsDefined(typeof(MaskInteraction), value)
? (MaskInteraction) value
: MaskInteraction.Custom;
}
set
{
_custom = (value == MaskInteraction.Custom);
if (!_custom)
{
_spMaskInteraction.intValue = (int) value;
}
}
}
static readonly Type s_TypeTMPro = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Text");
static readonly Type s_TypeTMP_SpriteAsset = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SpriteAsset");
static readonly Type s_TypeTMProSettings = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_Settings");
static readonly Type s_TypeTMP_SubMesh = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SubMesh");
static readonly Type s_TypeTMP_SubMeshUI = AppDomain.CurrentDomain.GetAssemblies ().SelectMany (x => x.GetTypes ()).FirstOrDefault (x => x.Name == "TMP_SubMeshUI");
static PropertyInfo s_PiFontSharedMaterial;
static PropertyInfo s_PiFontSharedMaterials;
static PropertyInfo s_PiSpriteAsset;
static PropertyInfo s_PiRichText;
static PropertyInfo s_PiText;
static PropertyInfo s_PiDefaultFontAssetPath;
static PropertyInfo s_PiDefaultSpriteAssetPath;
static FieldInfo s_FiMaterial;
static MethodInfo s_miGetSpriteAsset;
static readonly List<Graphic> s_Graphics = new List<Graphic> ();
Shader _shader;
Shader _mobileShader;
Shader _spriteShader;
List<MaterialEditor> _materialEditors = new List<MaterialEditor> ();
SerializedProperty _spMaskInteraction;
bool _custom = false;
void OnEnable ()
{
_spMaskInteraction = serializedObject.FindProperty("m_MaskInteraction");
_custom = (maskInteraction == MaskInteraction.Custom);
ClearMaterialEditors ();
_shader = Shader.Find ("TextMeshPro/Distance Field (SoftMaskable)");
_mobileShader = Shader.Find ("TextMeshPro/Mobile/Distance Field (SoftMaskable)");
_spriteShader = Shader.Find ("TextMeshPro/Sprite (SoftMaskable)");
if(s_TypeTMPro != null)
{
s_PiFontSharedMaterial = s_TypeTMPro.GetProperty ("fontSharedMaterial");
s_PiSpriteAsset = s_TypeTMPro.GetProperty ("spriteAsset");
s_PiRichText = s_TypeTMPro.GetProperty ("richText");
s_PiText = s_TypeTMPro.GetProperty ("text");
s_FiMaterial = s_TypeTMP_SpriteAsset.GetField ("material");
s_PiFontSharedMaterials = s_TypeTMPro.GetProperty ("fontSharedMaterials");
s_miGetSpriteAsset = s_TypeTMProSettings.GetMethod ("GetSpriteAsset", BindingFlags.Static | BindingFlags.Public);
s_PiDefaultFontAssetPath = s_TypeTMProSettings.GetProperty ("defaultFontAssetPath", BindingFlags.Static | BindingFlags.Public);
s_PiDefaultSpriteAssetPath = s_TypeTMProSettings.GetProperty ("defaultSpriteAssetPath", BindingFlags.Static | BindingFlags.Public);
}
s_MaskWarning = new GUIContent(EditorGUIUtility.FindTexture("console.warnicon.sml"), "This component is not SoftMask. Use SoftMask instead of Mask.");
}
void OnDisable ()
{
ClearMaterialEditors ();
}
List<Mask> tmpMasks = new List<Mask>();
void DrawMaskInteractions()
{
(target as SoftMaskable).GetComponentsInParent<Mask>(true, tmpMasks);
tmpMasks.RemoveAll(x => !x.enabled);
tmpMasks.Reverse();
maskInteraction = (MaskInteraction)EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction);
if (_custom)
{
var l = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 45;
using (var ccs = new EditorGUI.ChangeCheckScope())
{
int intr0 = DrawMaskInteraction(0);
int intr1 = DrawMaskInteraction(1);
int intr2 = DrawMaskInteraction(2);
int intr3 = DrawMaskInteraction(3);
if (ccs.changed) {
_spMaskInteraction.intValue = (intr0 << 0) + (intr1 << 2) + (intr2 << 4) + (intr3 << 6);
}
}
EditorGUIUtility.labelWidth = l;
}
}
static GUIContent s_MaskWarning = new GUIContent();
int DrawMaskInteraction(int layer)
{
Mask mask = layer < tmpMasks.Count ? tmpMasks[layer] : null;
MaskIntr intr = (MaskIntr)((_spMaskInteraction.intValue >> layer * 2) & 0x3);
if (!mask)
{
return (int)intr;
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(mask is SoftMask ? GUIContent.none : s_MaskWarning, GUILayout.Width(16));
GUILayout.Space(-5);
EditorGUILayout.ObjectField("Mask " + layer, mask, typeof(Mask), false);
GUILayout.Space(-15);
return (int)(MaskIntr)EditorGUILayout.EnumPopup(intr);
}
}
public override void OnInspectorGUI ()
{
base.OnInspectorGUI ();
serializedObject.Update();
DrawMaskInteractions();
// maskInteraction = (MaskInteraction)EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction);
serializedObject.ApplyModifiedProperties();
/*
EditorGUI.indentLevel++;
var l = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 60;
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.ObjectField("Mask 0", null, typeof(Mask), false);
EditorGUILayout.EnumPopup (MaskIntr.None);
}
EditorGUIUtility.labelWidth = l;
EditorGUI.indentLevel--;
var spMaskInteraction = serializedObject.FindProperty ("m_MaskInteraction");
MaskIntr intr0 = (MaskIntr)((spMaskInteraction.intValue >> 0) & 0x3);
MaskIntr intr1 = (MaskIntr)((spMaskInteraction.intValue >> 2) & 0x3);
MaskIntr intr2 = (MaskIntr)((spMaskInteraction.intValue >> 4) & 0x3);
MaskIntr intr3 = (MaskIntr)((spMaskInteraction.intValue >> 6) & 0x3);
using (var ccs = new EditorGUI.ChangeCheckScope ()) {
intr0 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 0", intr0);
intr1 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 1", intr1);
intr2 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 2", intr2);
intr3 = (MaskIntr)EditorGUILayout.EnumPopup ("Layer 3", intr3);
if (ccs.changed) {
current.SetMaskInteractions (intr0,intr1,intr2,intr3);
}
}
*/
// spMaskInteraction.intValue = (intr0 << 0) | (intr1 << 2) | (intr2 << 4) | (intr3 << 6);
//
// serializedObject.ApplyModifiedProperties ();
static readonly List<Graphic> s_Graphics = new List<Graphic>();
SerializedProperty _spMaskInteraction;
List<Mask> tmpMasks = new List<Mask>();
static GUIContent s_MaskWarning;
private void OnEnable()
{
_spMaskInteraction = serializedObject.FindProperty("m_MaskInteraction");
_custom = (maskInteraction == MaskInteraction.Custom);
s_MaskWarning = new GUIContent(EditorGUIUtility.FindTexture("console.warnicon.sml"),
"This is not a SoftMask component.");
}
var current = target as SoftMaskable;
current.GetComponentsInChildren<Graphic> (true, s_Graphics);
var fixTargets = s_Graphics.Where (x => x.gameObject != current.gameObject && !x.GetComponent<SoftMaskable> () && (!x.GetComponent<Mask> () || x.GetComponent<Mask> ().showMaskGraphic)).ToList ();
if (0 < fixTargets.Count)
{
GUILayout.BeginHorizontal ();
EditorGUILayout.HelpBox ("There are child Graphics that does not have a SoftMaskable component.\nAdd SoftMaskable component to them.", MessageType.Warning);
GUILayout.BeginVertical ();
if (GUILayout.Button ("Fix"))
{
foreach (var p in fixTargets)
{
p.gameObject.AddComponent<SoftMaskable> ();
}
}
if (GUILayout.Button ("Ping"))
{
EditorGUIUtility.PingObject (fixTargets [0]);
}
GUILayout.EndVertical ();
GUILayout.EndHorizontal ();
}
private void DrawMaskInteractions()
{
var softMaskable = target as SoftMaskable;
if (softMaskable == null) return;
if(s_TypeTMPro != null)
{
ShowTMProWarning (_shader, _mobileShader, _spriteShader, m => { });
var textMeshPro = current.GetComponent (s_TypeTMPro);
if (textMeshPro != null)
{
Material [] fontSharedMaterials = s_PiFontSharedMaterials.GetValue (textMeshPro, new object [0]) as Material [];
ShowMaterialEditors (fontSharedMaterials, 1, fontSharedMaterials.Length - 1);
}
}
if (!DetectMask (current.transform.parent))
{
GUILayout.BeginHorizontal ();
EditorGUILayout.HelpBox ("This is unnecessary SoftMaskable.\nCan't find any SoftMask components above.", MessageType.Warning);
if (GUILayout.Button ("Remove", GUILayout.Height (40)))
{
DestroyImmediate (current);
Utils.MarkPrefabDirty ();
}
GUILayout.EndHorizontal ();
}
}
softMaskable.GetComponentsInParent<Mask>(true, tmpMasks);
tmpMasks.RemoveAll(x => !x.enabled);
tmpMasks.Reverse();
static bool DetectMask (Transform transform)
{
if (transform == null)
{
return false;
}
maskInteraction = (MaskInteraction) EditorGUILayout.EnumPopup("Mask Interaction", maskInteraction);
if (!_custom) return;
if (transform.GetComponent<SoftMask> () != null)
{
return true;
}
var l = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 45;
return DetectMask (transform.parent);
}
using (var ccs = new EditorGUI.ChangeCheckScope())
{
int intr0 = DrawMaskInteraction(0);
int intr1 = DrawMaskInteraction(1);
int intr2 = DrawMaskInteraction(2);
int intr3 = DrawMaskInteraction(3);
void ClearMaterialEditors ()
{
foreach (var e in _materialEditors)
{
if (e)
{
DestroyImmediate (e);
}
}
_materialEditors.Clear ();
}
if (ccs.changed)
{
_spMaskInteraction.intValue = (intr0 << 0) + (intr1 << 2) + (intr2 << 4) + (intr3 << 6);
}
}
protected void ShowMaterialEditors (Material [] materials, int startIndex, int count)
{
for (int i = 0; i < count; i++)
{
if (_materialEditors.Count == i)
{
_materialEditors.Add (null);
}
EditorGUIUtility.labelWidth = l;
}
var mat = materials [startIndex + i];
var editor = _materialEditors [i];
if (editor && editor.target != mat)
{
DestroyImmediate (editor);
editor = null;
}
if (!editor)
{
editor = _materialEditors [i] = Editor.CreateEditor (mat) as MaterialEditor;
}
private int DrawMaskInteraction(int layer)
{
Mask mask = layer < tmpMasks.Count ? tmpMasks[layer] : null;
MaskIntr intr = (MaskIntr) ((_spMaskInteraction.intValue >> layer * 2) & 0x3);
if (!mask)
{
return (int) intr;
}
editor.DrawHeader ();
editor.OnInspectorGUI ();
}
}
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(mask is SoftMask ? GUIContent.none : s_MaskWarning, GUILayout.Width(16));
GUILayout.Space(-5);
EditorGUILayout.ObjectField("Mask " + layer, mask, typeof(Mask), false);
GUILayout.Space(-15);
return (int) (MaskIntr) EditorGUILayout.EnumPopup(intr);
}
}
public void ShowTMProWarning (Shader shader, Shader mobileShader, Shader spriteShader, System.Action<Material> onCreatedMaterial)
{
var current = target as SoftMaskable;
var textMeshPro = current.GetComponent (s_TypeTMPro);
if (textMeshPro == null)
{
return;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
Material fontSharedMaterial = s_PiFontSharedMaterial.GetValue (textMeshPro, new object [0]) as Material;
if (fontSharedMaterial == null)
{
return;
}
serializedObject.Update();
DrawMaskInteractions();
// Is the material preset for dissolve?
Material m = fontSharedMaterial;
if (m.shader != shader && m.shader != mobileShader)
{
EditorGUILayout.BeginHorizontal ();
EditorGUILayout.HelpBox (string.Format ("{0} requires '{1}' or '{2}' as a shader for material preset.", current.GetType ().Name, shader.name, mobileShader.name), MessageType.Warning);
if (GUILayout.Button ("Fix"))
{
var correctShader = m.shader.name.Contains ("Mobile") ? mobileShader : shader;
m = ModifyTMProMaterialPreset (m, correctShader, onCreatedMaterial);
s_PiFontSharedMaterial.SetValue (textMeshPro, m, new object [0]);
}
EditorGUILayout.EndHorizontal ();
return;
}
serializedObject.ApplyModifiedProperties();
// Is the sprite asset for dissolve?
object spriteAsset = s_PiSpriteAsset.GetValue (textMeshPro, new object [0]) ?? s_miGetSpriteAsset.Invoke (null, new object [0]);
//TMP_SpriteAsset spriteAsset = textMeshPro.spriteAsset ?? TMP_Settings.GetSpriteAsset ();
m = s_FiMaterial.GetValue (spriteAsset) as Material;
bool hasSprite = (bool)s_PiRichText.GetValue (textMeshPro, new object [0]) && (s_PiText.GetValue (textMeshPro, new object [0]) as string).Contains ("<sprite=");
if (m && m.shader != spriteShader && hasSprite)
{
EditorGUILayout.BeginHorizontal ();
EditorGUILayout.HelpBox (string.Format ("{0} requires '{1}' as a shader for sprite asset.", GetType ().Name, spriteShader.name), MessageType.Warning);
if (GUILayout.Button ("Fix"))
{
current.GetComponentsInChildren (s_TypeTMP_SubMesh).Select (x => x.gameObject).ToList ().ForEach (DestroyImmediate);
current.GetComponentsInChildren (s_TypeTMP_SubMeshUI).Select (x => x.gameObject).ToList ().ForEach (DestroyImmediate);
spriteAsset = ModifyTMProSpriteAsset (m, _spriteShader, mat => { });
s_PiSpriteAsset.SetValue (textMeshPro, spriteAsset, new object [0]);
}
EditorGUILayout.EndHorizontal ();
return;
}
}
var current = target as SoftMaskable;
Material ModifyTMProMaterialPreset (Material baseMaterial, Shader shader, System.Action<Material> onCreatedMaterial)
{
string path = AssetDatabase.GetAssetPath (baseMaterial);
string filename = Path.GetFileNameWithoutExtension (path) + " (" + typeof (SoftMaskable).Name + ")";
string defaultAssetPath = s_PiDefaultFontAssetPath.GetValue (null, new object [0]) as string;
Material mat = Resources.Load<Material> (defaultAssetPath + filename);
if (!mat)
{
mat = new Material (baseMaterial)
{
shaderKeywords = baseMaterial.shaderKeywords,
shader = shader,
};
onCreatedMaterial (mat);
AssetDatabase.CreateAsset (mat, Path.GetDirectoryName (path) + "/" + filename + ".mat");
current.GetComponentsInChildren<Graphic>(true, s_Graphics);
var fixTargets = s_Graphics.Where(x =>
x.gameObject != current.gameObject && !x.GetComponent<SoftMaskable>() &&
(!x.GetComponent<Mask>() || x.GetComponent<Mask>().showMaskGraphic)).ToList();
if (0 < fixTargets.Count)
{
GUILayout.BeginHorizontal();
EditorGUILayout.HelpBox(
"There are child Graphics that does not have a SoftMaskable component.\nAdd SoftMaskable component to them.",
MessageType.Warning);
GUILayout.BeginVertical();
if (GUILayout.Button("Fix"))
{
foreach (var p in fixTargets)
{
p.gameObject.AddComponent<SoftMaskable>();
}
}
EditorUtility.FocusProjectWindow ();
EditorGUIUtility.PingObject (mat);
}
else
{
mat.shader = shader;
}
EditorUtility.SetDirty (mat);
return mat;
}
if (GUILayout.Button("Ping"))
{
EditorGUIUtility.PingObject(fixTargets[0]);
}
object ModifyTMProSpriteAsset (Material baseMaterial, Shader shader, System.Action<Material> onCreatedMaterial)
{
string path = AssetDatabase.GetAssetPath (baseMaterial);
string filename = Path.GetFileNameWithoutExtension (path) + " (" + typeof (SoftMaskable).Name + ")";
string defaultAssetPath = s_PiDefaultSpriteAssetPath.GetValue (null, new object [0]) as string;
Object spriteAsset = Resources.Load (defaultAssetPath + filename, s_TypeTMP_SpriteAsset);
if (spriteAsset == null)
{
AssetDatabase.CopyAsset (path, Path.GetDirectoryName (path) + "/" + filename + ".mat");
spriteAsset = Resources.Load (defaultAssetPath + filename, s_TypeTMP_SpriteAsset);
Material m = s_FiMaterial.GetValue (spriteAsset) as Material;
m.shader = shader;
m.name = shader.name;
onCreatedMaterial (m);
GUILayout.EndVertical();
GUILayout.EndHorizontal();
}
EditorUtility.FocusProjectWindow ();
EditorGUIUtility.PingObject (spriteAsset);
}
else
{
Material m = s_FiMaterial.GetValue (spriteAsset) as Material;
m.shader = shader;
}
EditorUtility.SetDirty (spriteAsset);
return spriteAsset;
}
}
}
if (!DetectMask(current.transform.parent))
{
GUILayout.BeginHorizontal();
EditorGUILayout.HelpBox("This is unnecessary SoftMaskable.\nCan't find any SoftMask components above.",
MessageType.Warning);
if (GUILayout.Button("Remove", GUILayout.Height(40)))
{
DestroyImmediate(current);
EditorUtils.MarkPrefabDirty();
}
GUILayout.EndHorizontal();
}
}
static bool DetectMask(Transform transform)
{
while (transform)
{
if (transform.GetComponent<SoftMask>()) return true;
transform = transform.parent;
}
return false;
}
}
}

View File

@ -1,22 +0,0 @@
#if UNITY_2018_3_OR_NEWER
using UnityEditor.Experimental.SceneManagement;
#endif
using UnityEditor.SceneManagement;
namespace Coffee.UIExtensions.Editors
{
public static class Utils
{
public static void MarkPrefabDirty ()
{
#if UNITY_2018_3_OR_NEWER
var prefabStage = PrefabStageUtility.GetCurrentPrefabStage ();
if (prefabStage != null)
{
EditorSceneManager.MarkSceneDirty (prefabStage.scene);
}
#endif
}
}
}

107
Scripts/GraphicConnector.cs Normal file
View File

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Coffee.UISoftMask
{
internal static class GraphicConnectorExtension
{
public static void SetVerticesDirtyEx(this Graphic graphic)
{
GraphicConnector.FindConnector(graphic).SetVerticesDirty(graphic);
}
public static void SetMaterialDirtyEx(this Graphic graphic)
{
GraphicConnector.FindConnector(graphic).SetMaterialDirty(graphic);
}
public static Shader FindEffectShader(this Graphic graphic)
{
return GraphicConnector.FindConnector(graphic).FindEffectShader(graphic);
}
}
public class GraphicConnector
{
private static readonly List<GraphicConnector> s_Connectors = new List<GraphicConnector>();
private static readonly Dictionary<Type, GraphicConnector> s_ConnectorMap =
new Dictionary<Type, GraphicConnector>();
private static readonly GraphicConnector s_EmptyConnector = new GraphicConnector();
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
#endif
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void Init()
{
AddConnector(new GraphicConnector());
}
protected static void AddConnector(GraphicConnector connector)
{
s_Connectors.Add(connector);
s_Connectors.Sort((x, y) => y.priority - x.priority);
}
public static GraphicConnector FindConnector(Graphic graphic)
{
if (!graphic) return s_EmptyConnector;
var type = graphic.GetType();
GraphicConnector connector = null;
if (s_ConnectorMap.TryGetValue(type, out connector)) return connector;
foreach (var c in s_Connectors)
{
if (!c.IsValid(graphic)) continue;
s_ConnectorMap.Add(type, c);
return c;
}
return s_EmptyConnector;
}
/// <summary>
/// Connector priority.
/// </summary>
protected virtual int priority
{
get { return -1; }
}
/// <summary>
/// Find effect shader.
/// </summary>
public virtual Shader FindEffectShader(Graphic graphic)
{
return Shader.Find("Hidden/UI/SoftMaskable");
}
/// <summary>
/// The connector is valid for the component.
/// </summary>
protected virtual bool IsValid(Graphic graphic)
{
return true;
}
public virtual void SetVerticesDirty(Graphic graphic)
{
if (graphic)
graphic.SetVerticesDirty();
}
public virtual void SetMaterialDirty(Graphic graphic)
{
if (graphic)
graphic.SetMaterialDirty();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e702140c28f4425fac896f9394a31b1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

80
Scripts/MaterialCache.cs Normal file
View File

@ -0,0 +1,80 @@
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.UI;
namespace Coffee.UISoftMask
{
internal class MaterialCache
{
public delegate void ModifyAction(Material material, Graphic graphic);
static Dictionary<Hash128, MaterialEntry> materialMap = new Dictionary<Hash128, MaterialEntry>();
private class MaterialEntry
{
public Material material;
public int referenceCount;
public void Release()
{
if (material)
{
UnityEngine.Object.DestroyImmediate(material, false);
}
material = null;
}
}
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
private static void ClearCache()
{
foreach (var entry in materialMap.Values)
{
entry.Release();
}
materialMap.Clear();
}
#endif
public static Material Register(Material material, Hash128 hash, Action<Material> onModify)
{
if (!hash.isValid) return null;
MaterialEntry entry;
if (!materialMap.TryGetValue(hash, out entry))
{
entry = new MaterialEntry()
{
material = new Material(material)
{
hideFlags = HideFlags.HideAndDontSave,
},
};
onModify(entry.material);
materialMap.Add(hash, entry);
}
entry.referenceCount++;
//Debug.LogFormat("Register: {0}, {1} (Total: {2})", hash, entry.referenceCount, materialMap.Count);
return entry.material;
}
public static void Unregister(Hash128 hash)
{
MaterialEntry entry;
if (!hash.isValid || !materialMap.TryGetValue(hash, out entry)) return;
//Debug.LogFormat("Unregister: {0}, {1}", hash, entry.referenceCount -1);
if (--entry.referenceCount > 0) return;
entry.Release();
materialMap.Remove(hash);
//Debug.LogFormat("Unregister: Release Emtry: {0}, {1} (Total: {2})", hash, entry.referenceCount, materialMap.Count);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: be6c8de8d4ec241fdbfad99aca2497d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -1,301 +1,263 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
using MaskIntr = UnityEngine.SpriteMaskInteraction;
using UnityEngine.Serialization;
namespace Coffee.UIExtensions
namespace Coffee.UISoftMask
{
/// <summary>
/// Soft maskable.
/// Add this component to Graphic under SoftMask for smooth masking.
/// </summary>
/// <summary>
/// Soft maskable.
/// Add this component to Graphic under SoftMask for smooth masking.
/// </summary>
#if UNITY_2018_3_OR_NEWER
[ExecuteAlways]
[ExecuteAlways]
#else
[ExecuteInEditMode]
# endif
public class SoftMaskable : MonoBehaviour, IMaterialModifier, ICanvasRaycastFilter, ISerializationCallbackReceiver
{
//################################
// Constant or Static Members.
//################################
const int kVisibleInside = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6);
const int kVisibleOutside = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6);
public class SoftMaskable : MonoBehaviour, IMaterialModifier, ICanvasRaycastFilter
#if UNITY_EDITOR
, ISerializationCallbackReceiver
# endif
{
const int kVisibleInside = (1 << 0) + (1 << 2) + (1 << 4) + (1 << 6);
const int kVisibleOutside = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6);
static readonly Hash128 k_InvalidHash = new Hash128();
static int s_SoftMaskTexId;
static int s_StencilCompId;
static int s_MaskInteractionId;
static List<SoftMaskable> s_ActiveSoftMaskables;
static int[] s_Interactions = new int[4];
//################################
// Serialize Members.
//################################
[Tooltip("The graphic will be visible only in areas where no mask is present.")]
[System.Obsolete]
[HideInInspector]
[SerializeField] bool m_Inverse = false;
[Tooltip("The interaction for each masks.")]
[HideInInspector]
[SerializeField] int m_MaskInteraction = kVisibleInside;
[Tooltip("Use stencil to mask.")]
[SerializeField] bool m_UseStencil = false;
[Tooltip("Use soft-masked raycast target.\n\nNote: This option is expensive.")]
[SerializeField] bool m_RaycastFilter = false;
[Tooltip("The graphic will be visible only in areas where no mask is present.")]
[System.Obsolete]
[HideInInspector]
[SerializeField]
bool m_Inverse = false;
[Tooltip("The interaction for each masks.")] [HideInInspector] [SerializeField]
int m_MaskInteraction = kVisibleInside;
//################################
// Public Members.
//################################
/// <summary>
/// Perform material modification in this function.
/// </summary>
/// <returns>Modified material.</returns>
/// <param name="baseMaterial">Configured Material.</param>
public Material GetModifiedMaterial(Material baseMaterial)
{
_softMask = null;
if (!isActiveAndEnabled)
{
return baseMaterial;
}
[Tooltip("Use stencil to mask.")] [SerializeField]
bool m_UseStencil = false;
// Find the nearest parent softmask.
var parentTransform = transform.parent;
while (parentTransform)
{
var sm = parentTransform.GetComponent<SoftMask>();
if (sm && sm.enabled)
{
_softMask = sm;
break;
}
parentTransform = parentTransform.parent;
}
[Tooltip("Use soft-masked raycast target.\n\nNote: This option is expensive.")] [SerializeField]
bool m_RaycastFilter = false;
Material result = baseMaterial;
if (_softMask)
{
result = new Material(baseMaterial);
result.hideFlags = HideFlags.HideAndDontSave;
result.SetTexture(s_SoftMaskTexId, _softMask.softMaskBuffer);
result.SetInt(s_StencilCompId, m_UseStencil ? (int)CompareFunction.Equal : (int)CompareFunction.Always);
result.SetVector(s_MaskInteractionId, new Vector4(
(m_MaskInteraction & 0x3),
((m_MaskInteraction >> 2) & 0x3),
((m_MaskInteraction >> 4) & 0x3),
((m_MaskInteraction >> 6) & 0x3)
));
Graphic _graphic = null;
SoftMask _softMask = null;
Material _maskMaterial = null;
Hash128 _effectMaterialHash;
StencilMaterial.Remove(baseMaterial);
ReleaseMaterial(ref _maskMaterial);
_maskMaterial = result;
#if UNITY_EDITOR
result.EnableKeyword("SOFTMASK_EDITOR");
#endif
}
else
{
baseMaterial.SetTexture(s_SoftMaskTexId, Texture2D.whiteTexture);
}
return result;
}
/// <summary>
/// Given a point and a camera is the raycast valid.
/// </summary>
/// <returns>Valid.</returns>
/// <param name="sp">Screen position.</param>
/// <param name="eventCamera">Raycast camera.</param>
public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
{
if (!isActiveAndEnabled || !_softMask)
return true;
if (!RectTransformUtility.RectangleContainsScreenPoint(transform as RectTransform, sp, eventCamera))
{
return false;
}
else if (!m_RaycastFilter)
/// <summary>
/// The graphic will be visible only in areas where no mask is present.
/// </summary>
public bool inverse
{
get { return m_MaskInteraction == kVisibleOutside; }
set
{
return true;
var intValue = value ? kVisibleOutside : kVisibleInside;
if (m_MaskInteraction == intValue) return;
m_MaskInteraction = intValue;
graphic.SetMaterialDirtyEx();
}
}
/// <summary>
/// Use soft-masked raycast target. This option is expensive.
/// </summary>
public bool raycastFilter
{
get { return m_RaycastFilter; }
set { m_RaycastFilter = value; }
}
/// <summary>
/// The graphic associated with the soft mask.
/// </summary>
public Graphic graphic
{
get { return _graphic ? _graphic : _graphic = GetComponent<Graphic>(); }
}
/// <summary>
/// Perform material modification in this function.
/// </summary>
/// <returns>Modified material.</returns>
/// <param name="baseMaterial">Configured Material.</param>
Material IMaterialModifier.GetModifiedMaterial(Material baseMaterial)
{
_softMask = null;
// Unregister the previous material
MaterialCache.Unregister(_effectMaterialHash);
_effectMaterialHash = k_InvalidHash;
// If this component is disabled, the material is returned as is.
if (!isActiveAndEnabled) return baseMaterial;
// Find the nearest parent softmask.
var parentTransform = transform.parent;
while (parentTransform)
{
var sm = parentTransform.GetComponent<SoftMask>();
if (sm && sm.enabled)
{
_softMask = sm;
break;
}
parentTransform = parentTransform.parent;
}
var sm = _softMask;
for (int i = 0; i < 4; i++)
{
s_Interactions[i] = sm ? ((m_MaskInteraction >> i * 2) & 0x3) : 0;
sm = sm ? sm.parent : null;
}
// If the parents do not have a soft mask component, the material is returned as is.
if (!_softMask) return baseMaterial;
return _softMask.IsRaycastLocationValid(sp, eventCamera, graphic, s_Interactions);
}
// Generate soft maskable material.
_effectMaterialHash = new Hash128(
(uint) baseMaterial.GetInstanceID(),
(uint) _softMask.GetInstanceID(),
(uint) m_MaskInteraction,
(uint) (m_UseStencil ? 1 : 0)
);
// Generate soft maskable material.
var modifiedMaterial = MaterialCache.Register(baseMaterial, _effectMaterialHash, mat =>
{
mat.shader = Shader.Find(string.Format("Hidden/{0} (SoftMaskable)", mat.shader.name));
#if UNITY_EDITOR
mat.EnableKeyword("SOFTMASK_EDITOR");
#endif
mat.SetTexture(s_SoftMaskTexId, _softMask.softMaskBuffer);
mat.SetInt(s_StencilCompId,
m_UseStencil ? (int) CompareFunction.Equal : (int) CompareFunction.Always);
mat.SetVector(s_MaskInteractionId, new Vector4(
(m_MaskInteraction & 0x3),
((m_MaskInteraction >> 2) & 0x3),
((m_MaskInteraction >> 4) & 0x3),
((m_MaskInteraction >> 6) & 0x3)
));
});
_maskMaterial = modifiedMaterial;
return modifiedMaterial;
}
/// <summary>
/// Given a point and a camera is the raycast valid.
/// </summary>
/// <returns>Valid.</returns>
/// <param name="sp">Screen position.</param>
/// <param name="eventCamera">Raycast camera.</param>
bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
{
if (!isActiveAndEnabled || !_softMask)
return true;
if (!RectTransformUtility.RectangleContainsScreenPoint(transform as RectTransform, sp, eventCamera))
return false;
if (!m_RaycastFilter)
return true;
var sm = _softMask;
for (var i = 0; i < 4; i++)
{
s_Interactions[i] = sm ? ((m_MaskInteraction >> i * 2) & 0x3) : 0;
sm = sm ? sm.parent : null;
}
return _softMask.IsRaycastLocationValid(sp, eventCamera, graphic, s_Interactions);
}
/// <summary>
/// Set the interaction for each mask.
/// </summary>
public void SetMaskInteraction(SpriteMaskInteraction intr)
{
SetMaskInteraction(intr, intr, intr, intr);
}
/// <summary>
/// Set the interaction for each mask.
/// </summary>
public void SetMaskInteraction(SpriteMaskInteraction layer0, SpriteMaskInteraction layer1,
SpriteMaskInteraction layer2, SpriteMaskInteraction layer3)
{
m_MaskInteraction = (int) layer0 + ((int) layer1 << 2) + ((int) layer2 << 4) + ((int) layer3 << 6);
graphic.SetMaterialDirtyEx();
}
/// <summary>
/// The graphic will be visible only in areas where no mask is present.
/// </summary>
public bool inverse
{
get { return m_MaskInteraction == kVisibleOutside; }
set
{
int intValue = value ? kVisibleOutside : kVisibleInside;
if (m_MaskInteraction != intValue)
{
m_MaskInteraction = intValue;
graphic.SetMaterialDirty();
}
}
}
/// <summary>
/// This function is called when the object becomes enabled and active.
/// </summary>
private void OnEnable()
{
// Register.
if (s_ActiveSoftMaskables == null)
{
s_ActiveSoftMaskables = new List<SoftMaskable>();
/// <summary>
/// Use soft-masked raycast target. This option is expensive.
/// </summary>
public bool raycastFilter
{
get { return m_RaycastFilter; }
set { m_RaycastFilter = value; }
}
s_SoftMaskTexId = Shader.PropertyToID("_SoftMaskTex");
s_StencilCompId = Shader.PropertyToID("_StencilComp");
s_MaskInteractionId = Shader.PropertyToID("_MaskInteraction");
}
/// <summary>
/// The graphic associated with the soft mask.
/// </summary>
public Graphic graphic{ get { return _graphic ? _graphic : _graphic = GetComponent<Graphic>(); } }
s_ActiveSoftMaskables.Add(this);
/// <summary>
/// Set the interaction for each mask.
/// </summary>
public void SetMaskInteraction(SpriteMaskInteraction intr)
{
SetMaskInteraction(intr, intr, intr, intr);
}
graphic.SetMaterialDirtyEx();
_softMask = null;
}
/// <summary>
/// Set the interaction for each mask.
/// </summary>
public void SetMaskInteraction(SpriteMaskInteraction layer0, SpriteMaskInteraction layer1, SpriteMaskInteraction layer2, SpriteMaskInteraction layer3)
{
m_MaskInteraction = (int)layer0 + ((int)layer1 << 2) + ((int)layer2 << 4) + ((int)layer3 << 6);
if (graphic)
{
graphic.SetMaterialDirty();
}
}
/// <summary>
/// This function is called when the behaviour becomes disabled.
/// </summary>
private void OnDisable()
{
s_ActiveSoftMaskables.Remove(this);
//################################
// Private Members.
//################################
Graphic _graphic = null;
SoftMask _softMask = null;
Material _maskMaterial = null;
static int s_SoftMaskTexId;
static int s_StencilCompId;
static int s_MaskInteractionId;
static List<SoftMaskable> s_ActiveSoftMaskables;
static int[] s_Interactions = new int[4];
static Material s_DefaultMaterial;
graphic.SetMaterialDirtyEx();
_softMask = null;
MaterialCache.Unregister(_effectMaterialHash);
_effectMaterialHash = k_InvalidHash;
}
#if UNITY_EDITOR
/// <summary>
/// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).
/// </summary>
void OnValidate()
{
if (graphic)
{
graphic.SetMaterialDirty();
}
}
/// <summary>
/// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only).
/// </summary>
private void OnValidate()
{
graphic.SetMaterialDirtyEx();
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
#pragma warning disable 0612
if (m_Inverse)
{
m_Inverse = false;
m_MaskInteraction = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6);
}
#pragma warning restore 0612
var current = this;
UnityEditor.EditorApplication.delayCall += () =>
{
if (current && graphic && graphic.material && graphic.material.shader &&
graphic.material.shader.name == "Hidden/UI/Default (SoftMaskable)")
{
graphic.material = null;
graphic.SetMaterialDirtyEx();
}
};
#endif
/// <summary>
/// This function is called when the object becomes enabled and active.
/// </summary>
void OnEnable()
{
// Register.
if (s_ActiveSoftMaskables == null)
{
s_ActiveSoftMaskables = new List<SoftMaskable>();
s_SoftMaskTexId = Shader.PropertyToID("_SoftMaskTex");
s_StencilCompId = Shader.PropertyToID("_StencilComp");
s_MaskInteractionId = Shader.PropertyToID("_MaskInteraction");
}
s_ActiveSoftMaskables.Add(this);
var g = graphic;
if (g)
{
if (!g.material || g.material == Graphic.defaultGraphicMaterial)
{
g.material = s_DefaultMaterial ?? (s_DefaultMaterial = new Material(Resources.Load<Shader>("UI-Default-SoftMask")) { hideFlags = HideFlags.HideAndDontSave, });
}
g.SetMaterialDirty();
}
_softMask = null;
}
/// <summary>
/// This function is called when the behaviour becomes disabled.
/// </summary>
void OnDisable()
{
s_ActiveSoftMaskables.Remove(this);
var g = graphic;
if (g)
{
if (g.material == s_DefaultMaterial)
{
g.material = null;
}
g.SetMaterialDirty();
}
ReleaseMaterial(ref _maskMaterial);
_softMask = null;
}
/// <summary>
/// Release the material.
/// </summary>
void ReleaseMaterial(ref Material mat)
{
if (mat)
{
StencilMaterial.Remove(mat);
#if UNITY_EDITOR
if (!Application.isPlaying)
{
DestroyImmediate(mat);
}
else
#endif
{
Destroy(mat);
}
mat = null;
}
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
#pragma warning disable 0612
if (m_Inverse)
{
m_Inverse = false;
m_MaskInteraction = (2 << 0) + (2 << 2) + (2 << 4) + (2 << 6);
}
#pragma warning restore 0612
}
}
}
}
}

View File

@ -1,4 +1,4 @@
Shader "UI/Default-SoftMask"
Shader "Hidden/UI/Default (SoftMaskable)"
{
Properties
{
@ -52,7 +52,7 @@ Shader "UI/Default-SoftMask"
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile __ UNITY_UI_CLIP_RECT
#pragma multi_compile __ UNITY_UI_ALPHACLIP

View File

@ -1,4 +1,4 @@
Shader "TextMeshPro/Distance Field (SoftMaskable)" {
Shader "Hidden/TextMeshPro/Distance Field (SoftMaskable)" {
Properties {
_FaceTex ("Face Texture", 2D) = "white" {}
@ -35,7 +35,7 @@ Properties {
_ReflectOutlineColor("Reflection Color", Color) = (0,0,0,1)
_Cube ("Reflection Cubemap", Cube) = "black" { /* TexGen CubeReflect */ }
_EnvMatrixRotation ("Texture Rotation", vector) = (0, 0, 0, 0)
_UnderlayColor ("Border Color", Color) = (0,0,0, 0.5)
_UnderlayOffsetX ("Border OffsetX", Range(-1,1)) = 0
@ -67,7 +67,7 @@ Properties {
_VertexOffsetX ("Vertex OffsetX", float) = 0
_VertexOffsetY ("Vertex OffsetY", float) = 0
_MaskCoord ("Mask Coordinates", vector) = (0, 0, 32767, 32767)
_ClipRect ("Clip Rect", vector) = (-32767, -32767, 32767, 32767)
_MaskSoftnessX ("Mask SoftnessX", float) = 0
@ -95,7 +95,7 @@ SubShader {
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
@ -126,7 +126,7 @@ SubShader {
#include "UnityUI.cginc"
#include "Assets/TextMesh Pro/Resources/Shaders/TMPro_Properties.cginc"
#include "Assets/TextMesh Pro/Resources/Shaders/TMPro.cginc"
#include "Packages/com.coffee.softmask-for-ugui/Shaders/SoftMask.cginc"
#pragma shader_feature __ SOFTMASK_EDITOR
@ -146,7 +146,7 @@ SubShader {
float4 param : TEXCOORD1; // alphaClip, scale, bias, weight
float4 mask : TEXCOORD2; // Position in object space(xy), pixel Size(zw)
float3 viewDir : TEXCOORD3;
#if (UNDERLAY_ON || UNDERLAY_INNER)
float4 texcoord2 : TEXCOORD4; // u,v, scale, bias
fixed4 underlayColor : COLOR1;
@ -181,7 +181,7 @@ SubShader {
float bias =(.5 - weight) + (.5 / scale);
float alphaClip = (1.0 - _OutlineWidth*_ScaleRatioA - _OutlineSoftness*_ScaleRatioA);
#if GLOW_ON
alphaClip = min(alphaClip, 1.0 - _GlowOffset * _ScaleRatioB - _GlowOuter * _ScaleRatioB);
#endif
@ -232,7 +232,7 @@ SubShader {
fixed4 PixShader(pixel_t input) : SV_Target
{
float c = tex2D(_MainTex, input.atlas).a;
#ifndef UNDERLAY_ON
clip(c - input.param.x);
#endif
@ -249,7 +249,7 @@ SubShader {
half4 outlineColor = _OutlineColor;
faceColor.rgb *= input.color.rgb;
faceColor *= tex2D(_FaceTex, input.textures.xy + float2(_FaceUVSpeedX, _FaceUVSpeedY) * _Time.y);
outlineColor *= tex2D(_OutlineTex, input.textures.zw + float2(_OutlineUVSpeedX, _OutlineUVSpeedY) * _Time.y);
@ -294,9 +294,9 @@ SubShader {
half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(input.mask.xy)) * input.mask.zw);
faceColor *= m.x * m.y;
#endif
faceColor *= SoftMask(input.position, input.worldPosition);
#if UNITY_UI_ALPHACLIP
clip(faceColor.a - 0.001);
#endif

View File

@ -3,7 +3,7 @@
// - No Glow Option
// - Softness is applied on both side of the outline
Shader "TextMeshPro/Mobile/Distance Field (SoftMaskable)" {
Shader "Hidden/TextMeshPro/Mobile/Distance Field (SoftMaskable)" {
Properties {
_FaceColor ("Face Color", Color) = (1,1,1,1)
@ -41,18 +41,18 @@ Properties {
_ClipRect ("Clip Rect", vector) = (-32767, -32767, 32767, 32767)
_MaskSoftnessX ("Mask SoftnessX", float) = 0
_MaskSoftnessY ("Mask SoftnessY", float) = 0
_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
}
SubShader {
Tags
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
@ -64,7 +64,7 @@ SubShader {
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
@ -94,7 +94,7 @@ SubShader {
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#include "Assets/TextMesh Pro/Resources/Shaders/TMPro_Properties.cginc"
#include "Packages/com.coffee.softmask-for-ugui/Shaders/SoftMask.cginc"
#pragma shader_feature __ SOFTMASK_EDITOR
@ -132,7 +132,7 @@ SubShader {
float2 pixelSize = vPosition.w;
pixelSize /= float2(_ScaleX, _ScaleY) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));
float scale = rsqrt(dot(pixelSize, pixelSize));
scale *= abs(input.texcoord1.y) * _GradientScale * 1.5;
if(UNITY_MATRIX_P[3][3] == 0) scale = lerp(abs(scale) * (1 - _PerspectiveFilter), scale, abs(dot(UnityObjectToWorldNormal(input.normal.xyz), normalize(WorldSpaceViewDir(vert)))));
@ -223,9 +223,9 @@ SubShader {
#if (UNDERLAY_ON | UNDERLAY_INNER)
c *= input.texcoord1.z;
#endif
c *= SoftMask(input.vertex, input.worldPosition);
#if UNITY_UI_ALPHACLIP
clip(c.a - 0.001);
#endif

View File

@ -1,10 +1,10 @@
Shader "TextMeshPro/Sprite (SoftMaskable)"
Shader "Hidden/TextMeshPro/Sprite (SoftMaskable)"
{
Properties
{
_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
@ -20,19 +20,19 @@ Shader "TextMeshPro/Sprite (SoftMaskable)"
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
@ -55,10 +55,10 @@ Shader "TextMeshPro/Sprite (SoftMaskable)"
#pragma multi_compile __ UNITY_UI_CLIP_RECT
#pragma multi_compile __ UNITY_UI_ALPHACLIP
#include "Packages/com.coffee.softmask-for-ugui/Shaders/SoftMask.cginc"
#pragma shader_feature __ SOFTMASK_EDITOR
struct appdata_t
{
float4 vertex : POSITION;
@ -73,7 +73,7 @@ Shader "TextMeshPro/Sprite (SoftMaskable)"
half2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
};
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
@ -85,11 +85,11 @@ Shader "TextMeshPro/Sprite (SoftMaskable)"
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = IN.texcoord;
#ifdef UNITY_HALF_TEXEL_OFFSET
OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
#endif
OUT.color = IN.color * _Color;
return OUT;
}
@ -99,13 +99,13 @@ Shader "TextMeshPro/Sprite (SoftMaskable)"
fixed4 frag(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
#if UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
color.a *= SoftMask(IN.vertex, IN.worldPosition);
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif

View File

@ -2,7 +2,7 @@
"name": "com.coffee.softmask-for-ugui",
"displayName": "UI Soft Mask",
"description": "UI Soft Mask is a smooth masking component for Unity UI (uGUI) elements.\nBy using SoftMask instead of the default Mask component, you can beautifully represent the rounded edges of UI elements.",
"version": "0.10.0-preview.3",
"version": "1.0.0-preview.1",
"unity": "2017.1",
"license": "MIT",
"repository": {