Voronoi Prism

In this example below you will see how to do a Voronoi Prism with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by vaalentin, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright vaalentin ©
  • HTML
  • CSS
  • JavaScript
    <div class="viewport"></div>

/*Downloaded from https://www.codeseek.co/vaalentin/voronoi-prism-PZrjbJ */
    * {
	margin: 0;
	padding: 0;
}

body {
	background-color: #030413;
}

.viewport {
	position: absolute;
	width: 100%;
	height: 100%;
	overflow: hidden;
}



/*Downloaded from https://www.codeseek.co/vaalentin/voronoi-prism-PZrjbJ */
    let container;
let scene;
let camera;
let renderer;
let material;

function onResize() {
  const { offsetWidth: width, offsetHeight: height } = container;

  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
}

function setup() {
  container = document.querySelector('.viewport');
  scene = new THREE.Scene();

  const { offsetWidth: width, offsetHeight: height } = container;

  camera = new THREE.PerspectiveCamera(45, width / height, 1, 100);
  camera.position.z = 5;

  renderer = new THREE.WebGLRenderer({
    alpha: true,
    antialias: true
  });

  renderer.setSize(width, height);
  renderer.setClearColor(0x000000, 0);

  container.appendChild(renderer.domElement);

  window.addEventListener('resize', onResize);

  const geometry = new THREE.PlaneGeometry(3, 3, 1, 1);
  const texture = new THREE.ImageUtils.loadTexture('../../assets/img/vtest.png');
  // texture.minFilter = THREE.NearestFilter;
  texture.minFilter = THREE.LinearFilter;
  material = new THREE.ShaderMaterial({
    side: THREE.DoubleSide,
    transparent: true,
    uniforms: {
      resolution: { type: '2f', value: [width, height] },
      time: { type: '1f', value: 0.0 },
      texture: { type: 't', value: texture },
      threshold: { type: '1f', value: 0.02 },
      attenuation: { type: '1f', value: 1.11 },
      borderThreshold: { type: '1f', value: 0.0 },
      borderOffset: { type: '1f', value: -0.01 },
      voronoiPrecision: { type: '1f', value: 1.7 },

      gradientSteps: { type: '3fv', value: [
        -1.0, -0.6, -0.15,
        -0.2, -0.075, -0.05,
        -0.1, -0.05, 0.0
      ]},

      gradientColors: { type: '4fv', value: [
        0.0, 0.0, 1.0, 1.0,
        1.0, 1.0, 1.0, 1.0,
        1.0, 0.0, 0.0, 1.0
      ]},

      mouse: { type: '3f', value: [
        0.0, 0.0, 0.0
      ]}
    },
    vertexShader: `
      varying vec2 vUv;
      varying vec3 vPosition;

      void main(void) {
        vUv = uv;
        vPosition = position;

        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
    fragmentShader: `
      float luminance(in vec3 rgb) {
        const vec3 W = vec3(0.2125, 0.7154, 0.0721);
        return dot(rgb, W);
      }

      float map(in float value, in float inMin, in float inMax, in float outMin, in float outMax) {
        return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
      }

      vec2 hash2( vec2 p )
      {	
        // procedural white noise	
        return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453);
      }

      vec3 voronoi(in vec2 x, in float time)
      {
        vec2 n = floor(x);
        vec2 f = fract(x);

        //----------------------------------
        // first pass: regular voronoi
        //----------------------------------
        vec2 mg, mr;
        float md = 8.0;
        for(int j = -1; j <= 1; j++)
        for(int i = -1; i <= 1; i++)
        {
          vec2 g = vec2(float(i),float(j));
          vec2 o = hash2(n + g);
          o = 0.5 + 0.5 * sin(time + 6.2831 * o);
          vec2 r = g + o - f;
          float d = dot(r, r);

          if(d < md)
          {
            md = d;
            mr = r;
            mg = g;
          }
        }

        //----------------------------------
        // second pass: distance to borders
        //----------------------------------
        md = 8.0;
        for(int j = -2; j <= 2; j++)
        for(int i = -2; i <= 2; i++)
        {
          vec2 g = mg + vec2(float(i),float(j));
          vec2 o = hash2(n + g);

          o = 0.5 + 0.5 * sin(time + 6.2831 * o);
          vec2 r = g + o - f;

          if(dot(mr - r, mr - r) > 0.00001)
            md = min(md, dot(0.5 * (mr + r), normalize(r - mr)));
          }

          return vec3(md, mr);
      }

      uniform vec2 resolution;
      uniform float time;
      uniform sampler2D texture;

      uniform float threshold;
      uniform float attenuation;
      uniform float borderThreshold;
      uniform float borderOffset;
      uniform float voronoiPrecision;

      uniform vec3 gradientSteps[2];
      uniform vec4 gradientColors[2];

      uniform vec3 mouse;

      varying vec2 vUv;
      varying vec3 vPosition;

      void main(void)
      {
        // texture
        // vec4 color = texture2D(texture, vUv);

        // voronoi
        vec3 vor = voronoi(vPosition.xy * voronoiPrecision, time);
        vec3 vorCol = vor.x * 1.5 * vec3(1.0); // fill
        vorCol = mix(vec3(0.0, 0.0, 0.0), vorCol, smoothstep(0.001, 0.004, vor.x)); // borders	

        float dist = distance(vPosition, mouse);
        float len = length(dist);
        float light = 1.0 - (len * attenuation);


        vec3 adjustedColor = vec3(vorCol.xyz * light);

        float lum = luminance(adjustedColor.rgb);
        float distanceToBorder = threshold - lum;

        vec4 outColor = vec4(1.0, 1.0, 1.0, 0.0);

        // if (lum < threshold)
        // {
        // 	discard;
        // }

        // for (int i = 0; i < 3; i++)
        // {
        // 	float from = gradientSteps[i][0];
        // 	float middle = gradientSteps[i][1];
        // 	float to = gradientSteps[i][2];

        // 	vec4 col = gradientColors[i];

        // 	if (distanceToBorder >= from && distanceToBorder <= to)
        // 	{
        // 		float alpha = smoothstep(from, middle, distanceToBorder) * (1.0 - smoothstep(middle, to, distanceToBorder));
        // 		outColor = mix(outColor, col, alpha);
        // 	}		
        // }

        // gl_FragColor = outColor;


        // gradients
        if (lum < threshold)
        {
          discard;
        }

        if (distanceToBorder >= -0.4 && distanceToBorder <= -0.1)
        {
          float alpha = smoothstep(-0.4, -0.2, distanceToBorder) * (1.0 - smoothstep(-0.2, -0.1, distanceToBorder));
          outColor = mix(outColor, vec4(0.5, 0.0, 1.0, 1.0), alpha);
        }

        if (distanceToBorder >= -0.2 && distanceToBorder <= -0.05)
        {
          float alpha = smoothstep(-0.2, -0.075, distanceToBorder) * (1.0 - smoothstep(-0.075, -0.05, distanceToBorder));
          outColor = mix(outColor, vec4(vUv.x, vUv.y, 1.0, 1.0), alpha);
        }

        if (distanceToBorder >= -0.1 && distanceToBorder <= 0.0)
        {
          float alpha = smoothstep(-0.1, -0.05, distanceToBorder) * (1.0 - smoothstep(-0.05, 0.0, distanceToBorder));
          outColor = mix(outColor, vec4(0.4, 0.0, 0.4, 1.0), alpha);
        }

        gl_FragColor = outColor;
      }
    `
  });
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  const gui = new dat.GUI();
  gui.close();

  gui.add(material.uniforms.threshold, 'value', -1.0, 1.0).step(0.0001).name('threshold');
  gui.add(material.uniforms.attenuation, 'value', -1.0, 4.0).step(0.0001).name('attenuation');
  gui.add(material.uniforms.borderThreshold, 'value', -0.2, 0.2).step(0.0001).name('borderThreshold');
  gui.add(material.uniforms.borderOffset, 'value', -0.2, 0.2).step(0.0001).name('borderOffset');
  gui.add(material.uniforms.voronoiPrecision, 'value', 1.0, 10.0).step(0.0001).name('voronoiPrecision');

  
  gui.add
  TweenMax.fromTo(material.uniforms.attenuation, 5, { value: 0.6 }, { value: 2.41, repeat: -1, yoyo: true, ease: Expo.easeInOut });

  draw();
}

function draw()
{
  renderer.render(scene, camera);
  requestAnimationFrame(draw);

  material.uniforms.time.value += 0.01;
}

setup();


Comments