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

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

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

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Q&A

解決済

1回答

438閲覧

UnityのCustomShaderで頂点描画の前後がおかしくなる箇所ができる

TS627

総合スコア19

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

0グッド

0クリップ

投稿2018/03/05 13:57

編集2018/03/05 14:04

前提・実現したいこと

Unity3Dを用いてhttp://nn-hokuson.hatenablog.com/entry/2017/06/06/202953を参考に物体の頂点が法線方向に飛び散って消えるエフェクトを作成しようと考えています。

発生している問題・エラーメッセージ

物体が頂点表示になった時に頂点が他の物体の奥にあるにも関わらず手前に点が表示される(透けて見える)ことがあります。これを解決したいです。

該当のソースコード

以下のコードをSphereオブジェクトにアタッチし、effectMatに下記のEffectShaderを設定したMaterialを与えて実行しました。displacementの値を適当に変えながらcube等のオブジェクトを手前においてみると再現できると思います。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Effecter : MonoBehaviour 6{ 7 [SerializeField, Range(0, 1)] 8 private float displacement; 9 [SerializeField] 10 private Material effectMat; 11 private Material defaultMat; 12 private Renderer ren; 13 private Mesh mesh; 14 private bool isEffecting; 15 16 private void Start() 17 { 18 mesh = GetComponent<MeshFilter>().mesh; 19 ren = GetComponent<Renderer>(); 20 defaultMat = ren.material; 21 } 22 23 private void Update() 24 { 25 if (displacement > 0) 26 { 27 if (!isEffecting) 28 { 29 isEffecting = true; 30 ChangeTopology(true); 31 } 32 } 33 else 34 { 35 if (isEffecting) 36 { 37 isEffecting = false; 38 ChangeTopology(false); 39 } 40 } 41 42 if (isEffecting) 43 { 44 ren.material.SetFloat("_Displacement", displacement); 45 } 46 } 47 48 private void ChangeTopology(bool isEffect) 49 { 50 if (isEffect) 51 { 52 ren.material = effectMat; 53 mesh.SetIndices(mesh.GetIndices(0), MeshTopology.Points, 0); 54 } 55 else 56 { 57 ren.material = defaultMat; 58 mesh.SetIndices(mesh.GetIndices(0), MeshTopology.Triangles, 0); 59 } 60 } 61}

ShaderLab

1Shader "Custom/EffectShader" 2{ 3 Properties 4 { 5 _Displacement("Displacement",Range(0,1)) = 0 6 _PointColor("PointColor",Color) = (1,1,1,1) 7 } 8 9 SubShader 10 { 11 Tags{"RenderType" = "Transparent" } 12 Cull Off ZWrite On Blend SrcAlpha OneMinusSrcAlpha 13 LOD 100 14 15 Pass 16 { 17 CGPROGRAM 18 #pragma vertex vert 19 #pragma fragment frag 20 #include "UnityCG.cginc" 21 22 struct v2f { 23 float4 pos : SV_POSITION; 24 float3 worldPos : TEXCOORD0; 25 }; 26 27 float _Displacement; 28 half4 _PointColor; 29 30 v2f vert (appdata_base v) 31 { 32 v2f o; 33 float3 n = UnityObjectToWorldNormal(v.normal); 34 o.pos = UnityObjectToClipPos(v.vertex) + float4(n * _Displacement, 0); 35 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; 36 return o; 37 } 38 39 fixed4 frag (v2f i) : COLOR 40 { 41 return half4(_PointColor.r,_PointColor.g,_PointColor.b,max(1- _Displacement,0)); 42 } 43 ENDCG 44 } 45 } 46}

補足情報(FW/ツールのバージョンなど)

Unity 2017.3.1f1

回答よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

頂点座標をUnityObjectToClipPosでクリッピング座標に変換した後で、それをワールド座標における法線方向に移動させているために、頂点が正しい位置に移動していないのではないでしょうか?

順序としては、

  • 頂点のモデル座標をワールド座標に変換する
  • ワールド座標をワールド法線の向きにずらす
  • ワールド座標をクリッピング座標に変換する(ビュー変換・プロジェクション変換を行う)
  • 最終的なクリッピング座標をo.posにセットする

となるかと思います。

vertを下記のように変更してみましたが、いかがでしょうか?
上記の順序に合わせて変数を用意した冗長な形になっていますが、適宜行をまとめても問題ないでしょう。

HLSL

1Shader "Custom/EffectShader" 2{ 3 Properties 4 { 5 _Displacement("Displacement",Range(0,1)) = 0 6 _PointColor("PointColor",Color) = (1,1,1,1) 7 } 8 9 SubShader 10 { 11 Tags{"RenderType" = "Transparent" } 12 Cull Off ZWrite On Blend SrcAlpha OneMinusSrcAlpha 13 LOD 100 14 15 Pass 16 { 17 CGPROGRAM 18 #pragma vertex vert 19 #pragma fragment frag 20 #include "UnityCG.cginc" 21 22 struct v2f { 23 float4 pos : SV_POSITION; 24 // float3 worldPos : TEXCOORD0; // worldPosは使用していないようなので、削除してもいいでしょう 25 }; 26 27 float _Displacement; 28 half4 _PointColor; 29 30 v2f vert (appdata_base v) 31 { 32 v2f o; 33 float3 n = UnityObjectToWorldNormal(v.normal); // ワールド法線 34 float3 p = mul(unity_ObjectToWorld, v.vertex).xyz; // モデル座標→ワールド座標 35 float3 offset = n * _Displacement; // ワールド座標のずらし量 36 float3 pOffset = p + offset; // ずらし後のワールド座標 37 float4 pClip = mul(UNITY_MATRIX_VP, float4(pOffset, 1.0)); // ワールド座標→クリッピング座標(XYZ成分だけでなくW成分も必要なので、pOffsetにW成分として1を加えてfloat4としてから変換) 38 o.pos = pClip; // pClipを最終的なo.posとして以降の描画プロセスへ送る 39 // o.worldPos = pOffset; // worldPosは使用していないようなので、削除してもいいでしょう 40 return o; 41 } 42 43 fixed4 frag (v2f i) : COLOR 44 { 45 return half4(_PointColor.r,_PointColor.g,_PointColor.b,max(1- _Displacement,0)); 46 } 47 ENDCG 48 } 49 } 50}

投稿2018/03/05 21:16

Bongo

総合スコア10807

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

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

TS627

2018/03/06 00:48

うまく動作しました。 詳しい説明ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問