Unity は回転ビームを作成します

Unity は回転ビームを作成します


  皆さんこんにちは、私の名前はA Zhaoです。
  多くのゲームで見たことがあるエフェクトですが、ポータルや魔法陣、キャラクターなどの足元からブラシ状の光線が上方に放射され、連続的に回転します。
ここに画像の説明を挿入します

  今回はこのエフェクトをUnityエンジンでやってみます。

1. 材料を準備する

  準備する必要のある材料は非常にシンプルです。
  1 つ目は、上部と下部のキャップが削除され、UV が平坦化された円筒形のメッシュ モデルです。
ここに画像の説明を挿入します

  2番目はノイズマップです
ここに画像の説明を挿入します

2. 製造工程

1. 形状をコントロールする

  準備された出力は円筒形のグリッドであるため、実際の表示効果は扇形になります。したがって、頂点を制御することでこれを実現する必要があります。原理は非常に簡単で、モデルの下から上に向かってUVのV座標が0から1に変化するので、法線方向にUVのV座標を乗算し、制御値を乗算して加算するだけです。を頂点座標にすると、下は変わらず、上に行くほど幅が広くなります。

float3 vertexValue = ( v.normal * _normalScale * v.uv.y );
v.vertex.xyz += vertexValue;
o.vertex = UnityObjectToClipPos(v.vertex);

効果は以下の通りです
ここに画像の説明を挿入します

2. ブラシ効果

  この効果を得るには、まずノイズ マップをグリッド モデルに割り当てます。
ここに画像の説明を挿入します

  次にタイリングの数を設定します
ここに画像の説明を挿入します

  ブラシ効果が得られます。
ここに画像の説明を挿入します

  ここでは、HDR カラー オーバーレイを固有のカラーに追加し、ブラシ効果をアルファ チャネルとして入力し、この効果を得るために透明レンダリングを設定します。
ここに画像の説明を挿入します

3. 透明なグラデーション効果

  上記の効果は強すぎるため、透明度をある程度制御する必要があります。まず、UV 座標の V 座標の実際の範囲を確認します。
ここに画像の説明を挿入します

  前述したように、V 座標はモデルの下から上に向かって 0 から 1 に変化します。次に、この値を使用して何らかの処理を実行できます。

1. 上下エッジ制御

  最初に制御するのは、上部と下部のエッジです。ここではエッジが硬すぎます。それぞれ上部と下部に対応する 2 つの SmoothSteps を使用して、エッジを柔らかくします。

float tempOneMinueVal = ( 1.0 - i.uv.y );
float smoothstepResultV1 = smoothstep( _vMin , _vMax , ( tempOneMinueVal - _vOffset ));
float smoothstepResultV2 = smoothstep( _vMin2 , _vMax2 , i.uv.y);
float clampResult = clamp( min( min( smoothstepResultV1 , tempOneMinueVal ) , smoothstepResultV2 ) , 0.0 , 1.0 );

ここに画像の説明を挿入します

  ソフトな上端と下端に元のブラシ付きアルファ値を乗算すると、次の効果が得られます。
ここに画像の説明を挿入します

2. 左右エッジ制御

  上記の効果は希望する効果に非常に近いですが、まだ少し悪いです。左右のエッジも非常に硬いので、ワールド法線方向と観察方向を使用してドットの乗算を行います。 SmoothStep を追加して、左右のエッジに柔らかいグラデーションを与えます。

float3 worldNormal = i.worldNormal.xyz;
float3 worldViewDir = UnityWorldSpaceViewDir(i.worldPos);
worldViewDir = normalize(worldViewDir);
float dotResult = dot( worldNormal , worldViewDir );
float smoothstepResultEdge = smoothstep( _edgeMin , _edgeMax , abs( dotResult ));

  計算結果は以下のように左右が徐々に暗くなります。
ここに画像の説明を挿入します

3. オーバーレイマスク

  上記 3 つの SmoothStep の結果を乗算して、このようなマスク範囲を取得します。
ここに画像の説明を挿入します

  次に、ブラシ化されたアルファ値を乗算すると、次の効果が得られます。
ここに画像の説明を挿入します

4. オクルージョン問題の解決

  半透明のレンダリングに問題があり、特定の角度から見るとエラーが表示されます。
ここに画像の説明を挿入します

  ここで、グリッド モデルのコピーをもう 1 つ作成します。
ここに画像の説明を挿入します

  次に、2 つのメッシュ モデルは異なる CullMode を使用します。

ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します

ここに画像の説明を挿入します

  次に、2 つのメッシュ モデルが一緒に表示され、正しい効果が得られます。
ここに画像の説明を挿入します

3. シェーダのソースコード

