<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

<script type="importmap">
  {
    "imports": {
      "three": "https://cdn.skypack.dev/three@0.139.2",
      "three/": "https://cdn.skypack.dev/three@0.139.2/"
    }
  }
</script>

<script>
  // https://github.com/yiwenl/glsl-fbm/blob/master/3d.glsl
  let noise = `
    #define NUM_OCTAVES 5

float mod289(float x){return x - floor(x * (1.0 / 289.0)) * 289.0;}
vec4 mod289(vec4 x){return x - floor(x * (1.0 / 289.0)) * 289.0;}
vec4 perm(vec4 x){return mod289(((x * 34.0) + 1.0) * x);}

float noise(vec3 p){
    vec3 a = floor(p);
    vec3 d = p - a;
    d = d * d * (3.0 - 2.0 * d);

    vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);
    vec4 k1 = perm(b.xyxy);
    vec4 k2 = perm(k1.xyxy + b.zzww);

    vec4 c = k2 + a.zzzz;
    vec4 k3 = perm(c);
    vec4 k4 = perm(c + 1.0);

    vec4 o1 = fract(k3 * (1.0 / 41.0));
    vec4 o2 = fract(k4 * (1.0 / 41.0));

    vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);
    vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);

    return o4.y * d.y + o4.x * (1.0 - d.y);
}


float fbm(vec3 x) {
	float v = 0.0;
	float a = 0.5;
	vec3 shift = vec3(100);
	for (int i = 0; i < NUM_OCTAVES; ++i) {
		v += a * noise(x);
		x = x * 2.0 + shift;
		a *= 0.5;
	}
	return v;
}
  `;
</script>
body{
  overflow: hidden;
  margin: 0;
}
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";


let loader = new THREE.TextureLoader();

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(
  60,
  innerWidth / innerHeight,
  0.1,
  5000
);
camera.position.set(0, 10, 10).setLength(10);
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});

let controls = new OrbitControls(camera, renderer.domElement);
controls.enablePan = false;
controls.enableDamping = true;

let light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(10, 0, 0);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));

let orb = makeOrb(5);
scene.add(orb);
let icoLam = new THREE.Mesh(new THREE.IcosahedronGeometry(0.5, 2), new THREE.MeshLambertMaterial({color: "teal"}));
icoLam.position.set(-2, 2, -2);
scene.add(icoLam);

let clock = new THREE.Clock();

renderer.setAnimationLoop((_) => {
  let t = clock.getElapsedTime();
  light.position.x = Math.cos(t) * 10;
  light.position.z = -Math.sin(t) * 10;
  controls.update();
  renderer.render(scene, camera);
});

function makeOrb() {
  let g = new THREE.SphereGeometry(1, 72, 36);
  let m = new THREE.MeshStandardMaterial({
    map: loader.load("https://threejs.org/examples/textures/uv_grid_opengl.jpg"),
    onBeforeCompile: shader => {
      shader.uniforms.darkSideTex = {value: loader.load("https://threejs.org/examples/textures/758px-Canestra_di_frutta_(Caravaggio).jpg")};
      shader.fragmentShader = `
        #define ss(a, b, c) smoothstep(a, b, c)
        uniform sampler2D darkSideTex;
        ${shader.fragmentShader}
      `.replace(
        `#include <dithering_fragment>`,
        `#include <dithering_fragment>
          float d = max(dot(geometry.normal, directionalLights[0].direction), 0.);
          vec4 dst = texture(darkSideTex, vUv);
          gl_FragColor = mix(dst, gl_FragColor, ss(0., 0.15, d));
        `
      );
    }
  })
  let s = new THREE.Mesh(g, m);
  s.scale.setScalar(2);
  return s;
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.