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

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

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

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

Q&A

解決済

1回答

1096閲覧

Unity シェーダー 頂点を引き伸ばす

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

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

0グッド

0クリップ

投稿2020/03/06 16:09

編集2020/03/11 06:24

前提・実現したいこと

描画しているメッシュの頂点をシェーダーで引き延ばしたい

該当のソースコード

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.EventSystems; 5 6public class PlacementDraw : MonoBehaviour 7{ 8 public Material material; 9 Mesh mesh; 10 List<Vector2> ObjectPositionList = new List<Vector2>(); 11 public Placement.StateType stateType; 12 // Start is called before the first frame update 13 void Start() 14 { 15 mesh = new Mesh(); 16 mesh.vertices = new Vector3[] { 17 new Vector3 (0, 0, 0), 18 new Vector3 (0f, 1f, 0), 19 new Vector3 (1f, 0f, 0), 20 new Vector3 (1f, 1f, 0), 21 }; 22 23 mesh.uv = new Vector2[] { 24 new Vector2 (0f, 0f), 25 new Vector2 (0f, 1f), 26 new Vector2 (1f, 0f), 27 new Vector2 (1f, 1f), 28 }; 29 30 mesh.triangles = new int[] { 31 0, 1, 2, 32 1, 3, 2, 33 }; 34 35 mesh.RecalculateNormals(); 36 mesh.RecalculateBounds(); 37 } 38 39 // Update is called once per frame 40 void Update() 41 { 42 PlacementObject(); 43 for (int i = 0; i < ObjectPositionList.Count; i++) 44 { 45 Graphics.DrawMesh(mesh, ObjectPositionList[i], Quaternion.identity, material, 0); 46 } 47 } 48 void PlacementObject() 49 { 50 var pos = Camera.main.ScreenToWorldPoint(Input.mousePosition); 51 var x = Mathf.FloorToInt(pos.x); 52 var y = Mathf.FloorToInt(pos.y); 53 var pos2 = new Vector2(x, y); 54 Placement placement = GetComponent<Placement>(); 55 if (Input.GetMouseButton(0) && stateType == placement.state) 56 { 57 if (EventSystem.current.IsPointerOverGameObject()) 58 { 59 return; 60 } 61 ObjectPositionList.Add(pos2); 62 } 63 } 64} 65

ShaderLab

1Shader "Unlit/StencilObject" 2{ 3 Properties 4 { 5 [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} 6 _Color ("Tint", Color) = (1,1,1,1) 7 [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0 8 } 9 10 SubShader 11 { 12 Tags 13 { 14 "Queue"="Transparent" 15 "IgnoreProjector"="True" 16 "RenderType"="Transparent" 17 "PreviewType"="Plane" 18 "CanUseSpriteAtlas"="True" 19 } 20 21 /*Stencil 22 { 23 Ref 1 24 Comp equal 25 }*/ 26 27 Cull Off 28 Lighting Off 29 ZWrite Off 30 Blend One OneMinusSrcAlpha 31 32 Pass 33 { 34 CGPROGRAM 35 #pragma vertex vert 36 #pragma fragment frag 37 #pragma multi_compile _ PIXELSNAP_ON 38 #include "UnityCG.cginc" 39 40 struct appdata_t 41 { 42 float4 vertex : POSITION; 43 float4 color : COLOR; 44 float2 texcoord : TEXCOORD0; 45 }; 46 47 struct v2f 48 { 49 float4 vertex : SV_POSITION; 50 fixed4 color : COLOR; 51 float2 texcoord : TEXCOORD0; 52 }; 53 54 fixed4 _Color; 55 56 v2f vert(appdata_t IN) 57 { 58 v2f OUT; 59 OUT.vertex = UnityObjectToClipPos(IN.vertex); 60 OUT.texcoord = IN.texcoord; 61 OUT.color = IN.color * _Color; 62 #ifdef PIXELSNAP_ON 63 OUT.vertex = UnityPixelSnap (OUT.vertex); 64 #endif 65 66 return OUT; 67 } 68 69 sampler2D _MainTex; 70 sampler2D _AlphaTex; 71 float _AlphaSplitEnabled; 72 73 fixed4 SampleSpriteTexture (float2 uv) 74 { 75 fixed4 color = tex2D (_MainTex, uv); 76 77#if UNITY_TEXTURE_ALPHASPLIT_ALLOWED 78 if (_AlphaSplitEnabled) 79 color.a = tex2D (_AlphaTex, uv).r; 80#endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED 81 82 return color; 83 } 84 85 fixed4 frag(v2f IN) : SV_Target 86 { 87 fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color; 88 c.rgb *= c.a; 89 return c; 90 } 91 ENDCG 92 } 93 } 94}

追加スクリプト

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class PlacementShadow : MonoBehaviour 6{ 7 public Material material; 8 Mesh mesh; 9 List<Vector2> ObjectPositionList = new List<Vector2>(); 10 // Start is called before the first frame update 11 void Start() 12 { 13 mesh = new Mesh(); 14 mesh.vertices = new Vector3[] 15 { 16 new Vector3(0f,0f,0f), 17 new Vector3(0f,1f,0f), 18 new Vector3(1f,0f,0f), 19 20 new Vector3(0f,1f,1f), 21 new Vector3(1f,0f,1f), 22 new Vector3(1f,1f,1f), 23 }; 24 mesh.uv = new Vector2[] 25 { 26 new Vector2(0f,0f), 27 new Vector2(0f,1f), 28 new Vector2(1f,0f), 29 new Vector2(0f,1f), 30 new Vector2(1f,0f), 31 new Vector2(1f,1f), 32 }; 33 mesh.triangles = new int[] 34 { 35 0,1,2, 36 37 3,2,1, 38 2,3,4, 39 40 5,4,3, 41 }; 42 mesh.RecalculateBounds(); 43 mesh.RecalculateNormals(); 44 } 45 46 // Update is called once per frame 47 void Update() 48 { 49 Placement(); 50 for(int i = 0;i < ObjectPositionList.Count; i++) 51 { 52 Graphics.DrawMesh(mesh,Vector3.zero, Quaternion.identity, material, 0); 53 } 54 } 55 void Placement() 56 { 57 var pos = Camera.main.ScreenToWorldPoint(Input.mousePosition); 58 var x = Mathf.FloorToInt(pos.x); 59 var y = Mathf.FloorToInt(pos.y); 60 var pos2 = new Vector2(x, y); 61 if (Input.GetMouseButton(0)) 62 { 63 ObjectPositionList.Add(pos2); 64 } 65 } 66} 67

試したこと

イメージ説明
イメージ説明
正方形に描画しているメッシュの3つの頂点を引き伸ばして、ボリュームシャドウのようにしたかったのですが、どうすればシェーダーで描画しているメッシュの頂点をいじれるのか、調べても分かりませんでした。
どのようにすればシェーダーでverticesを変更することができますか?
回答お願いします。

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

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

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

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

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

Bongo

2020/03/07 23:19

ご提示いただいた図はどういう状況なのでしょうか? もし試行錯誤した結果の失敗図なのでしたら、他にも外部画像処理ソフトで模擬的な理想図を描いていただいた方がいいかもしれません。
退会済みユーザー

退会済みユーザー

2020/03/08 02:37

添付した画像は理想図です
guest

回答1

0

ベストアンサー

ご参考にされたサイトの「ボリュームシャドウ」の方に言及がありますが、正方形のような単純な形状をそのまま引き伸ばしたのでは六角形の影に変形させることはできないかと思います。

さいわい今回は単純な正方形ですので、正方形に特化したシンプルな加工ができそうです。
プランとしては、まず正方形を固定側と可動側の2つの三角形に分け、それらの間には2つをつなぐように面を張っておきます。
そしてシェーダー内では、引き伸ばし方向に応じて正方形を90°ずつ回転させることで引き伸ばしたい方向へ可動側三角形が向くようにしてみました。

PlacementDrawStartを下記のように変更しました。

C#

1 // Start is called before the first frame update 2 void Start() 3 { 4 mesh = new Mesh(); 5 mesh.vertices = new Vector3[] { 6 // 左下の三角形と... 7 new Vector3 (0f, 0f, 0f), 8 new Vector3 (0f, 1f, 0f), 9 new Vector3 (1f, 0f, 0f), 10 11 // 右上の三角形に分ける 12 // さらに、使用していないZ成分を固定側か可動側かを 13 // 区別するための目印として使うことにし、右上三角形の 14 // Zを1にしておく 15 new Vector3 (0f, 1f, 1f), 16 new Vector3 (1f, 0f, 1f), 17 new Vector3 (1f, 1f, 1f), 18 }; 19 20 mesh.uv = new Vector2[] { 21 // UVも頂点数に合わせて6つに増やす 22 new Vector2 (0f, 0f), 23 new Vector2 (0f, 1f), 24 new Vector2 (1f, 0f), 25 new Vector2 (0f, 1f), 26 new Vector2 (1f, 0f), 27 new Vector2 (1f, 1f), 28 }; 29 30 mesh.triangles = new int[] { 31 // 左下三角形 32 0, 1, 2, 33 34 // 2つの三角形をつなぐ長方形 35 3, 2, 1, 36 2, 3, 4, 37 38 // 右上三角形 39 5, 4, 3, 40 }; 41 42 mesh.RecalculateNormals(); 43 mesh.RecalculateBounds(); 44 }

シェーダー側は下記のようにしてみました。
ご提示のコードはスプライト用のものをベースにしているご様子で、若干複雑な記述になっていましたが、DrawMeshで使う分にはもっとシンプルでよさそうに思いましたので、記述をいくらか掃除してあります。

ShaderLab

1Shader "Unlit/SquareShadow" 2{ 3 Properties 4 { 5 _Color ("Shadow Color", Color) = (1,1,1,1) 6 _Angle ("Shadow Angle", Range(0.0, 360.0)) = 210.0 7 _Distance ("Shadow Distance", Range(0.0, 5.0)) = 2.0 8 } 9 10 SubShader 11 { 12 Tags 13 { 14 "Queue"="Transparent" 15 "IgnoreProjector"="True" 16 "RenderType"="Transparent" 17 "PreviewType"="Plane" 18 } 19 20 Cull Off 21 Lighting Off 22 ZWrite Off 23 Blend SrcAlpha OneMinusSrcAlpha 24 25 Pass 26 { 27 // すでに影を描画済みの部分には描画させないようにすることで、 28 // 影が重なったときに色が濃くなってしまうのを防ぐ 29 Stencil 30 { 31 Ref 1 32 ReadMask 1 33 WriteMask 1 34 Comp Greater 35 Pass Replace 36 } 37 38 CGPROGRAM 39 #pragma vertex vert 40 #pragma fragment frag 41 #include "UnityCG.cginc" 42 43 struct appdata_t 44 { 45 float4 vertex : POSITION; 46 }; 47 48 struct v2f 49 { 50 float4 vertex : SV_POSITION; 51 }; 52 53 fixed4 _Color; 54 float _Angle; 55 float _Distance; 56 57 v2f vert(appdata_t IN) 58 { 59 v2f OUT; 60 61 // まず、引き伸ばし方向を指す単位ベクトルを作る 62 float2 direction; 63 sincos(_Angle * UNITY_PI / 180.0, direction.y, direction.x); 64 65 // 引き伸ばし方向の成分の符号を求め... 66 float2 directionSign = sign(direction); 67 68 // 単純化のため、符号が0ならとりあえず1とし... 69 directionSign += 1.0 - abs(directionSign); 70 71 // 2つの軸に分け... 72 float2 axisX = float2(directionSign.x, 0.0); 73 float2 axisY = float2(0.0, directionSign.y); 74 75 // 符号の積を求めて第1・3象限(+1)か第2・4象限(-1)かを調べ... 76 float orthantSign = directionSign.x * directionSign.y; 77 78 // 象限に応じて軸を選び、それを使って元の頂点座標を(0.5, 0.5)を中心に回転させる 79 IN.vertex.xy = mul(IN.vertex.xy - 0.5, orthantSign > 0 ? float2x2(axisX, axisY) : float2x2(axisY, axisX)) + 0.5; 80 81 // 可動側の三角形をdirectionの向きに_Distanceだけずらす 82 IN.vertex.xy += (IN.vertex.z * _Distance) * direction; 83 84 // 可動側判定に使ったZ成分はもう不要なので0に変える 85 IN.vertex.z = 0.0; 86 87 OUT.vertex = UnityObjectToClipPos(IN.vertex); 88 89 return OUT; 90 } 91 92 fixed4 frag(v2f IN) : SV_Target 93 { 94 return _Color; 95 } 96 ENDCG 97 } 98 } 99}

図

こんな感じで影を描いた後、さらにその上に通常のシェーダーで本来の画像を描画すれば画像が影を落としているように見えるんじゃないかと思います。

投稿2020/03/08 08:41

Bongo

総合スコア10811

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

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

退会済みユーザー

退会済みユーザー

2020/03/08 14:17

回答ありがとうございました。いつも参考になります。
退会済みユーザー

退会済みユーザー

2020/03/11 06:26

ベストアンサー済みにしてから追記して申し訳ありません。 追加したスクリプトのようにしてメッシュを描画し、マテリアルのインスペクタをいじると、象限ごとにメッシュが瞬間移動したような動きになってしまいます。
Bongo

2020/03/11 09:41

象限をまたぐと位置が飛ぶということは、90°回転の部分に何か見落としがあったのかもしれません。のちほど調べてみます。 おうかがいしますが、スクリプト側はご質問文に追記いただいた形(Startのメッシュ生成部分を変更、DrawMesh時の位置はObjectPositionListは使わずVector3.zeroとする)で、シェーダー側は私が回答内に提示しましたものということでいいでしょうか。もしシェーダー側のコードが私のものと全く同じならけっこうですが、もし何らかのアレンジが加わっているようでしたら念のためシェーダーコードもご提示いただけるとありがたいです。
退会済みユーザー

退会済みユーザー

2020/03/11 10:01

すみません。瞬間移動したような動きになるのは、DrawMesh時の位置がObjectPositionList[i]の時でした。シェーダーコードは全く同じです。Vector3.zeroなら正常に動作します。
Bongo

2020/03/11 22:37

Vector3.zeroだと大丈夫でObjectPositionList[i]だとずれるとなるといよいよもって謎ですね...すみませんがまだその現象を再現できていません。 Vector3.zeroだとずれないのなら、おそらくメッシュに異常はないんじゃないかと思われます。DrawMesh時の位置が違う場合にずれるとなると、たとえば(0, 0, 0)と(1, 0, 0)と(0, 1, 0)のような3地点に描画させた場合、Angleを回転させると(0, 0, 0)だけがずれなくて(1, 0, 0)と(0, 1, 0)は瞬間移動してしまう感じでしょうか。 たびたびすみませんが、上記の3地点に描画させて動かした場合の映像を撮影していただけませんでしょうか。もしかすると瞬間移動するときの位置の飛び方が手がかりになるかもしれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問