[OpenGL] Shader instance analysis (9)-Main Character injury effect in AngryBots, shaderangrybots
Keep forwarding address: http://blog.csdn.net/stalendp/article/details/40859441
AngryBots is a great official example of Unity and has great research value. In previous studies, due to its rich content, I didn't know where to start writing and analyzing articles at a time. The shader technology has been studied more recently. Let's start with this aspect of shader. First, analyze one of the screen effects: the full screen effect (postScreenEffect) that will appear when the protagonist is attacked. The effect is as follows:
In fact, this is a Bloom effect. The relevant files include MobileBloom. js and MobileBloom. shader. For details about how to view these two files, see:
JS Code Analysis
Some code of MobileBloom. js is as follows:
function OnRenderImage (source : RenderTexture, destination : RenderTexture) {#if UNITY_EDITORFindShaders ();CheckSupport ();CreateMaterials ();#endifagonyTint = Mathf.Clamp01 (agonyTint - Time.deltaTime * 2.75f);var tempRtLowA : RenderTexture = RenderTexture.GetTemporary (source.width / 4, source.height / 4, rtFormat);var tempRtLowB : RenderTexture = RenderTexture.GetTemporary (source.width / 4, source.height / 4, rtFormat);// prepare dataapply.SetColor ("_ColorMix", colorMix);apply.SetVector ("_Parameter", Vector4 (colorMixBlend * 0.25f, 0.0f, 0.0f, 1.0f - intensity - agonyTint));// downsample & blurGraphics.Blit (source, tempRtLowA, apply, agonyTint < 0.5f ? 1 : 5);Graphics.Blit (tempRtLowA, tempRtLowB, apply, 2);Graphics.Blit (tempRtLowB, tempRtLowA, apply, 3);// applyapply.SetTexture ("_Bloom", tempRtLowA);Graphics.Blit (source, destination, apply, QualityManager.quality > Quality.Medium ? 4 : 0);RenderTexture.ReleaseTemporary (tempRtLowA);RenderTexture.ReleaseTemporary (tempRtLowB);}
Knowledge Point preparation 1) OnRenderImage Function
This is a callback function that is part of the life cycle of MonoBehaviour. Each frame is called. When this function is called, all 3d rendering is complete, the rendering result is passed into the function with the source parameter. The later implementation of the effect is to process the source and integrate the result into destination.The script of this function is usually bound to Camera. This function is only available in Unity Pro.
2) Graphics. BICS Function
static void Blit(Texture source, RenderTexture dest);static void Blit(Texture source, RenderTexture dest, Material mat, int pass = -1);static void Blit(Texture source, Material mat, int pass = -1);
This function is like a transformer. The source image is converted into a dest image after processing. The material object mat is responsible for algorithm implementation.(More accurately, the algorithm is bound to the shader on the mat. The shader can have multiple passes. You can use the pass parameter to specify a specific shader.-1 indicates executing all the passes on the shader).
3) RenderTexture. GetTemporary function and RenderTexture. ReleaseTemporary Function
GetTemporary gets the temporary RenderTexture. ReleaseTemporary is used to release the specified RenderTexture;
RenderTexture is generally implemented in the GPU, which is fast but has scarce resources. In unity, the RenderTexture is pooled for reuse. The call to the GetTemporary function is actually to get the reference of RenderTexture in unity. After processing, ReleaseTemporary is used to release the reference of this RenderTexture to achieve reuse and improve performance.
JS Code Analysis
With three knowledge points, the functions of the above Code are very clear. The analysis is as follows:
- A) obtain the tempRtLowA and tempRtLowB pasters.(The length and width are 1/4 of the source image to accelerate rendering)
- B) Set Shader parameters in Mat.
- C) use Mat to process the texture and render it to the destination texture for display.
- D) release a temporary texture.
Here we will first explain a and c;
[Step a], get two pasters and scale down to 1/16 of the original size (both the length and width are reduced to 1/4 of the original size and the area is 1/16 of the original size), saving GPU memory, at the same time, the rendering speed is improved. Because the next step is to blur the image (the quality requirement is not high), this is feasible.
Step c](Note: Call the Bader function to filter textures. The last numeric parameter is used to refer to the shader's pass)
Pass1 or pass5: extract the brightest part of the color; pass2 blur the highlighted image vertically; pass3 blur the highlighted image horizontally; pass0 or pass4; and then overlay the blurred image to the original image.
A highlight is the process of first going through horizontal fuzzy and then vertical fuzzy, as shown in(This can be understood as "an algorithm for spreading a point to the surrounding area "):
Graphic Algorithm
The focus is on how the shader Algorithm in Step c is implemented. First, let's illustrate the algorithm:
Figure 1 source Image
Figure 2 [initialization] scale the source image to 1/16
Figure 3 [Step 1] expand the highlighted area
Figure 4 [Step 2] vertical blur
Figure 5 [Step 3] horizontal blur
Figure 6 [step 4a] (source image + result of step 3) The final superposition effect, which is called glow or bloom.
Figure 7 [step 4b] (original image + result of step 3) The final superimposed effect ===( Note: You need to add the red component to step 1)
Adjust the color intensity of the image in step 1 to form an animation, as shown in:
Shader Analysis
Next, I will analyze the shader according to the sequence.
Figure 3 [Step 1] expand the highlighted area
Js Code:
Graphics.Blit (source, tempRtLowA, apply, 1);
Shader code:
struct v2f_withMaxCoords {half4 pos : SV_POSITION;half2 uv : TEXCOORD0;half2 uv2[4] : TEXCOORD1;};v2f_withMaxCoords vertMax (appdata_img v){v2f_withMaxCoords o;o.pos = mul (UNITY_MATRIX_MVP, v.vertex);o.uv = v.texcoord;o.uv2[0] = v.texcoord + _MainTex_TexelSize.xy * half2(1.5,1.5);o.uv2[1] = v.texcoord + _MainTex_TexelSize.xy * half2(-1.5,1.5);o.uv2[2] = v.texcoord + _MainTex_TexelSize.xy * half2(-1.5,-1.5);o.uv2[3] = v.texcoord + _MainTex_TexelSize.xy * half2(1.5,-1.5);return o; }fixed4 fragMax ( v2f_withMaxCoords i ) : COLOR{fixed4 color = tex2D(_MainTex, i.uv.xy);color = max(color, tex2D (_MainTex, i.uv2[0]));color = max(color, tex2D (_MainTex, i.uv2[1]));color = max(color, tex2D (_MainTex, i.uv2[2]));color = max(color, tex2D (_MainTex, i.uv2[3]));return saturate(color - ONE_MINUS_INTENSITY);} // 1Pass { CGPROGRAM#pragma vertex vertMax#pragma fragment fragMax#pragma fragmentoption ARB_precision_hint_fastest ENDCG }
This code can be described as follows: when rendering a certain point, the brightest point is selected as the color of the point at this point and its surrounding four points (top left, top right, bottom left, bottom right. The specific explanation is: In vertMax code, the uv coordinates offset to four directions are constructed. Combined with its own uv, a total of five Uvs are submitted together to openGL, Which is raster and then transmitted to fragmentShader for use. In fragMax, select the largest of the five uv pixels as the color output. Result 3 is displayed.
Figure 4 [Step 2] vertical blur
Js end
Graphics.Blit (tempRtLowA, tempRtLowB, apply, 2);
Shader code:
struct v2f_withBlurCoords {half4 pos : SV_POSITION;half2 uv2[4] : TEXCOORD0;};v2f_withBlurCoords vertBlurVertical (appdata_img v){v2f_withBlurCoords o;o.pos = mul (UNITY_MATRIX_MVP, v.vertex);o.uv2[0] = v.texcoord + _MainTex_TexelSize.xy * half2(0.0, -1.5);o.uv2[1] = v.texcoord + _MainTex_TexelSize.xy * half2(0.0, -0.5);o.uv2[2] = v.texcoord + _MainTex_TexelSize.xy * half2(0.0, 0.5);o.uv2[3] = v.texcoord + _MainTex_TexelSize.xy * half2(0.0, 1.5);return o; }fixed4 fragBlurForFlares ( v2f_withBlurCoords i ) : COLOR{fixed4 color = tex2D (_MainTex, i.uv2[0]);color += tex2D (_MainTex, i.uv2[1]);color += tex2D (_MainTex, i.uv2[2]);color += tex2D (_MainTex, i.uv2[3]);return color * 0.25;}// 2Pass {CGPROGRAM#pragma vertex vertBlurVertical#pragma fragment fragBlurForFlares#pragma fragmentoption ARB_precision_hint_fastest ENDCG }
The role of this code can be described as: when rendering a certain point, the color of the four points (up and down) between the 0.5 and 1.5 units is superimposed in the vertical direction, the color of the point. Result 4.
Figure 5 [Step 3] horizontal blur (as described in Figure 4) Figure 6 [step 4a] Final superposition Effect
(Source image + step 3) The final superimposed effect, which is called glow or bloom.
Js Code segment:
apply.SetTexture ("_Bloom", tempRtLowA);Graphics.Blit (source, destination, apply, 0);
Shader code:
struct v2f_simple {half4 pos : SV_POSITION;half4 uv : TEXCOORD0;};v2f_simple vertBloom (appdata_img v){v2f_simple o;o.pos = mul (UNITY_MATRIX_MVP, v.vertex);o.uv = v.texcoord.xyxy;#if SHADER_API_D3D9if (_MainTex_TexelSize.y < 0.0)o.uv.w = 1.0 - o.uv.w;#endifreturn o; }fixed4 fragBloom ( v2f_simple i ) : COLOR{fixed4 color = tex2D(_MainTex, i.uv.xy);return color + tex2D(_Bloom, i.uv.zw);} // 0Pass {CGPROGRAM#pragma vertex vertBloom#pragma fragment fragBloom#pragma fragmentoption ARB_precision_hint_fastest ENDCG}
The role of this code can be described as: overlay the result of Figure 5 to the source image. Result 6 is displayed.
Complete Shader code
MobileBloom. shader:
Shader "Hidden/MobileBloom" {Properties {_MainTex ("Base (RGB)", 2D) = "white" {}_Bloom ("Bloom (RGB)", 2D) = "black" {}}CGINCLUDE#include "UnityCG.cginc"sampler2D _MainTex;sampler2D _Bloom;uniform fixed4 _ColorMix;uniform half4 _MainTex_TexelSize;uniform fixed4 _Parameter;#define ONE_MINUS_INTENSITY _Parameter.wstruct v2f_simple {half4 pos : SV_POSITION;half4 uv : TEXCOORD0;};struct v2f_withMaxCoords {half4 pos : SV_POSITION;half2 uv : TEXCOORD0;half2 uv2[4] : TEXCOORD1;};struct v2f_withBlurCoords {half4 pos : SV_POSITION;half2 uv2[4] : TEXCOORD0;};v2f_simple vertBloom (appdata_img v){v2f_simple o;o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xyxy; #if SHADER_API_D3D9 if (_MainTex_TexelSize.y < 0.0) o.uv.w = 1.0 - o.uv.w; #endifreturn o; }v2f_withMaxCoords vertMax (appdata_img v){v2f_withMaxCoords o;o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord; o.uv2[0] = v.texcoord + _MainTex_TexelSize.xy * half2(1.5,1.5);o.uv2[1] = v.texcoord + _MainTex_TexelSize.xy * half2(-1.5,1.5);o.uv2[2] = v.texcoord + _MainTex_TexelSize.xy * half2(-1.5,-1.5);o.uv2[3] = v.texcoord + _MainTex_TexelSize.xy * half2(1.5,-1.5);return o; }v2f_withBlurCoords vertBlurVertical (appdata_img v){v2f_withBlurCoords o;o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv2[0] = v.texcoord + _MainTex_TexelSize.xy * half2(0.0, -1.5);o.uv2[1] = v.texcoord + _MainTex_TexelSize.xy * half2(0.0, -0.5);o.uv2[2] = v.texcoord + _MainTex_TexelSize.xy * half2(0.0, 0.5);o.uv2[3] = v.texcoord + _MainTex_TexelSize.xy * half2(0.0, 1.5);return o; }v2f_withBlurCoords vertBlurHorizontal (appdata_img v){v2f_withBlurCoords o;o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.uv2[0] = v.texcoord + _MainTex_TexelSize.xy * half2(-1.5, 0.0);o.uv2[1] = v.texcoord + _MainTex_TexelSize.xy * half2(-0.5, 0.0);o.uv2[2] = v.texcoord + _MainTex_TexelSize.xy * half2(0.5, 0.0);o.uv2[3] = v.texcoord + _MainTex_TexelSize.xy * half2(1.5, 0.0);return o; }fixed4 fragBloom ( v2f_simple i ) : COLOR{fixed4 color = tex2D(_MainTex, i.uv.xy);return color + tex2D(_Bloom, i.uv.zw);} fixed4 fragBloomWithColorMix ( v2f_simple i ) : COLOR{fixed4 color = tex2D(_MainTex, i.uv.xy);half colorDistance = Luminance(abs(color.rgb-_ColorMix.rgb));color = lerp(color, _ColorMix, (_Parameter.x*colorDistance));color += tex2D(_Bloom, i.uv.zw);return color;} fixed4 fragMaxWithPain ( v2f_withMaxCoords i ) : COLOR{fixed4 color = tex2D(_MainTex, i.uv.xy);color = max(color, tex2D (_MainTex, i.uv2[0]));color = max(color, tex2D (_MainTex, i.uv2[1]));color = max(color, tex2D (_MainTex, i.uv2[2]));color = max(color, tex2D (_MainTex, i.uv2[3]));return saturate(color + half4(0.25,0,0,0) - ONE_MINUS_INTENSITY);} fixed4 fragMax ( v2f_withMaxCoords i ) : COLOR{fixed4 color = tex2D(_MainTex, i.uv.xy);color = max(color, tex2D (_MainTex, i.uv2[0]));color = max(color, tex2D (_MainTex, i.uv2[1]));color = max(color, tex2D (_MainTex, i.uv2[2]));color = max(color, tex2D (_MainTex, i.uv2[3]));return saturate(color - ONE_MINUS_INTENSITY);} fixed4 fragBlurForFlares ( v2f_withBlurCoords i ) : COLOR{fixed4 color = tex2D (_MainTex, i.uv2[0]);color += tex2D (_MainTex, i.uv2[1]);color += tex2D (_MainTex, i.uv2[2]);color += tex2D (_MainTex, i.uv2[3]);return color * 0.25;}ENDCGSubShader { ZTest Always Cull Off ZWrite Off Blend Off Fog { Mode off } // 0Pass {CGPROGRAM#pragma vertex vertBloom#pragma fragment fragBloom#pragma fragmentoption ARB_precision_hint_fastest ENDCG}// 1Pass { CGPROGRAM#pragma vertex vertMax#pragma fragment fragMax#pragma fragmentoption ARB_precision_hint_fastest ENDCG }// 2Pass {CGPROGRAM#pragma vertex vertBlurVertical#pragma fragment fragBlurForFlares#pragma fragmentoption ARB_precision_hint_fastest ENDCG }// 3Pass {CGPROGRAM#pragma vertex vertBlurHorizontal#pragma fragment fragBlurForFlares#pragma fragmentoption ARB_precision_hint_fastest ENDCG}// 4Pass {CGPROGRAM#pragma vertex vertBloom#pragma fragment fragBloomWithColorMix#pragma fragmentoption ARB_precision_hint_fastest ENDCG}// 5Pass {CGPROGRAM#pragma vertex vertMax#pragma fragment fragMaxWithPain#pragma fragmentoption ARB_precision_hint_fastest ENDCG}}FallBack Off}
References
Official example AngryBots URL: http://u3d.as/content/unity-technologies/angry-bots/5CF
Unit Shaders and Effects Cookbook:
Chapter 10 Screen Effects with Unity Render Textures
Chapter 11 Gameplay and Screen Effects
[GPU Gems] Real-Time Glow: http://http.developer.nvidia.com/GPUGems/gpugems_ch21.html