-->

分類

2016年6月19日 星期日

Unity 2d water blob

references:
[1] http://codeartist.mx/tutorials/liquids/

based on [1], I made a shader that combines Unity default sprite shader and the metaball calculation. This shader is used on Sprite of water particle, not on the Render Textures as the implementation of [1]

here is the result video


shader code:

Shader "2D/SpriteMetaball"
{
 Properties
 {
  _MainTex ("Texture", 2D) = "white" {}
  _Color("Tint Color", Color) = (1,1,1,1)
  _EdgeThreshold("EdgeThreshold", Range(0,1)) = 0.2
  [MaterialToggle] PixelSnap("Pixel snap", Float) = 0
  _CenterSaturation("CenterSaturation", Range(1,100)) = 2
  _StepSize("StepSize", Range(0.1,1)) = 1
 }
 SubShader
 {
  Tags 
  {
   "Queue" = "Transparent"
   "IgnoreProjector" = "True"
   "RenderType" = "Transparent"
   "PreviewType" = "Plane"
   "CanUseSpriteAtlas" = "True"
  }

  Cull Off
  Lighting Off
  ZWrite Off
  Blend One OneMinusSrcAlpha

  Pass
  {
   CGPROGRAM
   #pragma vertex vert
   #pragma fragment frag
   #pragma multi_compile DUMMY PIXELSNAP_ON
   #pragma shader_feature ETC1_EXTERNAL_ALPHA
   
   #include "UnityCG.cginc"

   struct appdata
   {
    float4 vertex : POSITION;
    fixed4 color : COLOR;
    float2 uv : TEXCOORD0;
   };

   struct v2f
   {
    float2 uv : TEXCOORD0;
    fixed4 color : COLOR;
    float4 vertex : SV_POSITION;
   };

   sampler2D _MainTex;
   float4 _MainTex_ST;
   //tint color
   float4 _Color;
   //when texture color's alpha is below _EdgeThreshold, that color is discarded and the edge of rendered result formed
   //but it turns out that I got the result I want with _EdgeThreshold as 0...
   half _EdgeThreshold;
   /*
    higher _CenterSaturation makes the color from texture saturated faster(easier to become 1),
    since the default sprite texture this shader used has higher alpha in the center, 
    this value determined the how much the center part of rendered result is saturated 
   */
   half _CenterSaturation;
   //I think this value originally is related to metaball isosurface calculation,
   //but it may not be so useful in current implementation since I multiply texture's alpha which is formed as radial gradient 
   half _StepSize;

   sampler2D _AlphaTex;

   v2f vert (appdata v)
   {
    v2f o;
    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    #ifdef PIXELSNAP_ON
    o.vertex = UnityPixelSnap(o.vertex);
    #endif
    return o;
   }

   float4 SampleSpriteTexture(float2 uv)
   {
    float4 color = tex2D(_MainTex, uv);

#if ETC1_EXTERNAL_ALPHA
    // get the color from an external texture (usecase: Alpha support for ETC1 on android)
    color.a = tex2D(_AlphaTex, uv).r;
#endif //ETC1_EXTERNAL_ALPHA

    return color;
   }
   
   float4 frag (v2f i) : SV_Target
   {
    float4 col = SampleSpriteTexture(i.uv);
    
    float4 finalColor = col;
    if (finalColor.a > _EdgeThreshold) {
     //tint color
     finalColor *= _Color;
     //metaball isosurface
     finalColor.rgb *= float3(floor(finalColor.r * _CenterSaturation)*_StepSize, floor(finalColor.g * _CenterSaturation)*_StepSize, floor(finalColor.b * _CenterSaturation)*_StepSize);
     //this line kind of makes the isosurface of metaball formed by floor function and _StepSize meaningless, but I think it makes the rendered result looks better    
     finalColor.rgb *= finalColor.a;
    }
    else {
     discard;
    }

    return finalColor;
   }
   ENDCG
  }
 }
 Fallback "VertexLit"
}


here is the texture used for the water particle's SpriteRenderer(it's white with alpha, so you might only see a blank block here, but there is an image)




here is the settings of water particle:
you need to create a material with the shader code
the WaterBlob Sprite is the white image above(renamed from "RadialGradient" to "WaterBlob" in my project)

沒有留言:

張貼留言