Unity シェーダー 頂点を引き伸ばす
- 評価
- クリップ 0
- VIEW 563

退会済みユーザー
前提・実現したいこと
描画しているメッシュの頂点をシェーダーで引き延ばしたい
該当のソースコード
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class PlacementDraw : MonoBehaviour
{
public Material material;
Mesh mesh;
List<Vector2> ObjectPositionList = new List<Vector2>();
public Placement.StateType stateType;
// Start is called before the first frame update
void Start()
{
mesh = new Mesh();
mesh.vertices = new Vector3[] {
new Vector3 (0, 0, 0),
new Vector3 (0f, 1f, 0),
new Vector3 (1f, 0f, 0),
new Vector3 (1f, 1f, 0),
};
mesh.uv = new Vector2[] {
new Vector2 (0f, 0f),
new Vector2 (0f, 1f),
new Vector2 (1f, 0f),
new Vector2 (1f, 1f),
};
mesh.triangles = new int[] {
0, 1, 2,
1, 3, 2,
};
mesh.RecalculateNormals();
mesh.RecalculateBounds();
}
// Update is called once per frame
void Update()
{
PlacementObject();
for (int i = 0; i < ObjectPositionList.Count; i++)
{
Graphics.DrawMesh(mesh, ObjectPositionList[i], Quaternion.identity, material, 0);
}
}
void PlacementObject()
{
var pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
var x = Mathf.FloorToInt(pos.x);
var y = Mathf.FloorToInt(pos.y);
var pos2 = new Vector2(x, y);
Placement placement = GetComponent<Placement>();
if (Input.GetMouseButton(0) && stateType == placement.state)
{
if (EventSystem.current.IsPointerOverGameObject())
{
return;
}
ObjectPositionList.Add(pos2);
}
}
}
Shader "Unlit/StencilObject"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
/*Stencil
{
Ref 1
Comp equal
}*/
Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile _ PIXELSNAP_ON
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
fixed4 _Color;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap (OUT.vertex);
#endif
return OUT;
}
sampler2D _MainTex;
sampler2D _AlphaTex;
float _AlphaSplitEnabled;
fixed4 SampleSpriteTexture (float2 uv)
{
fixed4 color = tex2D (_MainTex, uv);
#if UNITY_TEXTURE_ALPHASPLIT_ALLOWED
if (_AlphaSplitEnabled)
color.a = tex2D (_AlphaTex, uv).r;
#endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED
return color;
}
fixed4 frag(v2f IN) : SV_Target
{
fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
c.rgb *= c.a;
return c;
}
ENDCG
}
}
}
追加スクリプト
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlacementShadow : MonoBehaviour
{
public Material material;
Mesh mesh;
List<Vector2> ObjectPositionList = new List<Vector2>();
// Start is called before the first frame update
void Start()
{
mesh = new Mesh();
mesh.vertices = new Vector3[]
{
new Vector3(0f,0f,0f),
new Vector3(0f,1f,0f),
new Vector3(1f,0f,0f),
new Vector3(0f,1f,1f),
new Vector3(1f,0f,1f),
new Vector3(1f,1f,1f),
};
mesh.uv = new Vector2[]
{
new Vector2(0f,0f),
new Vector2(0f,1f),
new Vector2(1f,0f),
new Vector2(0f,1f),
new Vector2(1f,0f),
new Vector2(1f,1f),
};
mesh.triangles = new int[]
{
0,1,2,
3,2,1,
2,3,4,
5,4,3,
};
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
// Update is called once per frame
void Update()
{
Placement();
for(int i = 0;i < ObjectPositionList.Count; i++)
{
Graphics.DrawMesh(mesh,Vector3.zero, Quaternion.identity, material, 0);
}
}
void Placement()
{
var pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
var x = Mathf.FloorToInt(pos.x);
var y = Mathf.FloorToInt(pos.y);
var pos2 = new Vector2(x, y);
if (Input.GetMouseButton(0))
{
ObjectPositionList.Add(pos2);
}
}
}
試したこと
正方形に描画しているメッシュの3つの頂点を引き伸ばして、ボリュームシャドウのようにしたかったのですが、どうすればシェーダーで描画しているメッシュの頂点をいじれるのか、調べても分かりませんでした。
どのようにすればシェーダーでverticesを変更することができますか?
回答お願いします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
ご参考にされたサイトの「ボリュームシャドウ」の方に言及がありますが、正方形のような単純な形状をそのまま引き伸ばしたのでは六角形の影に変形させることはできないかと思います。
さいわい今回は単純な正方形ですので、正方形に特化したシンプルな加工ができそうです。
プランとしては、まず正方形を固定側と可動側の2つの三角形に分け、それらの間には2つをつなぐように面を張っておきます。
そしてシェーダー内では、引き伸ばし方向に応じて正方形を90°ずつ回転させることで引き伸ばしたい方向へ可動側三角形が向くようにしてみました。
PlacementDraw
のStart
を下記のように変更しました。
// Start is called before the first frame update
void Start()
{
mesh = new Mesh();
mesh.vertices = new Vector3[] {
// 左下の三角形と...
new Vector3 (0f, 0f, 0f),
new Vector3 (0f, 1f, 0f),
new Vector3 (1f, 0f, 0f),
// 右上の三角形に分ける
// さらに、使用していないZ成分を固定側か可動側かを
// 区別するための目印として使うことにし、右上三角形の
// Zを1にしておく
new Vector3 (0f, 1f, 1f),
new Vector3 (1f, 0f, 1f),
new Vector3 (1f, 1f, 1f),
};
mesh.uv = new Vector2[] {
// UVも頂点数に合わせて6つに増やす
new Vector2 (0f, 0f),
new Vector2 (0f, 1f),
new Vector2 (1f, 0f),
new Vector2 (0f, 1f),
new Vector2 (1f, 0f),
new Vector2 (1f, 1f),
};
mesh.triangles = new int[] {
// 左下三角形
0, 1, 2,
// 2つの三角形をつなぐ長方形
3, 2, 1,
2, 3, 4,
// 右上三角形
5, 4, 3,
};
mesh.RecalculateNormals();
mesh.RecalculateBounds();
}
シェーダー側は下記のようにしてみました。
ご提示のコードはスプライト用のものをベースにしているご様子で、若干複雑な記述になっていましたが、DrawMesh
で使う分にはもっとシンプルでよさそうに思いましたので、記述をいくらか掃除してあります。
Shader "Unlit/SquareShadow"
{
Properties
{
_Color ("Shadow Color", Color) = (1,1,1,1)
_Angle ("Shadow Angle", Range(0.0, 360.0)) = 210.0
_Distance ("Shadow Distance", Range(0.0, 5.0)) = 2.0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
}
Cull Off
Lighting Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
// すでに影を描画済みの部分には描画させないようにすることで、
// 影が重なったときに色が濃くなってしまうのを防ぐ
Stencil
{
Ref 1
ReadMask 1
WriteMask 1
Comp Greater
Pass Replace
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
fixed4 _Color;
float _Angle;
float _Distance;
v2f vert(appdata_t IN)
{
v2f OUT;
// まず、引き伸ばし方向を指す単位ベクトルを作る
float2 direction;
sincos(_Angle * UNITY_PI / 180.0, direction.y, direction.x);
// 引き伸ばし方向の成分の符号を求め...
float2 directionSign = sign(direction);
// 単純化のため、符号が0ならとりあえず1とし...
directionSign += 1.0 - abs(directionSign);
// 2つの軸に分け...
float2 axisX = float2(directionSign.x, 0.0);
float2 axisY = float2(0.0, directionSign.y);
// 符号の積を求めて第1・3象限(+1)か第2・4象限(-1)かを調べ...
float orthantSign = directionSign.x * directionSign.y;
// 象限に応じて軸を選び、それを使って元の頂点座標を(0.5, 0.5)を中心に回転させる
IN.vertex.xy = mul(IN.vertex.xy - 0.5, orthantSign > 0 ? float2x2(axisX, axisY) : float2x2(axisY, axisX)) + 0.5;
// 可動側の三角形をdirectionの向きに_Distanceだけずらす
IN.vertex.xy += (IN.vertex.z * _Distance) * direction;
// 可動側判定に使ったZ成分はもう不要なので0に変える
IN.vertex.z = 0.0;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
return _Color;
}
ENDCG
}
}
}
こんな感じで影を描いた後、さらにその上に通常のシェーダーで本来の画像を描画すれば画像が影を落としているように見えるんじゃないかと思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.13%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
Bongo
2020/03/08 08:19
ご提示いただいた図はどういう状況なのでしょうか?
もし試行錯誤した結果の失敗図なのでしたら、他にも外部画像処理ソフトで模擬的な理想図を描いていただいた方がいいかもしれません。
退会済みユーザー
2020/03/08 11:37
添付した画像は理想図です