Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <script type="text/fragment" id="fragShader">#version 300 es
  precision highp float;
  
  uniform vec2 u_resolution;
  uniform float u_time;
  uniform vec2 u_mouse;
  uniform sampler2D s_noise;
  uniform vec3 u_cp;
  
  in vec2 v_uv;
  out vec4 c;
  
  /* Shading constants */
  /* --------------------- */
  const vec3 LP = vec3(-0.6, 0.7, -0.3);  // light position
  const vec3 LC = vec3(.85,0.80,0.70);    // light colour
  const vec3 HC1 = vec3(.5, .4, .3);      // hemisphere light colour 1
  const vec3 HC2 = vec3(0.1,.1,.6)*.5;    // hemisphere light colour 2
  const vec3 HLD = vec3(0,1,0)*.5+.5;     // hemisphere light direction
  const vec3 BC = vec3(0.25,0.25,0.25);   // back light colour
  const vec3 FC = vec3(1.30,1.20,1.00);   // fresnel colour
  const float AS = .5;                     // ambient light strength
  const float DS = 1.;                     // diffuse light strength
  const float BS = .3;                     // back light strength
  const float FS = .3;                     // fresnel strength
  /* Raymarching constants */
  /* --------------------- */
  const float MAX_TRACE_DISTANCE = 7.;             // max trace distance
  const float INTERSECTION_PRECISION = 0.001;       // precision of the intersection
  const int NUM_OF_TRACE_STEPS = 256;               // max number of trace steps
  const float STEP_MULTIPLIER = .9;                 // the step mutliplier - ie, how much further to progress on each step
  
  /* Structures */
  /* ---------- */
  struct Camera {
    vec3 ro;
    vec3 rd;
    vec3 forward;
    vec3 right;
    vec3 up;
    float FOV;
  };
  struct Surface {
    float len;
    vec3 position;
    vec3 colour;
    float id;
    float steps;
    float AO;
  };
  struct Model {
    float dist;
    vec3 colour;
    float id;
  };
  
  /* Utilities */
  /* ---------- */
  vec2 toScreenspace(in vec2 p) {
    vec2 uv = (p - 0.5 * u_resolution.xy) / min(u_resolution.y, u_resolution.x);
    return uv;
  }
  mat2 R(float a) {
    float c = cos(a);
    float s = sin(a);
    return mat2(c, -s, s, c);
  }
  Camera getCamera(in vec2 uv, in vec3 pos, in vec3 target) {
    vec3 f = normalize(target - pos);
    vec3 r = normalize(vec3(f.z, 0., -f.x));
    vec3 u = normalize(cross(f, r));
    
    float FOV = .6;
    
    return Camera(
      pos,
      normalize(f + FOV * uv.x * r + FOV * uv.y * u),
      f,
      r,
      u,
      FOV
    );
  }
  float smin(float a, float b, float k) {
    k *= 1.0/(1.0-sqrt(0.5));
    return max(k,min(a,b))-length(max(vec2(k-a,k-b), 0.0));
  }
  
  
  //--------------------------------
  // Modelling
  //--------------------------------
  Model model(vec3 p) {
    p.xy *= R(u_time*2.+.5);
    vec2 a = p.xy * R(p.z+u_time*2.);
    float ls = length(abs(a)-vec2(.2, .1));
    p.zy *= R(u_time*1.5+.5);
    a = p.zy * R(p.x+1.+u_time*1.5);
    ls = smin(length(abs(a)-vec2(.2, .1)), ls, .08);
    float sp = length(p)-.5;
    float spo = min(
      length(vec2(sp, ls-.2))-.02,
      length(vec2(sp+.1, ls-.1))-.02
    );
    float d = min(
      min(ls-smoothstep(-.2, 1., sp)*.1-.001, spo*.8),
      sp+.2
      );
    vec3 colour = vec3(.8,.3,.6);
    return Model(d, colour, 1.);
  }
  Model map( vec3 p ){
    return model(p);
  }
  
  /* Modelling utilities */
  /* ---------- */
  // Calculates the normal by taking a very small distance,
  // remapping the function, and getting normal for that
  vec3 calcNormal( in vec3 pos ){
    vec3 eps = vec3( 0.001, 0.0, 0.0 );
    vec3 nor = vec3(
      map(pos+eps.xyy).dist - map(pos-eps.xyy).dist,
      map(pos+eps.yxy).dist - map(pos-eps.yxy).dist,
      map(pos+eps.yyx).dist - map(pos-eps.yyx).dist );
    return normalize(nor);
  }
  
  //--------------------------------
  // Raymarcher
  //--------------------------------
  Surface march( in Camera cam ){
    float h = 1e4; // local distance
    float d = 0.; // ray depth
    float id = -1.; // surace id
    float s = 0.; // number of steps
    float ao = 0.; // march space AO. Simple weighted accumulator
    vec3 p; // ray position
    vec3 c; // surface colour

    for( int i=0; i< NUM_OF_TRACE_STEPS ; i++ ) {
      if( abs(h) < INTERSECTION_PRECISION || d > MAX_TRACE_DISTANCE ) break;
      p = cam.ro+cam.rd*d;
      Model m = map( p );
      h = m.dist;
      d += h * STEP_MULTIPLIER;
      id = m.id;
      s += 1.;
      ao += max(h, 0.);
      c = m.colour;
    }

    if( d >= MAX_TRACE_DISTANCE ) id = -1.0;

    return Surface( d, p, c, id, s, ao );
  }
  
  //--------------------------------
  // Shading
  //--------------------------------
  /*
   * Soft shadows curtesy of Inigo Quilez
   * https://iquilezles.org/articles/rmshadows
  */
  float softshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax ) {
    float res = 1.0;
    float t = mint;
    for( int i=0; i<16; i++ ) {
      float h = map( ro + rd*t ).dist;
      res = min( res, 8.0*h/t );
      t += clamp( h, 0.02, 0.10 );
      if( h<0.001 || t>tmax ) break;
    }
    return clamp( res, 0.0, 1.0 );
  }
  float AO( in vec3 pos, in vec3 nor ) {
    float occ = 0.0;
    float sca = 1.0;
    for( int i=0; i<5; i++ )
    {
      float hr = 0.01 + 0.12*float(i)/4.0;
      vec3 aopos =  nor * hr + pos;
      float dd = map( aopos ).dist;
      occ += -(dd-hr)*sca;
      sca *= 0.95;
    }
    return clamp( 1.0 - 3.0*occ, 0.0, 1.0 );    
  }
  vec3 shade(vec3 col, vec3 pos, vec3 nor, vec3 ref, Camera cam) {
    
    vec3 plp = LP - pos; // point light
    
    float o = AO( pos, nor );                 // Ambient occlusion
    vec3  l = normalize( plp );                    // light direction
    
    float d = clamp( dot( nor, l ), 0.0, 1.0 )*DS;   // diffuse component
    float b = clamp( dot( nor, normalize(vec3(-l.x,0,-l.z))), 0.0, 1.0 )*clamp( 1.0-pos.y,0.0,1.0)*BS; // back light component
    float f = pow( clamp(1.0+dot(nor,cam.rd),0.0,1.0), 2.0 )*FS; // fresnel component
    // float spe = pow(clamp( dot( ref, l ), 0.0, 1.0 ),16.0); // specular component

    vec3 c = vec3(0.0);
    c += d*LC;                           // diffuse light integration
    c += mix(HC1,HC2,dot(nor, HLD))*AS;        // hemisphere light integration (ambient)
    c += b*BC*o;       // back light component
    c += f*FC*o;       // fresnel component
    
    return col*c;
  }
  vec3 render(Surface surface, Camera cam, vec2 uv) {
    vec3 colour = vec3(.04,.045,.05);
    colour = vec3(.35, .5, .75);
    vec3 colourB = vec3(.9, .85, .8);
    
    vec2 pp = uv;
    
    colour = mix(colourB, colour, pow(length(pp), 2.)/1.5);

    if (surface.id > -1.){
      vec3 surfaceNormal = calcNormal( surface.position );
      vec3 ref = reflect(cam.rd, surfaceNormal);
      // colour = surfaceNormal;
      vec3 pos = surface.position;
      
      vec3 col = surface.colour;
      
      colour = mix(colour, shade(col, pos, surfaceNormal, ref, cam), smoothstep(7., 2., length(cam.ro-pos)));
    }

    return colour;
  }
  
  
  void main() {
    vec2 uv = toScreenspace(gl_FragCoord.xy);
    
    Camera cam = getCamera(uv, u_cp * .01, vec3(0));
    
    Surface surface = march(cam);
    
    c = vec4(render(surface, cam, uv), 1.);
  }
