{"author_link":"\/users\/coleslaughter","author_name":"ColeSlaughter","author_uid":"coleslaughter","comments":[],"epoch":1556773490,"event":"LD44","format":"md","ldjam_node_id":155875,"likes":24,"metadata":{"p_key":"131906","p_author":"ColeSlaughter","p_authorkey":"1013882","p_urlkey":"348100","p_title":"Making Organic Brain Chunks in Knit Worth Using Shaders","p_cat":"LDJam ","p_event":"LD44","p_time":"1556773490","p_likes":"24","p_comments":"0","p_status":"WAYBACK","us_key":"1013882","us_name":"ColeSlaughter","us_username":"coleslaughter","event_start":"1556236800","event_key":"75","event_name":"LD 44"},"node":{"_collation":{"body_sanitizer":"TextUtils::SanitizeHTML via existing importer","event":"LD44","removed_author":false},"_superparent":139254,"_trust":10,"author":13882,"body":"A lot of times in game dev, you put a lot of effort into a very specific thing that ultimately goes unnoticed by players.\n  \nWhy?  \n\nBecause if that thing is *not* there, then players will *definitely* notice its absence.\n\nThat very specific thing for us was the \u201cblobby\u201d effect of Granny's brain in Knit Worth.\n\nIn Knit Worth, you use crochet needles to poke and prod at a sweet old lady's brain chunks.  Naturally, something like that should look soft and organic.  Our solution was to use a simple vertex shader to manipulate the object on a `sin()` based rhythm.  The result was something that looked like this:\n\n![blobbois.gif](\/\/\/raw\/a36\/3\/z\/2447b.gif)\n\nFor folks who don't exactly know how shaders work, essentially a shader file usually (though not always) contains two functions that manipulate whatever object it's attached to.  The vertex shader function manipulates the position of a mesh's vertices, while a fragment shader manipulates the colors that are drawn to that object.\n\nIn the case of our blobby effect, we only needed to write a vertex shader.  We weren't too concerned with changing the colors of the object fragments (a sacrifice that was made for the sake of time).  Anyhoo, without further ado, here it is in all it's glory:\n\n```\nShader \"Custom\/Pulsate\"\n{\n\tProperties\n\t{\n\t\t_MainTex(\"Texture\", 2D) = \"white\" {}\n\t\t_Color(\"Main Color\", Color) = (1.0, 1.0, 1.0, 1.0)\n\t\t_Intensity(\"Intensity\", Range(0, 0.1)) = 0.01\n\t\t_Frequency(\"Frequency\", Range(0, 100)) = 20\n\t}\n\t\n\tSubShader\n\t{\n\t\tCGINCLUDE\n\t\t#include \"UnityCG.cginc\"\n\n\t\tstruct appdata\n\t\t{\n\t\t\tfloat4 vertex : POSITION;\n\t\t\tfloat3 normal : NORMAL;\n\t\t\tfloat2 uv : TEXCOORD0;\n\t\t};\n\n\t\tstruct v2f\n\t\t{\n\t\t\tfloat2 uv : TEXCOORD0;\n\t\t\tfloat4 vertex : SV_POSITION;\n\t\t\tfloat3 normal : NORMAL;\n\t\t};\n\n\t\tsampler2D _MainTex;\n\t\tfloat4 _MainTex_ST;\n\t\tfloat _Intensity;\n\t\tfloat _Frequency;\n\n\t\tv2f vert(appdata v)\n\t\t{\n\t\t\tv2f o;\n\t\t\to.vertex = UnityObjectToClipPos(v.vertex);\n\t\t\to.normal = normalize(mul(float4(v.normal, 0.0), unity_ObjectToWorld).xyz);\n\t\t\to.uv = TRANSFORM_TEX(v.uv, _MainTex);\n\n\t\t\tfloat4 newVertex = mul(v.vertex, unity_ObjectToWorld) + _Intensity * ((float4(o.normal, 0.0) * sin(o.uv.x * _Frequency + _Time.w)) + (float4(o.normal, 0.0) * sin(o.uv.y * _Frequency + _Time.w)));\n\n\t\t\to.vertex = UnityObjectToClipPos(newVertex);\n\n\t\t\treturn o;\n\t\t}\n\n\t\tENDCG\n\n\t\tPass \n\t\t{\n\t\t\tZWrite On\n\t\t\tZTest LEqual\n\n\t\t\tCGPROGRAM\n\t\t\t#pragma vertex vert\n\t\t\t#pragma fragment frag\n\n\t\t\thalf4 frag(v2f i) : COLOR \n\t\t\t{\n\t\t\t\treturn tex2D(_MainTex, i.uv);\n\t\t\t}\n\t\t\tENDCG\n\t\t}\n\t}\n}\n```\n\nIt's not the cleanest or most optimized thing in the world, but it *is* functional.  The main bulk of the heavy lifting is done in the `vert()` function.  Essentially what I'm doing is oscillating a vertex's position along its normal using a `sin()` function.  The vertex's final adjusted position depends on its texture UV coordinates as well as the Intensity and Frequency properties.  These last 2 values can be manipulated in code or in the inspector to customize the blobby effect.\n\n![unityDemonstrationSmaller.gif](\/\/\/raw\/a36\/3\/z\/2447c.gif)\n\nSo there are a couple of fairly problematic issues with this shader that prevent it from being super robust.  \n\nFirstly, it does not handle seams well.  If you look at the object too closely, or set the Intensity to be too high, you can see a break in the mesh that immediately breaks the blobby illusion.\n\nSecondly, this shader does not handle lighting or normal\/bump mapping in any way.  That would require a lot of extra work in the fragment shader that we unfortunately just did not have the time to implement.\n\nDespite these problems, we were able to create a halfway decent \u201corganic\u201d effect for any arbitrary object, including the little synapse connectors that wire up the inside of granny's head!\n\n![webBois.gif](\/\/\/raw\/a36\/3\/z\/2447d.gif)\n\nIt's a small little detail that required a super non-trivial amount of work, but we like to think that it looks a lot better than if it wasn't there at all!\n\nIf you're interested to see how it works in action, check it out at our game page!\n\nhttps:\/\/ldjam.com\/events\/ludum-dare\/44\/knit-worth\n\nAnd as always, thanks so much to everyone who has left feedback for us!  We're working hard to make sure to return the favor for everyone who comments on our game, but it may take some time, so we appreciate your patience!","comments":5,"comments-timestamp":"2019-05-02T11:12:27Z","created":"2019-05-02T04:44:51Z","files":[],"files-timestamp":0,"id":155875,"love":24,"love-timestamp":"2019-05-02T11:12:29Z","meta":[],"modified":"2019-05-02T11:12:29Z","name":"Making Organic Brain Chunks in Knit Worth Using Shaders","node-timestamp":"2019-05-02T05:04:50Z","parent":144497,"parents":[1,5,9,139254,144497],"path":"\/events\/ludum-dare\/44\/knit-worth\/making-organic-brain-chunks-in-knit-worth-using-shaders","published":"2019-05-02T05:04:50Z","scope":"public","slug":"making-organic-brain-chunks-in-knit-worth-using-shaders","subsubtype":"","subtype":"","type":"post","version":468849},"node_metadata":{"n_key":"155875","n_urlkey":"348100","n_parent":"144497","n_path":"\/events\/ludum-dare\/44\/knit-worth\/making-organic-brain-chunks-in-knit-worth-using-shaders","n_slug":"making-organic-brain-chunks-in-k","n_type":"post","n_subtype":"","n_subsubtype":"","n_author":"13882","n_created":"1556772291","n_modified":"1556795549","n_version":"468849","n_status":"WAYBACK"},"source_url":"https:\/\/ldjam.com\/events\/ludum-dare\/44\/knit-worth\/making-organic-brain-chunks-in-knit-worth-using-shaders","text":"A lot of times in game dev, you put a lot of effort into a very specific thing that ultimately goes unnoticed by players.\n  \nWhy?  \n\nBecause if that thing is *not* there, then players will *definitely* notice its absence.\n\nThat very specific thing for us was the \u201cblobby\u201d effect of Granny's brain in Knit Worth.\n\nIn Knit Worth, you use crochet needles to poke and prod at a sweet old lady's brain chunks.  Naturally, something like that should look soft and organic.  Our solution was to use a simple vertex shader to manipulate the object on a `sin()` based rhythm.  The result was something that looked like this:\n\n![blobbois.gif](\/\/\/raw\/a36\/3\/z\/2447b.gif)\n\nFor folks who don't exactly know how shaders work, essentially a shader file usually (though not always) contains two functions that manipulate whatever object it's attached to.  The vertex shader function manipulates the position of a mesh's vertices, while a fragment shader manipulates the colors that are drawn to that object.\n\nIn the case of our blobby effect, we only needed to write a vertex shader.  We weren't too concerned with changing the colors of the object fragments (a sacrifice that was made for the sake of time).  Anyhoo, without further ado, here it is in all it's glory:\n\n```\nShader \"Custom\/Pulsate\"\n{\n\tProperties\n\t{\n\t\t_MainTex(\"Texture\", 2D) = \"white\" {}\n\t\t_Color(\"Main Color\", Color) = (1.0, 1.0, 1.0, 1.0)\n\t\t_Intensity(\"Intensity\", Range(0, 0.1)) = 0.01\n\t\t_Frequency(\"Frequency\", Range(0, 100)) = 20\n\t}\n\t\n\tSubShader\n\t{\n\t\tCGINCLUDE\n\t\t#include \"UnityCG.cginc\"\n\n\t\tstruct appdata\n\t\t{\n\t\t\tfloat4 vertex : POSITION;\n\t\t\tfloat3 normal : NORMAL;\n\t\t\tfloat2 uv : TEXCOORD0;\n\t\t};\n\n\t\tstruct v2f\n\t\t{\n\t\t\tfloat2 uv : TEXCOORD0;\n\t\t\tfloat4 vertex : SV_POSITION;\n\t\t\tfloat3 normal : NORMAL;\n\t\t};\n\n\t\tsampler2D _MainTex;\n\t\tfloat4 _MainTex_ST;\n\t\tfloat _Intensity;\n\t\tfloat _Frequency;\n\n\t\tv2f vert(appdata v)\n\t\t{\n\t\t\tv2f o;\n\t\t\to.vertex = UnityObjectToClipPos(v.vertex);\n\t\t\to.normal = normalize(mul(float4(v.normal, 0.0), unity_ObjectToWorld).xyz);\n\t\t\to.uv = TRANSFORM_TEX(v.uv, _MainTex);\n\n\t\t\tfloat4 newVertex = mul(v.vertex, unity_ObjectToWorld) + _Intensity * ((float4(o.normal, 0.0) * sin(o.uv.x * _Frequency + _Time.w)) + (float4(o.normal, 0.0) * sin(o.uv.y * _Frequency + _Time.w)));\n\n\t\t\to.vertex = UnityObjectToClipPos(newVertex);\n\n\t\t\treturn o;\n\t\t}\n\n\t\tENDCG\n\n\t\tPass \n\t\t{\n\t\t\tZWrite On\n\t\t\tZTest LEqual\n\n\t\t\tCGPROGRAM\n\t\t\t#pragma vertex vert\n\t\t\t#pragma fragment frag\n\n\t\t\thalf4 frag(v2f i) : COLOR \n\t\t\t{\n\t\t\t\treturn tex2D(_MainTex, i.uv);\n\t\t\t}\n\t\t\tENDCG\n\t\t}\n\t}\n}\n```\n\nIt's not the cleanest or most optimized thing in the world, but it *is* functional.  The main bulk of the heavy lifting is done in the `vert()` function.  Essentially what I'm doing is oscillating a vertex's position along its normal using a `sin()` function.  The vertex's final adjusted position depends on its texture UV coordinates as well as the Intensity and Frequency properties.  These last 2 values can be manipulated in code or in the inspector to customize the blobby effect.\n\n![unityDemonstrationSmaller.gif](\/\/\/raw\/a36\/3\/z\/2447c.gif)\n\nSo there are a couple of fairly problematic issues with this shader that prevent it from being super robust.  \n\nFirstly, it does not handle seams well.  If you look at the object too closely, or set the Intensity to be too high, you can see a break in the mesh that immediately breaks the blobby illusion.\n\nSecondly, this shader does not handle lighting or normal\/bump mapping in any way.  That would require a lot of extra work in the fragment shader that we unfortunately just did not have the time to implement.\n\nDespite these problems, we were able to create a halfway decent \u201corganic\u201d effect for any arbitrary object, including the little synapse connectors that wire up the inside of granny's head!\n\n![webBois.gif](\/\/\/raw\/a36\/3\/z\/2447d.gif)\n\nIt's a small little detail that required a super non-trivial amount of work, but we like to think that it looks a lot better than if it wasn't there at all!\n\nIf you're interested to see how it works in action, check it out at our game page!\n\nhttps:\/\/ldjam.com\/events\/ludum-dare\/44\/knit-worth\n\nAnd as always, thanks so much to everyone who has left feedback for us!  We're working hard to make sure to return the favor for everyone who comments on our game, but it may take some time, so we appreciate your patience!","title":"Making Organic Brain Chunks in Knit Worth Using Shaders","wayback_source":[]}