Reputation: 173
I don't know much about shader :( if someone could help
I am using this free 2d water asset it contains a water shader. I want to edit that shader so it looks more like 2.5d or 3d.
I want to make it look like
Adding a foam type thing on top and make it little reflective
shader used in the asset to make 2d water
Shader "Water2D/Metaballs_Simple" {
Properties {
_MainTex ("Texture", 2D) = "white" { }
_Color ("Main color", Color) = (1,1,1,1)
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
_Stroke ("Stroke alpha", Range(0,1)) = 0.1
_StrokeColor ("Stroke color", Color) = (1,1,1,1)
}
/// <summary>
/// Multiple metaball shader.
/// </summary>
SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
GrabPass{}
Pass {
Blend SrcAlpha OneMinusSrcAlpha
// Blend One One // Additive
// Blend One OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float4 _Color;
sampler2D _MainTex;
fixed _Cutoff;
fixed _Stroke;
half4 _StrokeColor;
float2 _screenPos;
float4 _CameraDepthTexture_TexelSize;
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
float4 _MainTex_ST;
v2f vert (appdata_base v){
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
return o;
};
half4 frag (v2f i) : COLOR{
half4 texcol= tex2D (_MainTex, i.uv);
//half4 finalColor = texcol;
clip(texcol.a - _Cutoff);
if (texcol.a < _Stroke) {
texcol = _StrokeColor;
} else {
texcol = _Color;
}
return texcol;
}
ENDCG
}
}
Fallback "VertexLit"
}
Upvotes: 1
Views: 700
Reputation: 1268
Judging by your shader, it appears as if the fluid has a texture containing an alpha gradient based on the distance to the edge. If this is anything similar to a distance field, then you can use it to reconstruct a screen-space normal based on the derivatives.
float3 normal;
normal.x = ddx(texcol.a);
normal.y = ddy(texcol.a);
normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
Then, you can use this value to calculate some basic blinn-phong specular lighting. This involves using the sum of the vector to the light and the vector to the camera to get a half-way vector.
Since our normal is in camera space, we might want to do all other calculations in camera space too. Ideally, we want to do as many calculations as we can inside the vertex shader and then pass them over to the fragment shader:
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 viewDir : TEXCOORD1;
float3 lightDir : TEXCOORD2;
};
float4 _MainTex_ST;
v2f vert (appdata_base v){
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
o.viewDir = mul((float3x3)UNITY_MATRIX_MVP, ObjSpaceViewDir(v.vertex));
o.lightDir = mul((float3x3)UNITY_MATRIX_MVP, ObjSpaceLightDir (v.vertex));
o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
return o;
};
I'm assuming that ObjSpaceLightDir works for 2D lights, but i'm not sure. Inside the fragment shader, we can now get the specular highlights:
float3 lightDir = normalize(i.lightDir);
float3 viewDir = normalize(i.viewDir);
float3 halfDir = normalize(lightDir + viewDir);
float spec = pow(saturate(dot(normal, halfDir)), _Glossiness * 128);
return saturate(_BaseColor + spec);
You can also add some subtle lambert shading to create shadows underneath:
float diff = saturate(dot(normal, lightDir));
// 20% diffuse contribution, because lots of light passes through the liquid.
// Can be tweaked based on artistic needs.
return saturate(_BaseColor * (0.8 + 0.2 * diff) + spec);
Be aware though that this will not properly give the illusion of thickness that your reference has. For this, you need to simulate the thickness of the fluid into a heightmap and generate normals based on that. You can break up the shape of the specular by adding some procedural noise to it, though i haven't tried this. A big challenge when writing shaders is that the GPU doesn't know anything about the context of the pixel other than what you give to it, so things like the distance to the nearest edge have to be pre-computed and fed into the material as textures. I'm honestly not sure how they manage to produce the foam on top - it might be a part of the water texture or a separate sprite rendered in the background.
Upvotes: 1