├── PerlinNoise.cs ├── README.md ├── TesselationShader.shader └── TessellatedWater.cs /PerlinNoise.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | 4 | [ExecuteInEditMode] 5 | public class PerlinNoise : MonoBehaviour 6 | { 7 | private Texture2D permutationTable; 8 | 9 | // Use this for initialization 10 | public void Start () 11 | { 12 | Random.seed = (int) Time.time; 13 | this.generatePermutation((int) (Random.value * 100)); 14 | } 15 | 16 | // Update is called once per frame 17 | public void Update () 18 | { 19 | // Update the texture here for setting new random values 20 | // this.updatePermutation (); 21 | // this.generatePermutation((int) (Random.value * 100)); 22 | this.renderer.sharedMaterial.SetTexture ("_PermutationTable", this.permutationTable); 23 | } 24 | 25 | // Perlin noise implementation 26 | public void generatePermutation(int seed) 27 | { 28 | Random.seed = seed; 29 | 30 | // 256 Permutation 31 | this.permutationTable = new Texture2D(256, 1, TextureFormat.Alpha8, false); 32 | 33 | 34 | for(int i = 0; i < this.permutationTable.width; i++) 35 | { 36 | float permVal = Random.value; 37 | this.permutationTable.SetPixel (i, 0, new Color(permVal, permVal, permVal, permVal)); 38 | } 39 | 40 | this.permutationTable.Apply (); 41 | } 42 | 43 | public void updatePermutation() 44 | { 45 | Texture2D newTex = new Texture2D(256, 1, TextureFormat.Alpha8, false); 46 | 47 | // Fast copy 48 | newTex.SetPixels(1,0,255,1,this.permutationTable.GetPixels (1,0,255,1)); 49 | 50 | Random.seed = (int)Time.time; 51 | float permVal = Random.value; 52 | newTex.SetPixel (0, 0, new Color(permVal, permVal, permVal, permVal)); 53 | 54 | newTex.Apply (); 55 | 56 | this.permutationTable = newTex; 57 | } 58 | 59 | /*public void OnGUI() 60 | { 61 | GUI.DrawTexture (new Rect(0,0,256,20), this.permutationTable); 62 | }*/ 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Unity ocean shader 2 | ========= 3 | 4 | This unity shader "simulates" an ocean based on a displacement map. 5 | It supports displacement map scrolling (tiled), bumpmapping, bumpmap scrolling, specular lightning, tessellation, caustics, cubemap reflection and fresnel color. 6 | It is based on the unity free water shader and the WaterSimple.cs scrolling script. 7 | 8 | The shader is still work in progress, there are still some features planned and the code still need some tweaking. 9 | 10 | Current features 11 | ========= 12 | 13 | - Fresnel lens colors 14 | - Caustics 15 | - Specular lightning 16 | - Cubemap reflections 17 | - Tessellation (distance, edge length and static based) 18 | - Displacement mapping (tiled+scrolling) 19 | - Bumpmapping (+scrolling) 20 | 21 | Planned features 22 | ========= 23 | 24 | - Perlin noise 25 | - Own lightning model 26 | - Simple fallback-shader for ex. mobile devices 27 | - Displacement map generator 28 | 29 | License 30 | ========= 31 | Copyright (c) 2013 Kenneth Ellersdorfer 32 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 33 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 34 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /TesselationShader.shader: -------------------------------------------------------------------------------- 1 | Shader "Water/Tessellated Water" { 2 | Properties { 3 | _Color ("Color", color) = (1,1,1,0) 4 | _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5) 5 | _Gloss ("Spec gloss", Range(0,2)) = 0.5 6 | _Shininess ("Spec shininess", Range(0,2)) = 0.5 7 | 8 | _FresnelTex ("Fresnel color (RGB)", 2D) = "white" {} 9 | _DispTex ("Disp Texture", 2D) = "black" {} 10 | _NormalMap ("Normalmap", 2D) = "bump" {} 11 | _ReflectMap ("Reflection Cubemap", Cube) = "white" {} 12 | 13 | _ReflectStrength ("Reflection strength", Range(0,1)) = 0.5 14 | 15 | _Displacement ("Displacement", Range(0, 10.0)) = 0.3 16 | _DisplacementMul ("Displacement multiplier", Range(0, 4.0)) = 0.3 17 | DispSpeed ("Displacement speed (map1: x=x,y=y, map2: x=z, y=w)", Vector) = (1,1,1,1) 18 | 19 | _WaveScale ("Wave scale", Range (0.02,1.0)) = .07 20 | WaveSpeed ("Wave speed (map1 x,y; map2 x,y)", Vector) = (2,1,-2,-1) 21 | 22 | _EdgeLength ("Edge length (1-50)", Range(1,50)) = 4 23 | _MinTessDist ("Tess min distance", float) = 0 24 | _MaxTessDist ("Tess max distance", float) = 100 25 | _Tessellation ("Static tesselation", Range(1,32)) = 1 26 | _Phong ("Phong Strengh", Range(0,1)) = 0.5 27 | 28 | _CausticTex ("Caustics texture", 2D) = "black" {} 29 | _CausticStrength ("Caustics strength", Range(0,1)) = 0 30 | 31 | _PermutationTable ("Permutation table", 2D) = "white" {} 32 | _NoiseStrength ("Noise strength", Range(0, 1)) = 0.5 33 | } 34 | SubShader { 35 | Tags { "RenderType"="Opaque" "Quene"="Transparent" } 36 | LOD 500 37 | Blend SrcAlpha OneMinusSrcAlpha 38 | ZWrite On 39 | 40 | CGPROGRAM 41 | #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessEdge tessphong:_Phong approxview nolightmap 42 | #pragma target 5.0 43 | #include "Tessellation.cginc" 44 | #include "UnityCG.cginc" 45 | 46 | struct appdata { 47 | float4 vertex : POSITION; 48 | float4 tangent : TANGENT; 49 | float3 normal : NORMAL; 50 | float2 texcoord : TEXCOORD0; 51 | }; 52 | 53 | uniform float _EdgeLength; 54 | uniform float _Tessellation; 55 | uniform float _MinTessDist; 56 | uniform float _MaxTessDist; 57 | uniform float _WaveScale; 58 | uniform float4 _WaveOffset; 59 | uniform float4 _DispOffset; 60 | 61 | uniform float _Displacement; 62 | uniform float _DisplacementMul; 63 | 64 | uniform float _Phong; 65 | 66 | // Samplers 67 | uniform sampler2D _DispTex; 68 | uniform sampler2D _FresnelTex; 69 | uniform sampler2D _NormalMap; 70 | uniform sampler2D _CausticTex; 71 | uniform sampler2D _PermutationTable; 72 | uniform samplerCUBE _ReflectMap; 73 | 74 | uniform fixed4 _Color; 75 | uniform fixed _Gloss; 76 | uniform fixed _Shininess; 77 | uniform fixed _CausticStrength; 78 | uniform float _ReflectStrength; 79 | uniform float _NoiseStrength; 80 | 81 | // Used by TRANSFORM_TEX 82 | uniform float4 _DispTex_ST; 83 | 84 | struct Input { 85 | float3 worldRefl; 86 | float3 viewDir; 87 | float2 uv_Underground; 88 | float3 worldPos; 89 | float displacement; 90 | INTERNAL_DATA 91 | }; 92 | 93 | // Perlin noise lib 94 | // Noise is currently not done! I'll implement noise animation later. 95 | float FADE(float t) { return t * t * t * ( t * ( t * 6.0f - 15.0f ) + 10.0f ); } 96 | 97 | float LERP(float t, float a, float b) { return (a) + (t)*((b)-(a)); } 98 | 99 | int PERM(int i) 100 | { 101 | return tex2Dlod(_PermutationTable, float4((float)i, 0.0, 0, 0)).a * 255.0f; 102 | } 103 | 104 | float GRAD2(int hash, float x, float y) 105 | { 106 | int h = hash % 16; 107 | float u = h<4 ? x : y; 108 | float v = h<4 ? y : x; 109 | int hn = h % 2; 110 | int hm = (h/2) % 2; 111 | return ((hn != 0) ? -u : u) + ((hm != 0) ? -2.0f*v : 2.0f*v); 112 | } 113 | 114 | float NOISE2D(float x, float y) 115 | { 116 | //returns a noise value between -0.75 and 0.75 117 | int ix0, iy0, ix1, iy1; 118 | float fx0, fy0, fx1, fy1, s, t, nx0, nx1, n0, n1; 119 | 120 | ix0 = floor(x); // Integer part of x 121 | iy0 = floor(y); // Integer part of y 122 | fx0 = x - ix0; // Fractional part of x 123 | fy0 = y - iy0; // Fractional part of y 124 | fx1 = fx0 - 1.0f; 125 | fy1 = fy0 - 1.0f; 126 | ix1 = (ix0 + 1) % 256; // Wrap to 0..255 127 | iy1 = (iy0 + 1) % 256; 128 | ix0 = ix0 % 256; 129 | iy0 = iy0 % 256; 130 | 131 | t = FADE( fy0 ); 132 | s = FADE( fx0 ); 133 | 134 | nx0 = GRAD2(PERM(ix0 + PERM(iy0)), fx0, fy0); 135 | nx1 = GRAD2(PERM(ix0 + PERM(iy1)), fx0, fy1); 136 | 137 | n0 = lerp(nx0, nx1, t); 138 | 139 | nx0 = GRAD2(PERM(ix1 + PERM(iy0)), fx1, fy0); 140 | nx1 = GRAD2(PERM(ix1 + PERM(iy1)), fx1, fy1); 141 | 142 | n1 = lerp(nx0, nx1, t); 143 | 144 | return 0.507f * lerp(n0, n1, s); 145 | 146 | } 147 | // Perlin noise lib end! 148 | 149 | float4 tessEdge (appdata v0, appdata v1, appdata v2) 150 | { 151 | float tess = UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength) + _Tessellation; 152 | return UnityDistanceBasedTess(v0.vertex, v1.vertex, v2.vertex, _MinTessDist, _MaxTessDist, tess); 153 | } 154 | 155 | void disp (inout appdata v) 156 | { 157 | // Displacement map 158 | fixed2 texcoords = TRANSFORM_TEX(v.texcoord, _DispTex); 159 | fixed4 displacementCoords = float4(texcoords,texcoords) / unity_Scale.w + _DispOffset; 160 | 161 | float d = tex2Dlod(_DispTex, float4(displacementCoords.xy * float2(.4, .45),0,0)).r; 162 | float d2 = tex2Dlod(_DispTex, float4(displacementCoords.zw,0,0)).r; 163 | float displacement = 1; 164 | 165 | 166 | // If there is no noise, don't calculate it 167 | if (_NoiseStrength > 0) 168 | { 169 | displacement = (d+d2) * ((_Displacement * _DisplacementMul) + ((NOISE2D(v.vertex.x, v.vertex.z) * _NoiseStrength) * sin(_Time.y))) ; 170 | } 171 | else 172 | { 173 | displacement = (d+d2) * (_Displacement * _DisplacementMul); 174 | } 175 | 176 | // Displace 177 | v.vertex.y += v.normal.y * displacement; 178 | } 179 | 180 | void surf (Input IN, inout SurfaceOutput o) 181 | { 182 | // scroll bump waves 183 | fixed4 temp; 184 | temp.xyzw = IN.worldPos.xzxz * _WaveScale / unity_Scale.w + _WaveOffset; 185 | fixed3 bump1 = UnpackNormal(tex2D( _NormalMap, temp.xy * float2(.4, .45) )).rgb; 186 | fixed3 bump2 = UnpackNormal(tex2D( _NormalMap, temp.wz )).rgb; 187 | o.Normal = (bump1 + bump2) * 0.5; 188 | 189 | // Reflection 190 | fixed3 R = IN.viewDir + ( 2 * dot(IN.viewDir, o.Normal )); 191 | fixed4 reflectionColor = texCUBE(_ReflectMap, R); 192 | 193 | // Fresnel 194 | fixed fresnel = saturate(dot(IN.viewDir, o.Normal)); 195 | fixed4 c = tex2D (_FresnelTex, float2(fresnel, fresnel)) * _Color; 196 | 197 | o.Albedo = c.rgb; 198 | 199 | // Calculate emission 200 | fixed3 emissionColor = float3(reflectionColor.rgb * _ReflectStrength); 201 | emissionColor.rgb = lerp(emissionColor.rgb, tex2D(_CausticTex, o.Normal), _CausticStrength); 202 | 203 | o.Emission = emissionColor.rgb; 204 | o.Alpha = _Color.a; 205 | 206 | // Specular 207 | o.Specular = _Shininess; 208 | o.Gloss = _Gloss; 209 | } 210 | ENDCG 211 | } 212 | 213 | FallBack "Diffuse" 214 | 215 | } 216 | -------------------------------------------------------------------------------- /TessellatedWater.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | // Sets up transformation matrices to scale&scroll water waves 4 | // for the case where graphics card does not support vertex programs. 5 | 6 | [ExecuteInEditMode] 7 | public class TessellatedWater : MonoBehaviour 8 | { 9 | 10 | void Update() 11 | { 12 | if( !renderer ) 13 | return; 14 | Material mat = renderer.sharedMaterial; 15 | if( !mat ) 16 | return; 17 | 18 | Vector4 waveSpeed = mat.GetVector( "WaveSpeed" ); 19 | Vector4 dispSpeed = mat.GetVector( "DispSpeed" ); 20 | float waveScale = mat.GetFloat( "_WaveScale" ); 21 | float t = Time.time / 20.0f; 22 | 23 | // Bump 24 | Vector4 offset4 = waveSpeed * (t * waveScale); 25 | Vector4 offsetClamped = new Vector4(Mathf.Repeat(offset4.x,1.0f), Mathf.Repeat(offset4.y,1.0f), Mathf.Repeat(offset4.z,1.0f), Mathf.Repeat(offset4.w,1.0f)); 26 | mat.SetVector( "_WaveOffset", offsetClamped ); 27 | 28 | // Displacement 29 | Vector4 offset4disp = dispSpeed * (t); 30 | Vector4 offsetdispClamped = new Vector4(Mathf.Repeat(offset4disp.x,1.0f), Mathf.Repeat(offset4disp.y,1.0f), Mathf.Repeat(offset4disp.z,1.0f), Mathf.Repeat(offset4disp.w,1.0f)); 31 | mat.SetVector( "_DispOffset", offsetdispClamped ); 32 | } 33 | } 34 | --------------------------------------------------------------------------------