質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

HLSL

HLSLは、米マイクロソフト社によって開発された Direct3D APIで使われるプロプライエタリなシェーディング言語です。

Q&A

解決済

1回答

1030閲覧

spriteの特定の高さ以下を描画しないShader

concern12

総合スコア18

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

HLSL

HLSLは、米マイクロソフト社によって開発された Direct3D APIで使われるプロプライエタリなシェーディング言語です。

0グッド

0クリップ

投稿2021/06/22 13:12

編集2021/06/22 13:16

spriteの特定の高さ(ローカル)以下を描画しないShaderを実装中なのですが、うまくいきません。

特定のuv.y以下を表示しないようにすることでspriteのSprite ModeがSingleの場合は思った通りに動作しますが、
Sprite ModeがMultipleであると、Textureの中でのuv値が参照され、以下のコードがうまくいきません。
スクリプトから対象のspriteのuv値渡してもらうというような手法ではなく、もう少しスマートな方法はありませんでしょうか?
よろしくお願いいたします。

ShaderLab

1Shader "Unlit/NewUnlitShader" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 _Height("Height", Range(0,1)) = 0.5 7 8 } 9 SubShader 10 { 11 Tags { "RenderType"="Opaque" } 12 LOD 100 13 Cull Off 14 15 16 Pass 17 { 18 CGPROGRAM 19 #pragma vertex vert 20 #pragma fragment frag 21 // make fog work 22 #pragma multi_compile_fog 23 24 #include "UnityCG.cginc" 25 26 struct appdata 27 { 28 float4 vertex : POSITION; 29 float2 uv : TEXCOORD0; 30 }; 31 32 struct v2f 33 { 34 float2 uv : TEXCOORD0; 35 UNITY_FOG_COORDS(1) 36 float4 vertex : SV_POSITION; 37 }; 38 39 sampler2D _MainTex; 40 float4 _MainTex_ST; 41 fixed _Height; 42 43 v2f vert (appdata v) 44 { 45 v2f o; 46 o.vertex = UnityObjectToClipPos(v.vertex); 47 o.uv = TRANSFORM_TEX(v.uv, _MainTex); 48 UNITY_TRANSFER_FOG(o,o.vertex); 49 return o; 50 } 51 52 fixed4 frag (v2f i) : SV_Target 53 { 54 clip(i.uv.y - _Height); 55 56 // sample the texture 57 fixed4 col = tex2D(_MainTex, i.uv); 58 // apply fog 59 UNITY_APPLY_FOG(i.fogCoord, col); 60 return col; 61 } 62 ENDCG 63 } 64 } 65} 66 67 68

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

安直かもしれませんが、下記のように頂点座標を頼りにしてみるのはどうでしょうかね?

ShaderLab

1Shader "Unlit/NewUnlitShader" 2{ 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 _Height ("Height", Range(0,1)) = 0.5 7 8 // プロパティを追加 9 _PivotY ("Pivot Y (Normalized)", Range(0,1)) = 0.5 10 _SizeY ("Sprite Height In Pixels", Int) = 128 11 _PixelsPerUnit ("Pixels Per Unit", Float) = 100.0 12 } 13 SubShader 14 { 15 // バッチングが有効だと、バッチング可能と判断されたスプライトが結合されて 16 // 単一のメッシュになるため、vertexの値が今回の目的には利用できなくなりますので 17 // タグに"DisableBatching"="True"を追加しました 18 Tags { "RenderType"="Opaque" "DisableBatching"="True" } 19 LOD 100 20 Cull Off 21 22 Pass 23 { 24 CGPROGRAM 25 #pragma vertex vert 26 #pragma fragment frag 27 // make fog work 28 #pragma multi_compile_fog 29 30 #include "UnityCG.cginc" 31 32 struct appdata 33 { 34 float4 vertex : POSITION; 35 float2 uv : TEXCOORD0; 36 }; 37 38 struct v2f 39 { 40 float2 uv : TEXCOORD0; 41 UNITY_FOG_COORDS(1) 42 float localY : TEXCOORD2; // 頂点ローカル座標伝達用の変数を追加 43 float4 vertex : SV_POSITION; 44 }; 45 46 sampler2D _MainTex; 47 float4 _MainTex_ST; 48 fixed _Height; 49 50 // プロパティの値を受け取る変数を追加 51 float _PivotY; 52 float _SizeY; 53 float _PixelsPerUnit; 54 55 // lerpの逆を行う関数を追加 56 inline float inverseLerp(float a, float b, float value) 57 { 58 return saturate((value - a) / (b - a)); 59 } 60 61 v2f vert (appdata v) 62 { 63 v2f o; 64 o.vertex = UnityObjectToClipPos(v.vertex); 65 o.uv = TRANSFORM_TEX(v.uv, _MainTex); 66 UNITY_TRANSFER_FOG(o,o.vertex); 67 o.localY = v.vertex.y; // フラグメントシェーダーに頂点ローカル座標のYを送り... 68 69 // あるいは、下記のようにこの時点で頂点座標を0~1にリマップしてしまってもいいでしょう 70 // 頂点ローカル座標そのものを送ると、それに合わせて_Heightの範囲も調整してやる必要があるでしょうが 71 // それだとインスペクターの表示が直感的でなく気に入らない...といったことがあるかもしれません 72 /* 73 float scale = _SizeY / _PixelsPerUnit; 74 o.localY = inverseLerp(0.0, scale, v.vertex.y + _PivotY * scale); 75 */ 76 77 return o; 78 } 79 80 fixed4 frag (v2f i) : SV_Target 81 { 82 // uv.yに代わって、 83 // clip(i.uv.y - _Height); 84 85 // localYでクリッピング 86 clip(i.localY - _Height); 87 88 // sample the texture 89 fixed4 col = tex2D(_MainTex, i.uv); 90 // apply fog 91 UNITY_APPLY_FOG(i.fogCoord, col); 92 return col; 93 } 94 ENDCG 95 } 96 } 97}

図

バッチングを強制的に切るよう設定してしまいましたので、多数のスプライトを一発のドローコールで描画できる...という利点は失われるのが弱点かもしれません。
とはいえ、ご質問者さんのおっしゃる「スクリプトから対象のspriteのuv値渡してもらう」みたいな方法をとるにしても、バッチングを切らせないようにするにはそれなりに工夫が必要そうな気配がします。
バッチングが効かないと困るようなヘビーな描画を行っているのでなければ、シンプルさを重視してバッチングは妥協してもいいかもしれません。

投稿2021/06/22 21:39

編集2021/06/24 12:13
Bongo

総合スコア10811

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

concern12

2021/06/23 15:24

ご回答ありがとうございます。 初歩的な質問かつ、少し本来の質問からそれてしまい大変恐縮なのですが、 コメントアウトされている 「// o.localY = v.vertex.y * 0.5 + 0.5;」 の部分の代わりとして、フラグメントシェーダー側で clip(i.localY * 0.5 + 0.5 - _Height); としても同じように動かないのはなぜなのでしょうか?
Bongo

2021/06/23 18:14

奇妙ですね...先ほど私の方でも「vert側でo.localY = v.vertex.y;、frag側でclip(i.localY * 0.5 + 0.5 - _Height);」というのを試してみましたが、「vert側でo.localY = v.vertex.y * 0.5 + 0.5;、frag側でclip(i.localY - _Height);」の場合と同じ描画結果のように見えました。 私の場合はキャラクターのアニメーションのコマが縦横に並べられたよくあるテクスチャを使い、それをSprite Editor上のSliceメニューからAutomaticで自動分割したり、Grid By Cell Countで縦横にさいの目切りしてみたりしたもので試したのですが、もしかするとスプライトの分割のしかた、あるいはインポート設定によっては正しく動かなくなる条件を見落としてしまったかもしれません。 ご質問者さんのスプライトはどのように設定されているでしょうかね?Sprite Editorとかインスペクターの様子をご提示いただければ、私の方でも結果が食い違う現象を再現できるかもしれません。そうすれば、可能であれば原因を調べてみようと思います。
concern12

2021/06/24 04:13 編集

ご返信ありがとうございます! 「o.localY = v.vertex.y * 0.5 + 0.5;」のリマップをfragの方で行うと表示が異なる件ですが、 理由は不明ですが起こらなくなりました。失礼いたしました(見間違えていたのだと思います)。 ただ、「o.localY = v.vertex.y * 0.5 + 0.5;」のリマップを行うと、 表示的にどうやら私の方だと頂点座標が-1~1ではなく、-0.5~0.5となっているらしく、 o.localYに代入されるのが、0.25~0.75となり _Heightが0.25以上でクリップされるようになっていしまいます。 頂点座標が-0.5~0.5となる原因(要因)をもしご存知であれば教えてくださると幸いです。 使用画像はAssetsフォルダ上で右クリック->Creates->Sprites->Squareで生成された四角Textureの ImportSettingsのSpriteModeをSingleにしたものを使用しており、それ以外は一切弄っておりません(画像サイズ4x4、Pixel per unit 4)。
Bongo

2021/06/24 12:09

的確なツッコミありがとうございます。白状しますと、私が試した場合では0.18でスプライトの下端、0.83で上端となり、どうやらメッシュの原点についてはピボットに依存(デフォルトのCenterならメッシュの原点も中心)するらしいものの、あの数値から上端・下端がどのように決定されるのか想像できなかったのです。 Unityユーザーからは見えないところで謎の法則によって決定されていて知ることはできないのかもしれない...などと考え、大まかに調整できれば十分だろうと思って、恣意的に-1~1を0~1にマッピングしました。 ご質問者さんのご指摘を受けまして、なにかお答えせねばと思い観察しなおしてみたところ、どうやらスプライトのピクセル単位の高さとPixels Per Unitを絡めれば算出できそうな感じでした(私の場合はPixels Per Unitが100、スプライトの高さが128の状態だったので、シーン上におけるスプライトの高さは1.28となり、メッシュもそのようになっていると仮定すると説明ができそうでした)。 回答のコードを差し替えましたが、あれならどうでしょうか。結局_PivotY、_SizeY、_PixelsPerUnitの3つのプロパティを追加することになってしまいすみません。おそらく、さすがにあれらの値についてはUnity組み込みの変数だとかはないでしょうから、独自のプロパティとして与えてやる必要があるんじゃないかと思います。スプライトのピボット、サイズ、Pixels Per Unitがみんな同じなのでしたらマテリアルのインスペクター上で共通の値をセットしてやればいいでしょうが、スプライト毎にバラバラな場合はスプライトに応じてそれぞれ適切な値をセットしてやることになりますので、ご質問者さんのおっしゃったUV値を個別に与えてやる方法と大差ない手間になってしまうでしょう...
concern12

2021/06/25 01:53

詳しく教えてくださりありがとうございます。 新しく更新してくださったコードでうまくいきました。 特にPivotが影響してくることは盲点でした。 色々とこんがらがっていた部分が解決しました。 ご回答ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問