1. We've introduced thread tags, search within a thread and similar thread search. Read more here.
    Dismiss Notice
  2. Learn how you'll soon be able to publish your games to China in four simple steps with Xiaomi. Sign up now for early access.
    Dismiss Notice
  3. Get further faster with the Unity Plus Accelerator Pack, free for new Unity Plus subscribers for a limited time. Click here for more details.
    Dismiss Notice
  4. We've released our first Timeline Experimental Preview, our new tool for creating cutscenes and more! To check it out click here.
    Dismiss Notice
  5. Unity 5.5 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.5 in patch releases 1 & 2.
    Dismiss Notice
  7. Unity 5.6 beta is now available for download.
    Dismiss Notice

Raymarched ocean from Shadertoy

Discussion in 'Shaders' started by roberteker, Mar 18, 2017.

  1. roberteker

    roberteker

    Joined:
    Feb 22, 2017
    Posts:
    36
    So I came across this amazing Shadertoy ocean shader, which by sheer luck led me to find a Unity implementation, which works in VR no less:



    There is great documentation from the person who did the port here:

    https://www.shadertoy.com/view/llsXD2

    Now, I know next to nothing about shaders, but still managed to add color selection to this shader with a bit of internet searching. However, the sky color is still weird, because I don't think I've managed to figure it out completely yet. Also, can anyone who knows shaders a bit better tell me why the reflections of other objects go completely crazy only with certain colors:

    Code (CSharp):
    1. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    2. // ORIGINAL FROM HERE: https://www.reddit.com/r/oculus/comments/3hjl4e/raymarched_ocean_on_vive_in_unity_5_on_980_ti/cu80qfs/
    3.  
    4. Shader "Custom/RayMarchSkyboxSeascape" {
    5.     Properties {
    6.             _UpVector ("Up Vector", Vector) = (0.0,1.0,0.0)
    7.             _RightVector ("Up Vector", Vector) = (1.0,0.0,0.0)
    8.             _ForwardVector ("Up Vector", Vector) = (0.0,0.0,1.0)
    9.             _MyWorldPosition ("My World Location", Vector) = (0.0,0.0,0.0)
    10.             _MyWorldCameraLook ("My World Camera Look", Vector) = (0.0,0.0,0.0)
    11.             _SeaBaseColor ("Sea Base Color", Color) = (0.1,0.19,0.22,1.0)
    12.             _SeaWaterColor ("Sea Water Color", Color) = (0.8,0.9,0.6, 1.0)
    13.             _SkyColor ("Sky Color", Color) = (0.0,0.0,1.0,1.0)
    14.     }
    15.     SubShader {
    16.         Pass {
    17.             CGPROGRAM
    18.      
    19.             #include "UnityCG.cginc"
    20.             #pragma vertex vert
    21.             #pragma fragment frag
    22.      
    23.             #pragma target 3.0
    24.      
    25.             float4 _UpVector;
    26.             float4 _RightVector;
    27.             float4 _ForwardVector;
    28.             float3 _MyWorldPosition;
    29.             float3 _MyWorldCameraLookVector;
    30.             float3 _MyWorldCameraLook;
    31.             fixed4 _SeaBaseColor;
    32.             fixed4 _SeaWaterColor;
    33.             fixed4 _SkyColor;
    34.      
    35.             // Quality metric between 0 and 1 that is computed at the start of frag shader based on the angle
    36.             // between the world look direction and the world ray for that pixel
    37.             float fovQuality = 1.0;
    38.      
    39.             static const int NUM_STEPS = 5;
    40.             static const float PI         = 3.1415;
    41.             static const float EPSILON    = 1e-3;
    42.             float EPSILON_NRM    = 0.01 / 1024;
    43.  
    44.             // sky
    45.             static const float SKY_X = _SkyColor.rgb.r;
    46.             static const float SKY_Y = _SkyColor.rgb.g;
    47.             static const float SKY_Z = _SkyColor.rgb.b;
    48.  
    49.             // sea
    50.             static const int ITER_GEOMETRY_LOW  = 2;
    51.             static const int ITER_GEOMETRY_HIGH = 3;
    52.      
    53.             static const int ITER_FRAGMENT_LOW  = 4;
    54.             static const int ITER_FRAGMENT_HIGH = 5;
    55.      
    56.             static const float SEA_HEIGHT = 0.6;
    57.             static const float SEA_CHOPPY = 4.0;
    58.             static const float SEA_SPEED = 0.8;
    59.             static const float SEA_FREQ = 0.16;
    60.             static const float3 SEA_BASE = _SeaBaseColor.rgb;
    61.             static const float3 SEA_WATER_COLOR = _SeaWaterColor.rgb;
    62.             float SEA_TIME = 0;
    63.             static const float2x2 octave_m = float2x2(1.6,1.2,-1.2,1.6);
    64.  
    65.             float fract(float x) {
    66.                 return x - floor(x);
    67.             }
    68.      
    69.             float2 fract(float2 x) {
    70.                 return x - floor(x);
    71.             }
    72.      
    73.             float hash( float2 p ) {
    74.                 float h = dot(p,float2(127.1,311.7));
    75.                 return fract(sin(h)*43758.5453123);
    76.             }
    77.      
    78.             // TESTED
    79.             float noise( in float2 p ) {
    80.                 float2 i = floor( p );
    81.                 float2 f = fract( p );
    82.                 float2 u = f*f*(3.0-2.0*f);
    83.          
    84.  
    85.                 //return fract(p).x;
    86.          
    87.                 return -1.0+2.0*lerp( lerp( hash( i + float2(0.0,0.0) ),
    88.                                  hash( i + float2(1.0,0.0) ), u.x),
    89.                             lerp( hash( i + float2(0.0,1.0) ),
    90.                                  hash( i + float2(1.0,1.0) ), u.x), u.y);
    91.             }
    92.  
    93.             // lighting
    94.             float diffuse(float3 n,float3 l,float p) {
    95.                 return pow(dot(n,l) * 0.4 + 0.6,p);
    96.             }
    97.             float specular(float3 n,float3 l,float3 e,float s) {
    98.                 float nrm = (s + 8.0) / (3.1415 * 8.0);
    99.                 return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
    100.             }
    101.  
    102.             // sky
    103.             float3 getSkyColor(float3 e) {
    104.                 //return _SkyColor.rgb;
    105.                 e.y = max(e.y,0.0);
    106.                 float3 ret;
    107.                ret.x = max((1.0-e.y), SKY_X);
    108.                ret.y = max((1.0-e.y), SKY_Y);
    109.                ret.z = max((1.0-e.y), SKY_Z);
    110.                 return ret;
    111.             }
    112.  
    113.             /*
    114.                 ret.x = pow(1.0-e.y,2.0);
    115.                 ret.y = 1.0-e.y;
    116.                 ret.z = 0.6+(1.0-e.y)*0.4;
    117.             */
    118.  
    119.  
    120.             // TESTED
    121.             // sea
    122.             float sea_octave(float2 uv, float choppy) {
    123.                 uv += noise(uv);
    124.                 float2 wv = 1.0-abs(sin(uv));
    125.                 float2 swv = abs(cos(uv));
    126.                 wv = lerp(wv,swv,wv);
    127.                 return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
    128.             }
    129.      
    130.             float map(float3 p) {
    131.                 float freq = SEA_FREQ;
    132.                 float amp = SEA_HEIGHT;
    133.                 float choppy = SEA_CHOPPY;
    134.                 float2 uv = p.xz; uv.x *= 0.75;
    135.  
    136.                 // CHECKPOINT - TESTED TO HERE
    137.                 //return uv.x + uv.y;
    138.                // return p.y;
    139.  
    140.                 float d = 0.0, h = 0.0;
    141.                // p = float3(0.0, 0.0, 0.0);
    142.                 //return 0.4f;
    143.                 // int iters = ITER_GEOMETRY_LOW + ceil(fovQuality * (ITER_GEOMETRY_HIGH - ITER_GEOMETRY_LOW));
    144.                 for(int i = 0; i < ITER_GEOMETRY_HIGH; i++) { // ITER_GEOMETRY
    145.                     //d = 19.0; // remove
    146.              
    147.                     //if (i == 2) {
    148.                     //return 0.4f;
    149.                          
    150.                     d = sea_octave((uv+SEA_TIME)*freq,choppy);
    151.                     d += sea_octave((uv-SEA_TIME)*freq,choppy);
    152.  
    153.                     h += d * amp;
    154.                        
    155.                     uv = mul(octave_m, uv);
    156.              
    157.                     freq *= 1.9;
    158.                     amp *= 0.22;
    159.                     choppy = lerp(choppy,1.0,0.2);
    160.                 }
    161.  
    162.                 return p.y - h;
    163.             }
    164.  
    165.             float map_detailed(float3 p) {
    166.                 float freq = SEA_FREQ;
    167.                 float amp = SEA_HEIGHT;
    168.                 float choppy = SEA_CHOPPY;
    169.                 float2 uv = p.xz;
    170.                 uv.x *= 0.75;
    171.          
    172.                 float d, h = 0.0;
    173.          
    174.                 int iters = ITER_FRAGMENT_LOW + ceil(fovQuality * (ITER_FRAGMENT_HIGH - ITER_FRAGMENT_LOW));
    175.                 for(int i = 0; i < iters; i++) {  
    176.                     d = sea_octave((uv+SEA_TIME)*freq,choppy);
    177.                     d += sea_octave((uv-SEA_TIME)*freq,choppy);
    178.                     h += d * amp;  
    179.                     uv = mul(octave_m, uv);
    180.                     freq *= 1.9;
    181.                     amp *= 0.22;
    182.                     choppy = lerp(choppy,1.0,0.2);
    183.                 }
    184.                 return p.y - h;
    185.             }
    186.      
    187.             float3 getSeaColor(float3 p, float3 n, float3 l, float3 eye, float3 dist) {
    188.                 float fresnel = 1.0 - max(dot(n,-eye),0.0);
    189.                 fresnel = pow(fresnel,3.0) * 0.65;
    190.              
    191.                 float3 reflected = getSkyColor(reflect(eye,n));
    192.                 float3 refractted = SEA_BASE + diffuse(n,l,80.0) * SEA_WATER_COLOR * 0.12;
    193.          
    194.                 float3 color_ = lerp(refractted,reflected,fresnel);
    195.          
    196.                 float atten = max(1.0 - dot(dist,dist) * 0.001, 0.0);
    197.                 color_ += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
    198.          
    199.                 float c = specular(n,l,eye,60.0);
    200.                 color_ += float3(c, c, c);
    201.          
    202.                 return color_;
    203.             }
    204.  
    205.             // tracing
    206.             float3 getNormal(float3 p, float eps) {
    207.                 float3 n;
    208.                 n.y = map_detailed(p);
    209.                 n.x = map_detailed(float3(p.x+eps,p.y,p.z)) - n.y;
    210.                 n.z = map_detailed(float3(p.x,p.y,p.z+eps)) - n.y;
    211.                 n.y = eps;
    212.                 return normalize(n);
    213.             }
    214.  
    215.             float heightMapTracing(float3 ori, float3 dir, out float3 p) {
    216.                 p = float3(0.0, 0.0, 0.0);
    217.          
    218.                 float tm = 0.0;
    219.                 float tx = 1000.0;
    220.                 float hx = map(ori + dir * tx);
    221.                 if(hx > 0.0) return tx;
    222.                 float hm = map(ori + dir * tm);
    223.                 float tmid = 0.0;
    224.          
    225.                 for(int i = 0; i < NUM_STEPS; i++) {
    226.                     tmid = lerp(tm,tx, hm/(hm-hx));            
    227.                     p = ori + dir * tmid;            
    228.                     float hmid = map(p);
    229.                     if(hmid < 0.0) {
    230.                         tx = tmid;
    231.                         hx = hmid;
    232.                     } else {
    233.                         tm = tmid;
    234.                         hm = hmid;
    235.                     }
    236.                 }
    237.                 return tmid;
    238.             }
    239.  
    240.      
    241.             struct v2f {
    242.                 float4 position : SV_POSITION;
    243.                 //float2 uv : TEXCOORD0; // stores uv
    244.                 float3 worldSpacePosition : TEXCOORD0;
    245.                 float3 worldSpaceView : TEXCOORD1;
    246.             };
    247.      
    248.             v2f vert(appdata_full i) {
    249.                 SEA_TIME = 0; // TODO: swap above
    250.      
    251.                 v2f o;
    252.                 o.position = mul (UNITY_MATRIX_MVP, i.vertex);
    253.          
    254.                 float4 vertexWorld = mul(unity_ObjectToWorld, i.vertex);
    255.          
    256.                 o.worldSpacePosition = vertexWorld.xyz;
    257.                 o.worldSpaceView = vertexWorld.xyz - _WorldSpaceCameraPos;
    258.                 return o;
    259.             }
    260.  
    261.             fixed4 frag(v2f i) : SV_Target {
    262.                    EPSILON_NRM    = 0.35 / _ScreenParams.x;
    263.                    SEA_TIME = _Time[1] * SEA_SPEED;
    264.      
    265.                 float3 ro = _WorldSpaceCameraPos;
    266.                 //float3 ro = float3(0.0, 3.5, 0.0); // TODO: remove
    267.          
    268.                 float3 rd = normalize(i.worldSpaceView);
    269.      
    270.                 // VR Quality based on angular distance from look direction
    271.                 fovQuality = dot(_MyWorldCameraLook, rd);
    272.                 fovQuality = pow(fovQuality, 6);
    273.                  
    274.                 // tracing
    275.                 float3 p = float3(5.0,233.0,1.0);
    276.                 heightMapTracing(ro,rd,p);
    277.                 float3 dist = p - ro;
    278.          
    279.                 // Increase epsilon for lower quality pixels
    280.                 float fovQualityNormalEpsilonFactor = 1.0 + saturate(0.8 - fovQuality);
    281.                 fovQualityNormalEpsilonFactor = dot(fovQualityNormalEpsilonFactor, fovQualityNormalEpsilonFactor);
    282.          
    283.                 fovQualityNormalEpsilonFactor = 1.0;
    284.                 float distToPixelWorldSquared = dot(dist, dist);
    285.          
    286.                 float3 n = getNormal(p, distToPixelWorldSquared * EPSILON_NRM * fovQualityNormalEpsilonFactor);
    287.          
    288.                 float3 light = normalize(float3(sin(SEA_TIME * 0.03f),1.0,cos(SEA_TIME * 0.03f)));
    289.                  
    290.                 //return float4(p.x, p.y, p.z, 1.0);
    291.                      
    292.                 // color
    293.                 float3 color_ = lerp(
    294.                     getSkyColor(rd),
    295.                     getSeaColor(p,n,light,rd,dist),
    296.                     pow(smoothstep(0.0,-0.05,rd.y),0.3));
    297.                  
    298.  
    299.                 //float3 c = getSkyColor(rd);
    300.                 //return float4(c.x, c.y, c.z, 1.0);
    301.          
    302.                 //return float4(p.x, p.y, p.z, 1.0);
    303.                 //float2 f = p.xy;
    304.                 //float n2 = noise(f);
    305.                 //return float4(n2, n2, n2, 1.0);
    306.                 //float2 n3 = float2(5.1, 4.3);
    307.                 //float n2 = n3 - floor (n3);
    308.                 //float n2 = noise(n3);
    309.          
    310.                 //p = ro + rd * 50.0;
    311.        
    312.                 //float j = map(ro + rd * 50.0);
    313.                 //float j = map_detailed(ro + rd * 50.0);
    314.                //float j = sea_octave((ro + rd * 50.0).xz, 4.0);
    315.                 //return float4(j, j, j, 1.0);
    316.               //  return float4(noise(rd.xy), noise(rd.xz), noise(rd.yz), 1.0);
    317.                // return float4(rd.x, rd.y, rd.z, 1.0);
    318.                                  
    319.                 float3 finalColor = pow(color_,float3(0.75, 0.75, 0.75));
    320.          
    321.                 // !! Visualize field of view quality falloff raw
    322.                 // finalColor = float3(fovQuality, fovQuality, fovQuality);
    323.          
    324.                 // !! Visualize field of view quality falloff blended
    325.                 // finalColor = lerp(finalColor, float3(1.0f, 0.0f, 0.0f), fovQuality);
    326.          
    327.                 return float4(finalColor.x, finalColor.y, finalColor.z, 1.0);
    328.  
    329.             }
    330.  
    331.             ENDCG
    332.         }
    333.     }
    334. }
    EDIT: Also, if anyone knows perhaps how to ignore the sky completely so you could apply this material to something other than a skybox, that would be really nice... getting some clouds and sun into the scene... but then I guess it would need to receive light information from the skybox which is probably quite a rewrite...
     
    Last edited: Mar 19, 2017