Shader "azhao/LightColumn"
{
    
    
	Properties
	{
    
    
		[HDR]_emissCol("emissCol", Color) = (0,0,0,0)
		_emissScale("emissScale", Float) = 1
		_noiseTex("noiseTex", 2D) = "white" {
    
    }
		_flowSpeed("flowSpeed", Vector) = (0,0,0,0)
		_vOffset("vOffset", Float) = 0
		_edgeMin("edgeMin", Range( 0 , 1)) = 0
		_edgeMax("edgeMax", Range( 0 , 1)) = 1
		_vMin("vMin", Range( 0 , 1)) = 0
		_vMax("vMax", Range( 0 , 1)) = 1
		_normalScale("normalScale", Range(-2,2)) = 1		
		_vMin2("vMin2", Range( 0 , 1)) = 0
		_vMax2("vMax2", Range( 0 , 1)) = 1
[Enum(UnityEngine.Rendering.CullMode)]_CullMode("CullMode", Float) = 2

	}
	
	SubShader
	{
    
    
		
		
		Tags {
    
     "RenderType"="Opaque" }
	LOD 100

		CGINCLUDE
		#pragma target 3.0
		ENDCG
		Blend SrcAlpha One, SrcAlpha One
		AlphaToMask Off
		Cull [_CullMode]
		ColorMask RGBA
		ZWrite On
		ZTest LEqual
		Offset 0 , 0
		
		
		
		Pass
		{
    
    
			Name "Unlit"
			Tags {
    
     "LightMode"="ForwardBase" }
			CGPROGRAM

			

			#ifndef UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX
			//only defining to not throw compilation error over Unity 5.5
			#define UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input)
			#endif
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_instancing
			#include "UnityCG.cginc"
			#include "UnityShaderVariables.cginc"



			struct appdata
			{
    
    
				float4 vertex : POSITION;
				float4 color : COLOR;
				float3 normal : NORMAL;
				float2 uv : TEXCOORD0;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};
			
			struct v2f
			{
    
    
				float4 vertex : SV_POSITION;

				float3 worldPos : TEXCOORD0;
				float2 uv : TEXCOORD1;
				float3 worldNormal : TEXCOORD2;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};

			uniform float _CullMode;
			uniform float _normalScale;
			uniform float4 _emissCol;
			uniform float _emissScale;
			uniform sampler2D _noiseTex;
			SamplerState sampler_noiseTex;
			uniform float2 _flowSpeed;
			uniform float4 _noiseTex_ST;
			uniform float _vMin;
			uniform float _vMax;
			uniform float _vOffset;
			uniform float _vMin2;
			uniform float _vMax2;
			uniform float _edgeMin;
			uniform float _edgeMax;

			
			v2f vert ( appdata v )
			{
    
    
				v2f o;
				UNITY_SETUP_INSTANCE_ID(v);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
				UNITY_TRANSFER_INSTANCE_ID(v, o);

				
				float3 worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldNormal = worldNormal;				
				o.uv.xy = v.uv.xy;				


				float3 vertexValue = ( v.normal * _normalScale * v.uv.y );

				v.vertex.xyz += vertexValue;

				o.vertex = UnityObjectToClipPos(v.vertex);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				return o;
			}
			
			half4 frag (v2f i ) : SV_Target
			{
    
    
				UNITY_SETUP_INSTANCE_ID(i);
				UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);

				float2 uv_noiseTex = i.uv.xy * _noiseTex_ST.xy + _noiseTex_ST.zw;
				float2 panner6 = ( 1.0 * _Time.y * _flowSpeed + uv_noiseTex);
				float tempOneMinueVal = ( 1.0 - i.uv.y );
				float smoothstepResultV1 = smoothstep( _vMin , _vMax , ( tempOneMinueVal - _vOffset ));
				float smoothstepResultV2 = smoothstep( _vMin2 , _vMax2 , i.uv.y);
				float clampResult = clamp( min( min( smoothstepResultV1 , tempOneMinueVal ) , smoothstepResultV2 ) , 0.0 , 1.0 );
				float3 worldNormal = i.worldNormal.xyz;
				float3 worldViewDir = UnityWorldSpaceViewDir(i.worldPos);
				worldViewDir = normalize(worldViewDir);
				float dotResult = dot( worldNormal , worldViewDir );
				float smoothstepResultEdge = smoothstep( _edgeMin , _edgeMax , abs( dotResult ));
				half4 finalColor = (float4((( _emissCol * _emissScale )).rgb , ( tex2D( _noiseTex, panner6 ).r * clampResult * smoothstepResultEdge )));
				
				return finalColor;
			}
			ENDCG
		}
	}
	
}

おすすめ

転載: blog.csdn.net/liweizhao/article/details/133195646