{"id":612,"date":"2017-02-04T00:56:33","date_gmt":"2017-02-03T23:56:33","guid":{"rendered":"http:\/\/piflik.de\/?p=612"},"modified":"2017-02-04T00:56:33","modified_gmt":"2017-02-03T23:56:33","slug":"pretty-explosions","status":"publish","type":"post","link":"http:\/\/piflik.de\/?p=612","title":{"rendered":"Pretty Explosions"},"content":{"rendered":"<p>I haven&#8217;t posted anything about my current project, mainly because I mostly worked on internal systems. But recently I needed a bit of a break and implemented some visual FX. The first I want to show here is a &#8216;simple&#8217; explosion.<\/p>\n<p><a rel=\"attachment wp-att-613\" href=\"http:\/\/piflik.de\/?attachment_id=613\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-613\" title=\"explosion\" src=\"http:\/\/piflik.de\/wp-content\/uploads\/2017\/02\/explosion.gif\" alt=\"\" width=\"652\" height=\"466\" srcset=\"http:\/\/piflik.de\/wp-content\/uploads\/2017\/02\/explosion.gif 652w, http:\/\/piflik.de\/wp-content\/uploads\/2017\/02\/explosion-300x214.gif 300w\" sizes=\"(max-width: 652px) 100vw, 652px\" \/><\/a><!--more-->The base effect consists of a Shuriken particle system, making use of a custom shader to control color and transparency. This shader is based on Florian Smolka&#8217;s shader linked to in <a href=\"https:\/\/simonschreibt.de\/gat\/fallout-4-the-mushroom-case\/\">this blog post<\/a>. It uses 2D gradients to remap the color of a sprite into a different color space. Each horizontal pixel-line in the texture defines a color gradient that is selected according to each individual particle&#8217;s age. I modified the shader to only use a single gradient texture with an alpha channel instead of two textures and added a multiplier for HDR output. The sprite itself is animated (via a spritesheet) to further enhance the animation. I added a shockwave effect with a second shader that uses the GrabPass function and some maths to distort the already rendered image (sourcecode at the end of this post). It is not physically correct, and has some issues (most notably it distorts objects in front of the shockwave, since it is rendered in the transparent queue), but it is sufficient for this effect. It takes both the vertex normals and an optional normal map into account to calculate the distortion, and the strength is controlled further via a fresnel effect, so distortion is strongest at surfaces perpendicular to the camera&#8217;s viewing direction. The shockwave, as well as a point light, is animated via a script and a custom curve.<\/p>\n<p>And since Unity updated its particle system with line renderers and noise, I decided to quickly try creating some kind of electrical\/emp explosion effect. Totally unrelated to the above technique (save for the shockwave), but it looks quite neat for the effort. The line renderer and noise functions are really good.<\/p>\n<p><a rel=\"attachment wp-att-614\" href=\"http:\/\/piflik.de\/?attachment_id=614\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-614\" title=\"emp\" src=\"http:\/\/piflik.de\/wp-content\/uploads\/2017\/02\/emp.gif\" alt=\"\" width=\"652\" height=\"466\" srcset=\"http:\/\/piflik.de\/wp-content\/uploads\/2017\/02\/emp.gif 652w, http:\/\/piflik.de\/wp-content\/uploads\/2017\/02\/emp-300x214.gif 300w\" sizes=\"(max-width: 652px) 100vw, 652px\" \/><\/a><\/p>\n<p>Now obviously have to create a nuclear mushroom cloud. No explosion VFX set can be complete without one.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nShader &quot;Custom\/Distortion&quot; {\r\n\tProperties {\r\n\t\t_MainColor (&quot;Color&quot;, Color) = (1,1,1,1)\r\n\t\t_Normal (&quot;Normal Map&quot;, 2D) = &quot;normal&quot; {}\r\n\t\t_IOR(&quot;Refraction&quot;, Range(-5, 5)) = 1\r\n\t\t_NormalMapStrength(&quot;Normal Map Strength)&quot;, Range(0, 1)) = 1\r\n\t\t_FresnelStrength(&quot;Fresnel Strength)&quot;, Range(0, 1)) = 1\r\n\t}\r\n\r\n\tSubShader {\r\n\r\n\t\tTags{ &quot;Queue&quot; = &quot;Transparent&quot; &quot;IgnoreProjector&quot; = &quot;True&quot; &quot;RenderType&quot; = &quot;Transparent&quot; }\r\n\r\n\t\tGrabPass {}\r\n\r\n\t\tPass {\r\n\r\n\t\t\tCGPROGRAM\r\n\r\n\t\t\t#pragma vertex vert\r\n\t\t\t#pragma fragment frag\r\n\r\n\t\t\t#include &quot;UnityCG.cginc&quot;\r\n\r\n\t\t\tstruct appdata {\r\n\t\t\t\tfloat4 vertex : POSITION;\r\n\t\t\t\tfloat2 uv : TEXCOORD0;\r\n\t\t\t\tfloat3 normal : NORMAL;\r\n\t\t\t};\r\n\r\n\t\t\tstruct v2f {\r\n\t\t\t\tfloat4 position : SV_POSITION;\r\n\t\t\t\tfloat2 uv : TEXCOORD0;\r\n\t\t\t\tfloat3 normal : TEXCOORD1;\r\n\t\t\t\tfloat3 viewDir : TEXCOORD2;\r\n\t\t\t\tfloat4 grabUv : TEXCOORD3;\r\n\t\t\t\tfloat3 viewNormal : TEXCOORD4;\r\n\t\t\t};\r\n\r\n\t\t\tuniform sampler2D _GrabTexture;\r\n\r\n\t\t\tuniform half4 _MainColor;\r\n\t\t\tuniform sampler2D _Normal;\r\n\t\t\tuniform float4 _Normal_ST;\r\n\t\t\tuniform half _IOR;\r\n\t\t\tuniform half _NormalMapStrength;\r\n\t\t\tuniform half _FresnelStrength;\r\n\r\n\t\t\tv2f vert (appdata IN) {\r\n\t\t\t\tv2f OUT;\r\n\r\n\t\t\t\tOUT.position = UnityObjectToClipPos(IN.vertex);\r\n\t\t\t\tOUT.uv = IN.uv;\r\n\r\n\t\t\t\tfloat3 worldPos = mul(unity_ObjectToWorld, IN.vertex).xyz;\r\n\r\n\t\t\t\tOUT.viewDir = normalize(UnityWorldSpaceViewDir(worldPos));\r\n\t\t\t\tOUT.normal = UnityObjectToWorldNormal(IN.normal);\r\n\r\n\t\t\t\tOUT.grabUv = ComputeGrabScreenPos(OUT.position);\r\n\r\n\t\t\t\tOUT.viewNormal = UnityObjectToClipPos(IN.normal);\r\n\r\n\t\t\t\treturn OUT;\r\n\t\t\t}\r\n\r\n\t\t\t\/\/TODO fix distortion of geometry in front of object\r\n\t\t\tfixed4 frag (v2f IN) : SV_Target {\r\n\r\n\t\t\t\tIN.normal = normalize(IN.normal);\r\n\t\t\t\tIN.viewDir = normalize(IN.viewDir);\r\n\t\t\t\tIN.viewNormal = normalize(IN.viewNormal);\r\n\r\n\t\t\t\tfixed3 normalMap = normalize(UnpackNormal(tex2D(_Normal, _Normal_ST * IN.uv))) * _NormalMapStrength;\r\n\r\n\t\t\t\tfloat3 normProj = IN.normal - dot(IN.normal, IN.viewDir) * IN.viewDir;\r\n\t\t\t\tfloat fresnel = pow(length(cross(IN.normal, IN.viewDir)),4) * _FresnelStrength;\r\n\r\n\t\t\t\tIN.grabUv.x += _IOR * IN.viewNormal.x * fresnel;\r\n\t\t\t\tIN.grabUv.y -= _IOR * IN.viewNormal.y * fresnel;\r\n\r\n\t\t\t\tIN.grabUv.xy += _IOR * normalMap;\r\n\r\n\t\t\t\tfixed4 refraction = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(IN.grabUv));\r\n\r\n\t\t\t\treturn _MainColor * refraction;\r\n\t\t\t}\r\n\r\n\t\t\tENDCG\r\n\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I haven&#8217;t posted anything about my current project, mainly because I mostly worked on internal systems. But recently I needed a bit of a break and implemented some visual FX. The first I want to show here is a &#8216;simple&#8217; explosion.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[7,13,12,4],"tags":[],"_links":{"self":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/612"}],"collection":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=612"}],"version-history":[{"count":2,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/612\/revisions"}],"predecessor-version":[{"id":616,"href":"http:\/\/piflik.de\/index.php?rest_route=\/wp\/v2\/posts\/612\/revisions\/616"}],"wp:attachment":[{"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=612"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=612"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/piflik.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=612"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}