Unity Shader implements X-ray effects

Unity Shader realizes the luminous effect of physical objects blocking the outer contour

I have seen "Torchlight", "Dead by Daylight", "Identity V" and many other games before, in which characters are blocked by buildings and show different effects. Here we call it the X-Ray effect, or it can also be called perspective effect.

fifth personality

fifth personality

Dead by Daylight

Dead by Daylight

Torchlight

Torchlight

Implementation plan

  1. Using Amplify Shader Editor1.6.1

  2. The Fresnel Node
    exploits the behavior of light when it reaches the interface between two materials with different refractive indexes, and the amount of reflection and refraction.
    ReflectionCoefficient = Bias + Scale x (1 + N)

Node parameters describe default value
normal space Specify the coordinate space where the normal vector lies cut
Tangent: normal vector in tangential space coordinates
World: normal vector in world space coordinates
bias Defines the bias variable for the Fresnel equation. Only visible when each input port is not connected 0
scale Defines the scale variable of the Fresnel equation. Only visible when each input port is not connected 1
Power determined The power-definite variables of the Fresnel equation are defined. Only visible when each input port is not connected 5
input port describe type
normal vector to use If not connected, surface world normals will be used float 3
bias Defines the bias variable for the Fresnel equation float
scale Defines the scale variable of the Fresnel equation float
power Defines the power variables of the Fresnel equation float
  1. Swizzle Node
    allows its input components to be reorganized and replicated. Input and output can be of different types.

Insert image description here
4. Outline Node
creates an Outline around an object.
Insert image description here

Operational realization

X-Ray

  1. Create a Shader
    (1) Set Outline to Transparent
    (2) Cull Mode setting has three options off front back.
    Normally we use one front. This can save performance
    because transparent materials are rendered from front to back. When we select front, we don’t need to render the back of the object, which reduces GPU performance consumption.

Note: If we want to do the occlusion relationship between objects, we need to know the z-buffer. However, our call to the z-buffer is implemented through ZTest and ZWrite.

Here I will just take the test I did before and not demonstrate
ZTest (depth test) and ZWrite (depth write)
a. The depth test is passed, and depth writing is turned on: writing to the depth buffer and writing to the color buffer;
b .The depth test passes, and depth writing is turned off: the depth buffer is not written, but the color buffer is written;
c. The depth test fails, and depth writing is turned on: the depth buffer is not written, and the color buffer is not written;
d. The depth test fails. , depth writing is turned off: the depth buffer is not written, and the color buffer is not written;
so the direct impact still depends on ZTest

When ZTest and ZWrite are the same, you need to adjust the size of the Geometry queue to affect the rendering order. Larger Geometry is rendered first, and smaller Geometry is rendered later.

ZTest Less (pass if the depth is less than the current cache, pass ZTest Greater (pass if the depth is greater
than the current cache) ZTest LEqual (pass if the depth is less than or equal to the current cache)
ZTest GEqual (pass if the depth is greater than or equal to the current cache)
ZTest Equal (pass if the depth is equal to the current cache) Pass)
ZTest NotEqual (pass if the depth is not equal to the current cache)
ZTest Always (pass no matter what)

Note:
ZTest Off is equivalent to ZTest Always, and turning off depth testing is equivalent to completely passing.

(3) ZWrite (depth writing)
can be directly turned off here, no need to write to the depth buffer
(4) ZTest (depth test)
directly Always (passed forever)
Insert image description here
at this time create a material ball to assign the Shader just created

I found that the X-ray effect is already there, but it has shortcomings and no three-dimensional effect. We are optimizing it.
Insert image description here

Three-dimensional sense optimization

Improvement plan:
Lighten the color from the edge to the center to make it look more three-dimensional

NOTE: Change the Normal Vector option in Fresnel to itself, not the world (stereoscopic)
Insert image description here

At this time, a Lerp difference operation
is added to interpolate the color and the calculation formula above to
Insert image description here
optimize the completed rendering.
Insert image description here

At this time, we found another problem. When we adjust the Alpha value, cold tones and segment tones are opposite. For example, as shown in the picture above, the alpha value of red is around -0.93, but the cool tones are better between 1 and 2. , we need to control the value within a range and continue to optimize

  1. At this time, when we do the difference operation of Color, we add a Swizzle and change its output type to Float
    and change the port to alpha.
  2. Add a One Minus to negate
  3. Remap the value at Alpha (reassign the original value)

Insert image description here
The effect diagram is as follows:
adjust the value range of Alpha to [0,1]
Insert image description here

Summarize

