on
Procedural World - Water
In this post I’ll be going over a simple water material I made for my procedural world project.
Multiple Materials in a Mesh
Water blocks use a different material than the other blocks in the engine for far. It’s fairly easy to set this up.
Each mesh in unity can have any number of submeshes
. The material used for that submesh corresponds to the list of materials specified in the MeshRenderer
component. So I simple adjusted the mesh generators return an array of MeshData. Different blocks are assigned to different meshes. So far all blocks are added to the “default” submesh with the exception of water which is added to another submesh.
Water Shader
I wrote a really simple water shader to test out having multiple materials in a mesh.
I used this tutorial as a reference.
Shader "Custom/Water" {
Properties {
// color of the water
_Color("Color", Color) = (1,1,1,1)
// color of the edge effect
_EdgeColor("Edge Color", Color) = (1,1,1,1)
// width of the edge
_DepthFactor("Depth Factor", float) = 1.0
_WaterTexture("Water Texture", 2D) = "white"{}
_WaveSpeed("Wave Speed", float) = 0.0
_WaveTexture("Wave Texture", 2D) = "white" {}
}
SubShader {
Tags {
"Queue" = "Transparent"
"RenderType" = "Transparent"
}
LOD 100
CGPROGRAM
#pragma surface surf Standard fullforwardshadows alpha
#pragma target 3.0
#include "UnityCG.cginc"
struct Input
{
float3 worldPos;
float4 screenPos;
};
sampler2D _CameraDepthTexture;
sampler2D _WaterTexture;
sampler2D _WaveTexture;
fixed4 _Color;
fixed4 _EdgeColor;
half _DepthFactor;
half _WaveSpeed;
half _WaveAmp;
void surf(Input i, inout SurfaceOutputStandard o) {
// get depth at screen position
float4 depthSample = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, i.screenPos);
// get the depth [0, 1]
float depth = LinearEyeDepth(depthSample).r;
fixed4 foamLine = 1 - saturate(_DepthFactor * (depth - i.screenPos.w));
// water texture
float2 texCoord = float2(frac(i.worldPos.x), frac(i.worldPos.z));
// sample random noise
float2 waveOffset = tex2D(_WaveTexture, texCoord) * sin(_Time * _WaveSpeed);
// get color of water from offset
fixed4 waterColor = tex2D(_WaterTexture, texCoord + waveOffset);
// foam color
fixed4 c = _Color + foamLine * _EdgeColor;
// mix colors together
o.Albedo = c.rgb * waterColor;
o.Alpha = _Color.a;
o.Metallic = 0.5;
o.Smoothness = 0.5;
}
ENDCG
}
}
Important Notes
- The
Queue
field inTags
needs to be set toTransparent
- The
alpha
option needs to be specified#pragma surface surf Standard fullforwardshadows alpha
Issues
A problem that has come up is that since the water material is transparent you can now see hidden faces of adjacent chunks. See below.
The best thing to do is to fix the greedy mesher so that it does not create these hidden faces.