当前位置:   article > 正文

Unity Shader之几何着色器(Geometry Shader)实现面片飞散的爆炸效果_shader 特效

shader 特效

前言

上篇文章初学集合着色器实现了草地效果,这篇再次使用GS实现一个“爆炸效果”。为什么要加上引号呢,因为实现的其实不是一个传统的爆炸效果,更类似于面片向外扩散消失的一种科幻效果,其实通过修改面片大小,颜色和扩散方向,还可以模拟复仇者联盟三最后人化为灰烬的效果。
为什么要实现这个效果呢,实际上我最早知道几何着色器是下载了一个K神实现的开源demo,然后看到了一个非常酷炫的传送特效。
传送
当时我第一感受就是“这尼玛也太太太太帅了吧!!!我什么时候也可以写出这种特效??!!”
感谢这是个开源Demo我可以看到其中的源码,我把下载地址提供给大家点我点我。这个网站还有很多同样酷炫的demo可供学习。这个特效其实使用的就是GS,然后通过调整面片的大小方向等来将物体“打碎”成粒子,再将粒子“重组”成物体。其实仔细观察“打碎”这个过程,有一部分图元用来表现传送了,还有一些细小的图元好像是粉末一样向外挥发掉了,我这次实现的就是后者这个效果,传送效果我以后会补上的。

实现

我其实参考大佬代码实现的Demo不是很复杂,直接放上代码吧。

Shader "MyShader/Explosion"
{
	Properties
	{
		_Color("Color Tint", Color) = (1,1,1,1)
		_Emission1("Emission1", Color) = (1,1,1,1)
		_Emission2("Emission2", Color) = (1,1,1,1)
		_Height("Height", Range(-1.5, 0.5)) = 0
		_TotalHeight("Total Height", Float) = 1
		_Strength("Explosion Strenth", Range(0, 10)) = 2
		_Scale("Scale", Range(0, 5)) = 1
	}
    SubShader
    {
        Tags { "RenderType"="Opaque"}
		Pass
		{
			Tags{"LightMode" = "ForwardBase"}
			Cull Off
			 CGPROGRAM
			#pragma vertex vert
			#pragma geometry geom
			#pragma fragment frag
			#include "UnityCG.cginc" 

			struct a2v
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};

			struct v2g
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};

			struct g2f
			{
				float4 pos : SV_POSITION;
				float3 normal : TEXCOORD0;
				float EmissionParam : TEXCOORD1;
			};

			fixed4 _Color;
			fixed4 _Emission1;
			fixed4 _Emission2;
			float _Height;
			float _TotalHeight;
			float _Strength;
			float _Scale;

			float3 randto3D(float3 seed)
			{
				float3 f = sin(float3(dot(seed, float3(127.1, 337.1, 256.2)), dot(seed, float3(129.8, 782.3, 535.3))
				, dot(seed, float3(269.5, 183.3, 337.1))));
				f = -1 + 2 * frac(f * 43785.5453123);
				return f;
			}

			float rand(float3 seed)
			{
				float f = sin(dot(seed, float3(127.1, 337.1, 256.2)));
				f = -1 + 2 * frac(f * 43785.5453123);
				return f;
			}

			float3x3 AngleAxis3x3(float angle, float3 axis)
			{
				float s, c;
				sincos(angle, s, c);
				float x = axis.x;
				float y = axis.y;
				float z = axis.z;
				return float3x3(
					x * x + (y * y + z * z) * c, x * y * (1 - c) - z * s, x * z * (1 - c) - y * s,
					x * y * (1 - c) + z * s, y * y + (x * x + z * z) * c, y * z * (1 - c) - x * s,
					x * z * (1 - c) - y * s, y * z * (1 - c) + x * s, z * z + (x * x + y * y) * c
				);
			}

			float3x3 rotation3x3(float3 angle)
			{
				return mul(AngleAxis3x3(angle.x, float3(0, 0, 1)), mul(AngleAxis3x3(angle.y, float3(1, 0, 0)), AngleAxis3x3(angle.z, float3(0, 1, 0))));
			}

			v2g vert(a2v v)
			{
				v2g o;
				o.vertex = v.vertex;
				o.normal = v.normal;
				return o;
			}

			g2f VertexOutput(float3 pos, float3 normal, float param)
			{
				g2f o;
				o.pos = UnityObjectToClipPos(float4(pos, 1));
				o.normal = UnityObjectToWorldNormal(normal);
				o.EmissionParam = param;
				return o;
			}

			[maxvertexcount(3)]
			void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream)
			{
				float3 p0 = IN[0].vertex.xyz;
				float3 p1 = IN[1].vertex.xyz;
				float3 p2 = IN[2].vertex.xyz;

				float3 n0 = IN[0].normal;
				float3 n1 = IN[1].normal;
				float3 n2 = IN[2].normal;

				float3 center = (p0 + p1 + p2) / 3;
				float offset = (center.y - _Height) * _TotalHeight;

				if (offset < 0)
				{
					triStream.Append(VertexOutput(p0, n0, -1));
					triStream.Append(VertexOutput(p1, n1, -1));
					triStream.Append(VertexOutput(p2, n2, -1));
					triStream.RestartStrip();
					return;
				}

				else if (offset > 1)
					return;

				float ss_offset = smoothstep(0, 1, offset);

				float3 translation = (n0 + n1 + n2) / 3 * ss_offset * _Strength;
				float3x3 rotationMatrix = rotation3x3(rand(center.zyx));
				float scale = _Scale - ss_offset;

				float3 t_p0 = mul(rotationMatrix, p0 - center) * scale + center + translation;
				float3 t_p1 = mul(rotationMatrix, p1 - center) * scale + center + translation;
				float3 t_p2 = mul(rotationMatrix, p2 - center) * scale + center + translation;
				float3 normal = normalize(cross(t_p1 - t_p0, t_p2 - t_p0));

				triStream.Append(VertexOutput(t_p0, normal, ss_offset));
				triStream.Append(VertexOutput(t_p1, normal, ss_offset));
				triStream.Append(VertexOutput(t_p2, normal, ss_offset));
				triStream.RestartStrip();
			}

			fixed4 frag(g2f i) : SV_Target
			{
				fixed4 color = step(0, i.EmissionParam) * _Emission1 + step(i.EmissionParam, 0) * _Color;
				if(i.EmissionParam > 0)
				color = lerp(color, _Emission2, i.EmissionParam);
				return color;
			}
			ENDCG
		}      
    }
    FallBack "Diffuse"
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159

其实原理就是根据高度决定保留哪些三角面片原有的形态,再把剩余的三角面片根据中心点的位置,加上位移,旋转,缩放组成新的面片。
最终效果如下。

最终效果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/127808
推荐阅读
相关标签
  

闽ICP备14008679号