Fluid Shader File

For anyone who wants to modify the shader to tweak the shading functionality, I will explain how the shading process works, though i personally not recommend.

The files used for fluid shading are in Assets/SSF_Particle2Fluid_ShaderUtil/Shaders/FluidRender.shader

The whole process can be divided into the following steps:

  • Read the surface parameters through the map:

TEXTURE2D(_ColorTex);
TEXTURE2D_FLOAT(_EyeDepthTex);
TEXTURE2D(_EyeNormalTex);
TEXTURE2D_FLOAT(_ParticleDataTex);
TEXTURE2D_FLOAT(_ThicknessTex);
StructuredBuffer<SSF_RenderParams> _RenderParams;

....
float fluidEyeDepth = SAMPLE_TEXTURE2D(_EyeDepthTex, sampler_PointClamp, uv).r;
float3 fluidColor = SAMPLE_TEXTURE2D(_ColorTex, sampler_LinearRepeat, uv).xyz;
float thickness = SAMPLE_TEXTURE2D(_ThicknessTex, sampler_LinearRepeat, uv).r;
float3 fluidEyeNormal = SAMPLE_TEXTURE2D(_EyeNormalTex, sampler_LinearRepeat, uv).xyz;
int paramIndex = SAMPLE_TEXTURE2D(_ParticleDataTex, sampler_PointClamp,uv).x;
float smoothness = _RenderParams[paramIndex].smoothness;
float refractiveIndex = _RenderParams[paramIndex].ior;
float fresnelPower = _RenderParams[paramIndex].fresnelPower;
float minReflectionRatio = _RenderParams[paramIndex].minReflectionRatio;
float maxReflectionRatio = _RenderParams[paramIndex].maxReflectionRatio;
float isTransparent = _RenderParams[paramIndex].isTransparent;
float4 ambientColor = _RenderParams[paramIndex].ambientColor;
float4 diffuseColor = _RenderParams[paramIndex].diffuseColor;
float4 specularColor = _RenderParams[paramIndex].specularColor;
  • We first filter out the pixels that are not blocked by the fluid particles and return them to the previously rendered color.

half4 color = SAMPLE_TEXTURE2D_X_LOD(_BlitTexture, sampler_LinearRepeat, uv, _BlitMipLevel);
#if UNITY_REVERSED_Z
real depth = SampleSceneDepth(uv);
#else
// Adjust z to match NDC for OpenGL
real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
#endif
float sceneEyeDepth = LinearEyeDepth(depth, _ZBufferParams);
       	if(fluidEyeDepth <= 0.0f || fluidEyeDepth > 1000.0f ||sceneEyeDepth < fluidEyeDepth) {
	return color;
}

Based on the above parameters, you can play with the shader to create different effects.

  • For example, I first made a blinn-phong rendering

// Calculate non-transparent color, using old model
Light mainLight = GetMainLight();
// the light direction is also expect to be a inverse since we care its relative angle to the normal
// so its world direction should be considered to treate inversely
float3 lightDir = -mul(unity_MatrixV, float4(mainLight.direction, 0.0)).xyz;
float3 specular = LightingSpecular(mainLight.color,lightDir,fluidEyeNormal,viewDir,specularColor,smoothness*32);
float3 diffuse = LightingLambert(mainLight.color,lightDir,fluidEyeNormal)*diffuseColor.rgb;
float3 ambient = ambientColor.rgb;
float3 finalColorNonTransparent = ambient + diffuse + specular;
  • In addition, you can use parameters such as thickness, fluid color, IOR, smoothness, etc. to create water rendering effects that include refraction and reflection:

// Calculate transparent color, with a combination of refraction and reflection
float eta =  1.0 / refractiveIndex;
float F0 = ((1.0 - eta) * (1.0 - eta)) / ((1.0 + eta) * (1.0 + eta));
float fresnelRatio = clamp(F0 + (1.0 - F0) * pow((1.0 - dot(viewDir, fluidEyeNormal)), fresnelPower), 0, 1);

float3 reflectionDir = reflect(-viewDir, fluidEyeNormal);
float3 reflectionDirWS = mul(unity_MatrixInvV, float4(reflectionDir, 0.0)).xyz;

float3 reflectionColor = GlossyEnvironmentReflection(reflectionDirWS, smoothness, half(1.0));

float3 colorAttennuation = computeAttennuation(thickness*5, 1-fluidColor);

half3 refractionDir = refract(-viewDir, fluidEyeNormal, eta);
float3 refractionColor = colorAttennuation * SAMPLE_TEXTURE2D(_BlitTexture,sampler_LinearRepeat, uv + refractionDir.xy * thickness  * 0.1f).xyz;

fresnelRatio = clamp(fresnelRatio, minReflectionRatio, maxReflectionRatio);
float3 finalColorTransparent = lerp(refractionColor, reflectionColor, fresnelRatio) ;

Of course, we can also implement shadow effects, but since Unity's API is not stable and open enough, we will consider updating it later.

Last updated