teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

マテリアル案を追記

2021/01/21 03:47

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -1,4 +1,117 @@
1
1
  ブレンドモードが`Blend One OneMinusSrcAlpha`となっていますので、描画結果は`シェーダーが出力した色 + 下地の色 × (1.0 - シェーダーが出力した色のアルファ)`となるはずです。アルファが0のときの描画結果は`シェーダーが出力した色 + 下地の色`となり、加算合成をしているのと同じになるわけですね。
2
2
 
3
3
  アルファが0のときに完全透明にしたいとなると、ブレンドモードを`Blend SrcAlpha OneMinusSrcAlpha`にするのがいいかと思います。ですがそれだと普通のアルファブレンディングと同じになってしまうはずですが、ご質問者さんの意図する挙動はどのようなものでしょうか。
4
- 「アルファ1だと完全不透明、アルファを下げていくとだんだん加算合成のようになっていき、さらにアルファを下げていくと絵が薄くなり、アルファ0で完全透明」みたいな感じでしょうか?
4
+ 「アルファ1だと完全不透明、アルファを下げていくとだんだん加算合成のようになっていき、さらにアルファを下げていくと絵が薄くなり、アルファ0で完全透明」みたいな感じでしょうか?
5
+
6
+ ##マテリアル案
7
+
8
+ 一案として下記のようなものはいかがでしょうか?
9
+
10
+ ```ShaderLab
11
+ // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
12
+
13
+ Shader "Sprites/TestShader"
14
+ {
15
+ Properties
16
+ {
17
+ [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
18
+ _Color ("Tint", Color) = (1,1,1,1)
19
+ [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
20
+ [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
21
+ [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
22
+ [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
23
+ [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
24
+ _Alpha ("Alpha", Range(0, 1)) = 1
25
+ _Exponent ("Exponent", Range(1, 16)) = 1
26
+ }
27
+
28
+ SubShader
29
+ {
30
+ Tags
31
+ {
32
+ "Queue"="Transparent"
33
+ "IgnoreProjector"="True"
34
+ "RenderType"="Transparent"
35
+ "PreviewType"="Plane"
36
+ "CanUseSpriteAtlas"="True"
37
+ }
38
+
39
+ Cull Off
40
+ Lighting Off
41
+ ZWrite Off
42
+ Blend One OneMinusSrcAlpha
43
+
44
+ Pass
45
+ {
46
+ CGPROGRAM
47
+ #pragma vertex vert
48
+ #pragma fragment frag
49
+ #pragma target 2.0
50
+ #pragma multi_compile_instancing
51
+ #pragma multi_compile _ PIXELSNAP_ON
52
+ #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
53
+ #include "UnitySprites.cginc"
54
+
55
+ struct v2fCustom
56
+ {
57
+ float4 vertex : SV_POSITION;
58
+ fixed4 color : COLOR;
59
+ float2 texcoord : TEXCOORD0;
60
+ float2 position : TEXCOORD1;
61
+ UNITY_VERTEX_OUTPUT_STEREO
62
+ };
63
+
64
+ v2fCustom vert(appdata_t IN)
65
+ {
66
+ v2fCustom OUT;
67
+
68
+ UNITY_SETUP_INSTANCE_ID (IN);
69
+ UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
70
+
71
+ OUT.vertex = UnityFlipSprite(IN.vertex, _Flip);
72
+ OUT.vertex = UnityObjectToClipPos(OUT.vertex);
73
+ OUT.texcoord = IN.texcoord;
74
+ OUT.color = IN.color * _Color * _RendererColor;
75
+ OUT.position = IN.vertex.xy * 2;
76
+
77
+ #ifdef PIXELSNAP_ON
78
+ OUT.vertex = UnityPixelSnap (OUT.vertex);
79
+ #endif
80
+
81
+ return OUT;
82
+ }
83
+
84
+ float _Alpha;
85
+ float _Exponent;
86
+
87
+ fixed4 frag(v2fCustom IN) : SV_Target
88
+ {
89
+ fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
90
+
91
+ // アルファ変化時の見た目の変化を実演するため、アルファを
92
+ // プロパティにして外部から操作できるようにした
93
+ float alpha = _Alpha;
94
+ c.a = alpha;
95
+
96
+ // 通常のアルファブレンディングではRGBにアルファがそのまま乗算されるが、
97
+ // ここで「白黒反転して冪乗して白黒反転」の操作を加えることで
98
+ // 乗算値の変化が非線形なカーブとなって、中間のアルファのときに
99
+ // 乗算値が通常よりも高くなり、加算合成に近づく
100
+ c.rgb *= 1.0 - pow(1.0 - c.a, _Exponent);
101
+
102
+ return c;
103
+ }
104
+ ENDCG
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ ブレンドモードは`Blend One OneMinusSrcAlpha`としておき、RGBへのアルファ乗算は`frag`内で行うようにしてみました。
111
+ Exponentが1のとき...つまり通常のアルファブレンディングだと下図のようになりますが(さまざまなアルファ値のときにどう見えるかをご覧に入れようと思ってGIFにしたのですが、代償として階調数が落ちてしまいました)...
112
+
113
+ ![図1](0e8a20b69f38fb6b1bc688f14a2d442b.gif)
114
+
115
+ Exponentを8に上げると、半透明のときにRGBに乗算される値が実際のアルファよりも高めに引き上げられ、加算合成に近い結果になります。ですがアルファが0になると乗算値も0まで落ち込むので、アルファが0のときには完全透明になるというわけです。
116
+
117
+ ![図2](404b2c52d93d8ce1c7e9faa3c5d01f8d.gif)