回答編集履歴
5
初期テクスチャサイズが1の時エラーを起こすため、縮小ループをdo-whileからwhileに変更
answer
CHANGED
@@ -102,7 +102,7 @@
|
|
102
102
|
this.material.SetFloat(this.referenceColorThresholdId, this.referenceColorThreshold);
|
103
103
|
Graphics.Blit(src, previousLevelTexture, this.material, 0); // パス0...入力イメージから目的色を抽出し、結果をlevel0TextureSize四方のテクスチャに出力
|
104
104
|
|
105
|
-
|
105
|
+
while (scaledSize > 1)
|
106
106
|
{
|
107
107
|
scaledSize >>= 1;
|
108
108
|
|
@@ -112,7 +112,6 @@
|
|
112
112
|
RenderTexture.ReleaseTemporary(previousLevelTexture);
|
113
113
|
previousLevelTexture = scaledTexture;
|
114
114
|
}
|
115
|
-
while (scaledSize > 1);
|
116
115
|
|
117
116
|
var currentActiveTexture = RenderTexture.active;
|
118
117
|
|
4
他環境での不具合を修正
answer
CHANGED
@@ -21,6 +21,9 @@
|
|
21
21
|
|
22
22
|
※余談ですが、「シェーダーで音を鳴らす」のではなく「シェーダーで音データを加工する」ケースはあり得ると思います。RGB画像は3チャンネル2次元の波、ステレオ音声は2チャンネル1次元の波だと思えば、画像加工も音声加工も似たようなことをやっている気がしませんかね?
|
23
23
|
|
24
|
+
[追記]
|
25
|
+
当初のカメラスクリプトではテクスチャ生成時にテクスチャフォーマットを指定していましたが、それをやめてサイズだけ指定するようにしました(最初のコードはMac版OpenGL上でしか動作確認していなかったのですが、後で試したらMetalやWindows版で正しい結果が得られませんでした...)。また併せて、シェーダーコードで返していたフラグメントの色を`fixed4(result, 0.0, 0.0, 1.0)`から`fixed4(result, result, result, 1.0)`に変えました。動作上は変える必要はないのですが、縮小過程をフレームデバッガで見た時に、前者だと目的色部分が赤色になってしまいます。上記のコード概要説明では抽出結果を白だの黒だのと表現していますので、それに合わせるようにしてみました。
|
26
|
+
|
24
27
|
- カメラのスクリプト
|
25
28
|
```C#
|
26
29
|
using UnityEngine;
|
@@ -89,11 +92,11 @@
|
|
89
92
|
|
90
93
|
if (this.queryResultTexture == null)
|
91
94
|
{
|
92
|
-
this.queryResultTexture = new Texture2D(1, 1
|
95
|
+
this.queryResultTexture = new Texture2D(1, 1);
|
93
96
|
}
|
94
97
|
|
95
98
|
var scaledSize = this.level0TextureSize;
|
96
|
-
var previousLevelTexture = RenderTexture.GetTemporary(scaledSize, scaledSize
|
99
|
+
var previousLevelTexture = RenderTexture.GetTemporary(scaledSize, scaledSize);
|
97
100
|
|
98
101
|
this.material.SetColor(this.referenceColorId, this.referenceColor);
|
99
102
|
this.material.SetFloat(this.referenceColorThresholdId, this.referenceColorThreshold);
|
@@ -103,7 +106,7 @@
|
|
103
106
|
{
|
104
107
|
scaledSize >>= 1;
|
105
108
|
|
106
|
-
var scaledTexture = RenderTexture.GetTemporary(scaledSize, scaledSize
|
109
|
+
var scaledTexture = RenderTexture.GetTemporary(scaledSize, scaledSize);
|
107
110
|
|
108
111
|
Graphics.Blit(previousLevelTexture, scaledTexture, this.material, 1); // パス1...抽出結果を段階的に1ピクセル四方まで縮小
|
109
112
|
RenderTexture.ReleaseTemporary(previousLevelTexture);
|
@@ -168,101 +171,101 @@
|
|
168
171
|
```
|
169
172
|
Shader "Hidden/Color Extractor"
|
170
173
|
{
|
171
|
-
|
174
|
+
Properties
|
172
|
-
|
175
|
+
{
|
173
|
-
|
176
|
+
_MainTex ("Texture", 2D) = "white" {}
|
174
|
-
|
177
|
+
_ReferenceColor ("Reference Color", Color) = (1.0, 0.0, 0.0, 1.0)
|
175
|
-
|
178
|
+
_ReferenceColorThreshold ("Reference Color Threshold", Range(0.0, 1.0)) = 0.5
|
176
|
-
|
179
|
+
}
|
177
|
-
|
178
|
-
SubShader
|
179
|
-
{
|
180
|
-
Cull Off ZWrite Off ZTest Always
|
181
180
|
|
182
|
-
// 抽出パス
|
183
|
-
|
181
|
+
SubShader
|
184
|
-
|
182
|
+
{
|
185
|
-
CGPROGRAM
|
186
|
-
#pragma vertex vert
|
187
|
-
#pragma fragment frag
|
188
|
-
|
189
|
-
|
183
|
+
Cull Off ZWrite Off ZTest Always
|
190
184
|
|
191
|
-
|
185
|
+
// 抽出パス
|
186
|
+
Pass
|
192
|
-
|
187
|
+
{
|
188
|
+
CGPROGRAM
|
193
|
-
|
189
|
+
#pragma vertex vert
|
194
|
-
|
190
|
+
#pragma fragment frag
|
195
|
-
};
|
196
191
|
|
197
|
-
struct v2f
|
198
|
-
{
|
199
|
-
float2 uv : TEXCOORD0;
|
200
|
-
|
192
|
+
#include "UnityCG.cginc"
|
201
|
-
};
|
202
193
|
|
203
|
-
|
194
|
+
struct appdata
|
195
|
+
{
|
204
|
-
|
196
|
+
float4 vertex : POSITION;
|
205
|
-
|
197
|
+
float2 uv : TEXCOORD0;
|
198
|
+
};
|
206
199
|
|
207
|
-
|
200
|
+
struct v2f
|
208
|
-
|
201
|
+
{
|
209
|
-
v2f o;
|
210
|
-
o.vertex = UnityObjectToClipPos(v.vertex);
|
211
|
-
|
202
|
+
float2 uv : TEXCOORD0;
|
212
|
-
|
203
|
+
float4 vertex : SV_POSITION;
|
213
|
-
|
204
|
+
};
|
214
205
|
|
206
|
+
sampler2D _MainTex;
|
215
|
-
|
207
|
+
float4 _ReferenceColor;
|
216
|
-
{
|
217
|
-
|
208
|
+
float _ReferenceColorThreshold;
|
218
|
-
float result = sign(max(_ReferenceColorThreshold - length(_ReferenceColor.rgb - tex2D(_MainTex, i.uv).rgb), 0.0));
|
219
209
|
|
210
|
+
v2f vert(appdata v)
|
211
|
+
{
|
212
|
+
v2f o;
|
220
|
-
|
213
|
+
o.vertex = UnityObjectToClipPos(v.vertex);
|
214
|
+
o.uv = v.uv;
|
215
|
+
return o;
|
221
|
-
|
216
|
+
}
|
222
|
-
ENDCG
|
223
|
-
}
|
224
217
|
|
225
|
-
|
218
|
+
fixed4 frag(v2f i) : SV_Target
|
226
|
-
Pass
|
227
|
-
|
219
|
+
{
|
228
|
-
CGPROGRAM
|
229
|
-
#pragma vertex vert
|
230
|
-
#pragma fragment frag
|
231
|
-
|
232
|
-
|
220
|
+
// ピクセル色と目的色の距離がしきい値未満なら1、さもなくば0
|
221
|
+
float result = sign(max(_ReferenceColorThreshold - length(_ReferenceColor.rgb - tex2D(_MainTex, i.uv).rgb), 0.0));
|
233
222
|
|
234
|
-
struct appdata
|
235
|
-
{
|
236
|
-
|
223
|
+
return fixed4(result, result, result, 1.0);
|
237
|
-
float2 uv : TEXCOORD0;
|
238
|
-
|
224
|
+
}
|
225
|
+
ENDCG
|
226
|
+
}
|
239
227
|
|
240
|
-
|
228
|
+
// 縮小パス
|
229
|
+
Pass
|
241
|
-
|
230
|
+
{
|
242
|
-
|
231
|
+
CGPROGRAM
|
243
|
-
|
232
|
+
#pragma vertex vert
|
244
|
-
|
233
|
+
#pragma fragment frag
|
245
234
|
|
246
|
-
|
235
|
+
#include "UnityCG.cginc"
|
247
236
|
|
248
|
-
|
237
|
+
struct appdata
|
249
|
-
|
238
|
+
{
|
250
|
-
v2f o;
|
251
|
-
|
239
|
+
float4 vertex : POSITION;
|
252
|
-
|
240
|
+
float2 uv : TEXCOORD0;
|
253
|
-
return o;
|
254
|
-
|
241
|
+
};
|
255
242
|
|
256
|
-
|
243
|
+
struct v2f
|
257
|
-
|
244
|
+
{
|
258
|
-
|
245
|
+
float2 uv : TEXCOORD0;
|
259
|
-
|
246
|
+
float4 vertex : SV_POSITION;
|
247
|
+
};
|
260
248
|
|
249
|
+
sampler2D _MainTex;
|
250
|
+
|
251
|
+
v2f vert(appdata v)
|
252
|
+
{
|
253
|
+
v2f o;
|
261
|
-
|
254
|
+
o.vertex = UnityObjectToClipPos(v.vertex);
|
255
|
+
o.uv = v.uv;
|
256
|
+
return o;
|
262
|
-
|
257
|
+
}
|
258
|
+
|
259
|
+
fixed4 frag(v2f i) : SV_Target
|
260
|
+
{
|
261
|
+
// 近傍4テクセルの中心からサンプリング、ピクセル色が0より大きければ(1のテクセルが1つ以上あれば)1、さもなくば0
|
262
|
+
float result = sign(tex2D(_MainTex, i.uv).r);
|
263
|
+
|
264
|
+
return fixed4(result, result, result, 1.0);
|
265
|
+
}
|
263
|
-
|
266
|
+
ENDCG
|
264
|
-
|
267
|
+
}
|
265
|
-
|
268
|
+
}
|
266
269
|
}
|
267
270
|
```
|
268
271
|
|
3
マテリアルをHideFlags.DontSave指定する必要はなかった気がしたので削除
answer
CHANGED
@@ -83,7 +83,6 @@
|
|
83
83
|
if (this.material == null)
|
84
84
|
{
|
85
85
|
this.material = new Material(Shader.Find("Hidden/Color Extractor"));
|
86
|
-
this.material.hideFlags = HideFlags.DontSave;
|
87
86
|
this.referenceColorId = Shader.PropertyToID("_ReferenceColor");
|
88
87
|
this.referenceColorThresholdId = Shader.PropertyToID("_ReferenceColorThreshold");
|
89
88
|
}
|
2
リファレンスのリンク先を修正
answer
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
自身の勉強も兼ねて、下記のような方法での色判定を試してみました。
|
12
12
|
|
13
13
|
- 画面をレンダリングする。天球画像の代用としてシーンに赤い球を配置し、カメラに赤色が写り込んでいるかを判定することにした。
|
14
|
-
- [ポストプロセッシングエフェクト](https://docs.unity3d.com/Manual/PostProcessingWritingEffects.html)のやり方を参考に、カメラにアタッチしたスクリプトの[OnRenderImage](https://docs.unity3d.com/ScriptReference/
|
14
|
+
- [ポストプロセッシングエフェクト](https://docs.unity3d.com/Manual/PostProcessingWritingEffects.html)のやり方を参考に、カメラにアタッチしたスクリプトの[OnRenderImage](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnRenderImage.html)内で色判定処理を行う。
|
15
15
|
- レンダリング結果を適当な2の冪乗サイズの一時レンダーテクスチャに写す。この時色判定を行い、目的の色であれば白、そうでなければ黒として写す。
|
16
16
|
※色判定はピクセル色と目的色の距離が一定以下なら真とすることにしましたが、他にも色相の一致度を見るなどでもいいと思います。
|
17
17
|
- 先の白黒画像を縦横1/2の一時レンダーテクスチャに写す。この時、白黒画像からサンプリングした色が真っ黒でなければ、サンプリングされた4テクセルの内1つ以上白テクセルがあるものと考え、出力する色を白とする。そうでなければ黒とする。
|
1
リンクを追加、機能名を訂正
answer
CHANGED
@@ -271,6 +271,6 @@
|
|
271
271
|
|
272
272
|

|
273
273
|
|
274
|
-
- フレームデバッ
|
274
|
+
- [フレームデバッガ](https://docs.unity3d.com/Manual/FrameDebugger.html)で見た描画の過程
|
275
275
|
|
276
|
-

|