1. The model I used in the picture uses a single model with multiple materials, so only one body is shown. For a single model, the material can be directly assigned to the shader. If it is a single model with multiple materials, you need to create several more shaders, because The discovery cut diagram and Albedo diagram of each part are different.
2. I won’t show the demo here. The stuff is relatively simple. If you are interested, you can study the plug-in Amplify Shader Editor. I am using version 1.6.1.
3. I also attach the source code below.

Source code

Shader “ASE/Ray”
{
Properties
{
_ASEOutlineWidth( “Outline Width”, Float ) = 0
_Albedo(“Albedo”, 2D) = “white” {}
_Normalmap(“Normal map”, 2D) = “white” {}
_Color0(“Color 0”, Color) = (1,0,0,0)
_Alpha(“Alpha”, Float) = 0
_Bias(“Bias”, Range( 0 , 1)) = 0
_Scale(“Scale”, Range( 0 , 1)) = 0
_Power(“Power”, Range( 0 , 1)) = 0
[HideInInspector] _texcoord( “”, 2D ) = “white” {}
[HideInInspector] __dirty( “”, Int ) = 1
}

SubShader
{
	Tags{ "RenderType" = "Transparent"  "Queue" = "Transparent+0"}
	ZWrite Off
	ZTest Always
	Cull Front
	CGPROGRAM
	#pragma target 3.0
	#pragma surface outlineSurf Outline nofog alpha:fade  keepalpha noshadow noambient novertexlights nolightmap nodynlightmap nodirlightmap nometa noforwardadd vertex:outlineVertexDataFunc 
	
	
	
	struct Input
	{
		float3 worldPos;
		float3 worldNormal;
		INTERNAL_DATA
	};
	uniform float4 _Color0;
	uniform float _Bias;
	uniform float _Scale;
	uniform float _Power;
	uniform float _Alpha;
	uniform half _ASEOutlineWidth;
	
	void outlineVertexDataFunc( inout appdata_full v, out Input o )
	{
		UNITY_INITIALIZE_OUTPUT( Input, o );
		v.vertex.xyz += ( v.normal * _ASEOutlineWidth );
	}
	inline half4 LightingOutline( SurfaceOutput s, half3 lightDir, half atten ) { return half4 ( 0,0,0, s.Alpha); }
	void outlineSurf( Input i, inout SurfaceOutput o )
	{
		float3 ase_worldPos = i.worldPos;
		float3 ase_worldViewDir = normalize( UnityWorldSpaceViewDir( ase_worldPos ) );
		float3 ase_worldNormal = WorldNormalVector( i, float3( 0, 0, 1 ) );
		float fresnelNdotV7 = dot( ase_worldNormal, ase_worldViewDir );
		float fresnelNode7 = ( _Bias + _Scale * pow( 1.0 - fresnelNdotV7, _Power ) );
		float lerpResult18 = lerp( ( 1.0 - (_Color0).a ) , fresnelNode7 , (-2.0 + (_Alpha - 0.0) * (0.0 - -2.0) / (1.0 - 0.0)));
		o.Emission = _Color0.rgb;
		o.Alpha = lerpResult18;
		o.Normal = float3(0,0,-1);
	}
	ENDCG
	

	Tags{ "RenderType" = "Opaque"  "Queue" = "Geometry+1" }
	Cull Back
	ZWrite On
	ZTest LEqual
	CGPROGRAM
	#pragma target 3.0
	#pragma surface surf Standard keepalpha addshadow fullforwardshadows vertex:vertexDataFunc 
	struct Input
	{
		float2 uv_texcoord;
	};

	uniform sampler2D _Normalmap;
	uniform float4 _Normalmap_ST;
	uniform sampler2D _Albedo;
	uniform float4 _Albedo_ST;

	void vertexDataFunc( inout appdata_full v, out Input o )
	{
		UNITY_INITIALIZE_OUTPUT( Input, o );
		v.vertex.xyz += 0;
	}

	void surf( Input i , inout SurfaceOutputStandard o )
	{
		float2 uv_Normalmap = i.uv_texcoord * _Normalmap_ST.xy + _Normalmap_ST.zw;
		o.Normal = UnpackNormal( tex2D( _Normalmap, uv_Normalmap ) );
		float2 uv_Albedo = i.uv_texcoord * _Albedo_ST.xy + _Albedo_ST.zw;
		o.Albedo = tex2D( _Albedo, uv_Albedo ).rgb;
		o.Alpha = 1;
	}

	ENDCG
}
Fallback "Diffuse"
CustomEditor "ASEMaterialInspector"

}

Guess you like

Origin blog.csdn.net/qq_42194657/article/details/135422747
Recommended