</script>
              
            
!

CSS

              
                body {
  background: #333;
  color: #fff;
  font-family: sans-serif;
}
body,
html {
  margin: 0;
  overflow: hidden;
  padding: 0;
}
canvas { width:100%; height: 100%; }
              
            
!

JS

              
                console.clear();

import { FragmentShader, Texture, Uniform, DollyCamera } from 'https://cdn.skypack.dev/wtc-gl@1.0.0-beta.51';
import { Vec2, Vec3, Mat4 } from "https://cdn.skypack.dev/wtc-math@1.0.17";

const fragment = fragShader.innerText;
const vertex = `#version 300 es
in vec3 position;
in vec2 uv;
out vec2 v_uv;
void main() {
gl_Position = vec4(position, 1.0);
v_uv = uv;
}
`

const camera = new DollyCamera({},{far:1000});

const cp = new Uniform({
  name: "cp",
  value: [50,50,100],
  kind: "vec3"
})

// Create the fragment shader wrapper
const FSWrapper = new FragmentShader({
  fragment,
  vertex,
  onBeforeRender: (t) => {
    camera.update();
    
    cp.value = camera.position.multiplyNew(new Vec3(-1,1,1)).array;
  }
});
FSWrapper.playing = false;

const { gl, uniforms } = FSWrapper;

camera.setPosition(100, 100, -200.);
uniforms.u_cp = cp;

// Create the texture
const texture = new Texture(gl, {
  wrapS: gl.REPEAT,
  wrapT: gl.REPEAT
});
// Load the image into the uniform
const img = new Image();
img.crossOrigin = "anonymous";
img.src = "https://assets.codepen.io/982762/noise.png";
img.onload = () => { FSWrapper.playing = true; (texture.image = img) };

uniforms.s_noise = new Uniform({
  name: "noise",
  value: texture,
  kind: "texture"
});

              
            
!
999px

Console