Unity creates rotating beam

Unity creates rotating beam


  Hello everyone, my name is A Zhao.
  This is an effect that you may have seen in many games. A beam of brushed light is emitted upward from under the feet of portals, magic circles, characters, etc., and then rotates continuously.
Insert image description here

  This time let’s do this effect in the Unity engine.

1. Prepare materials

  The materials that need to be prepared are very simple.
  The first one is a cylindrical mesh model with the upper and lower caps removed and then the UVs flattened.
Insert image description here

  The second one is a noise map
Insert image description here

2. Production process

1. Control the shape

  Since the prepared output is a cylindrical grid, the actual display effect is a fan-like shape. So it needs to be achieved by controlling the vertices. The principle is very simple. The V coordinate of UV changes from 0 to 1 from the bottom to the top of the model, so just multiply it by the V coordinate of UV along the normal direction, and then multiply it by a control value and add it to the vertex coordinate. , the bottom will remain unchanged, and the width will increase as you go up.

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

The effect is as shown below
Insert image description here

2. Brushed effect

  First assign the noise map to the grid model to get this effect:
Insert image description here

  Then set the number of tilings
Insert image description here

  You get the brushed effect.
Insert image description here

  Here, add an HDR color overlay to the inherent color, then input the brushed effect as the Alpha channel, and set Transparent rendering to get this effect:
Insert image description here

3. Transparent gradient effect

  The above effect is too strong and requires some control over its transparency. First look at the actual range of the V coordinate of the UV coordinate:
Insert image description here

  As mentioned before, the V coordinate changes from 0 to 1 from the bottom to the top of the model. Next, you can do some processing with this value.

1. Upper and lower edge control

  The first thing to control is the upper and lower edges. Now the edges are too hard. I use two SmoothSteps, corresponding to the top and bottom respectively, to make the edges soft:

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 );

Insert image description here

  Multiplying the soft upper and lower edges with the original brushed Alpha value, we get this effect:
Insert image description here

2. Left and right edge control

  The above effect is very close to the effect we want, but it is still a little bit worse. The left and right edges are also very hard, so we use the world normal direction and the observation direction to do dot multiplication. Finally, we add a SmoothStep to give a soft gradient to the left and right edges. .

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 ));

  The calculation result is the gradual darkening of the left and right sides like this:
Insert image description here

3. Overlay mask

  Multiply the above three SmoothStep results to get such a mask range:
Insert image description here

  Then multiplied by the brushed Alpha value, we get this effect:
Insert image description here

4. Solving the occlusion problem

  There is a problem with translucent rendering. From certain angles, an error will appear:
Insert image description here

  Here I make another copy of the grid model:
Insert image description here

  Then the two mesh models use different CullMode

Insert image description here
Insert image description here
Insert image description here

Insert image description here

  Then the two mesh models are displayed together, and the correct effect is obtained:
Insert image description here

3. Shader source code

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
		}
	}
	
}

Guess you like

Origin blog.csdn.net/liweizhao/article/details/133195646