Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Three.js Shader Example</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r82/three.min.js"></script>
</head>
<body>
  <canvas class="webgl"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vertexUV;
void main() {
    vertexUV = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision highp float;
uniform vec3 iResolution;
uniform float iTime;
uniform sampler2D iChannel0;
#define M_NONE -1.0
#define M_NOISE 1.0
float hash(float h) {
    return fract(sin(h) * 43758.5453123);
}
float noise(vec3 x) {
    vec3 p = floor(x);
    vec3 f = fract(x);
    f = f * f * (3.0 - 2.0 * f);
    float n = p.x + p.y * 157.0 + 113.0 * p.z;
    return mix(
            mix(mix(hash(n + 0.0), hash(n + 1.0), f.x),
                    mix(hash(n + 157.0), hash(n + 158.0), f.x), f.y),
            mix(mix(hash(n + 113.0), hash(n + 114.0), f.x),
                    mix(hash(n + 270.0), hash(n + 271.0), f.x), f.y), f.z);
}
#define OCTAVES 4
float fbm(vec3 x) {
    float v = 0.0;
    float a = 0.5;
    vec3 shift = vec3(100);
    for (int i = 0; i < OCTAVES; ++i) {
        v += a * noise(x);
        x = x * 2.0 + shift;
        a *= 0.5;
    }
    return v;
}
const int MAX_MARCHING_STEPS = 200;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float EPSILON = 0.002;
float sdBox(vec3 p, vec3 b) {
    vec3 q = abs(p) - b;
    return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - 2.0;
}
float opSmI(float d1, float d2, float k) {
    float h = clamp(0.5 - 0.5 * (d2 - d1) / k, 0.0, 1.0);
    return mix(d2, d1, h) + k * h * (1.0 - h);
}
mat3 rotateY(float t) {
    float c = cos(t);
    float s = sin(t);
    return mat3(vec3(c, 0, s),
                vec3(0, 1, 0),
                vec3(-s, 0, c));
}
mat3 rotateX(float t) {
    float c = cos(t);
    float s = sin(t);
    return mat3(vec3(1, 0, 0),
                vec3(0, c, -s),
                vec3(0, s, c));
}
mat3 rotateZ(float t) {
    float c = cos(t);
    float s = sin(t);
    return mat3(vec3(c, -s, 0),
                vec3(s, c, 0),
                vec3(0, 0, 1));
}
float sdCapsule(vec3 p, vec3 a, vec3 b, float r) {
    vec3 pa = p - a;
    vec3 ba = b - a;
    float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
    return length(pa - ba * h) - r;
}
float sceneSDF(vec3 sP) {
    float f = sdCapsule(sP, vec3(-1.7, 0., 0.), vec3(1.7, 0., 0.), 0.3);
    float d = 0.02 * sin(sP.x * 5.0) * sin((sin(sP.x * 2.0 + iTime) + 1.0) * sP.x * 20.0) + noise(vec3(sP.z * 2.5 - iTime * 1.0)) - 1.2;
    return f + 0.5 * d;
}
vec2 shortestDistanceToSurface(vec3 eye, vec3 marchingDirection, float start, float end) {
    float depth = start;
    for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
        float dist = sceneSDF(eye + depth * marchingDirection);
        if (dist < EPSILON) {
            return vec2(depth, float(i + 1));
        }
        depth += dist;
        if (depth >= end) {
            return vec2(end, 0.0);
        }
    }
    return vec2(end, 0.0);
}
vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {
    vec2 xy = fragCoord - size / 2.0;
    float z = size.y / tan(radians(fieldOfView) / 2.0);
    return normalize(vec3(xy, -z));
}
vec3 estimateNormal(vec3 p) {
    return normalize(vec3(
        sceneSDF(vec3(p.x + EPSILON, p.y, p.z)) - sceneSDF(vec3(p.x - EPSILON, p.y, p.z)),
        sceneSDF(vec3(p.x, p.y + EPSILON, p.z)) - sceneSDF(vec3(p.x, p.y - EPSILON, p.z)),
        sceneSDF(vec3(p.x, p.y, p.z + EPSILON)) - sceneSDF(vec3(p.x, p.y, p.z - EPSILON))
    ));
}
vec3 phongContribForLight(vec3 k_d, vec3 k_s, float alpha, vec3 p, vec3 eye,
                          vec3 lightPos, vec3 lightIntensity) {
    vec3 N = estimateNormal(p);
    vec3 L = normalize(lightPos - p);
    vec3 V = normalize(eye - p);
    vec3 R = normalize(reflect(-L, N));
    
    vec3 ref = reflect(p - eye, N);
    
    float dotLN = dot(L, N);
    float dotRV = dot(R, V);
    
    if (dotLN < 0.0) {
        return vec3(0.0, 0.0, 0.0);
    }
    
    if (dotRV < 0.0) {
        return lightIntensity * (k_d * dotLN);
    }
    return (lightIntensity * (k_d * dotLN + k_s * pow(dotRV, alpha)) * 0.5 + 0.5 * texture(iChannel0, ref.xy).xyz);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec3 dir = rayDirection(45.0, iResolution.xy, fragCoord);
    vec3 eye = vec3(0.0, 0.0, 5.0);
    vec2 sdf = shortestDistanceToSurface(eye, dir, MIN_DIST, MAX_DIST);
    float dist = sdf.x;
    
    if (dist > MAX_DIST - EPSILON) {
        fragColor = vec4(0.0, 0.0, 0.0, 0.0);
        return;
    }
    
    vec3 p = eye + dist * dir;
    vec3 N = estimateNormal(p);
    
    float l1 = length(cross(vec3(0., 0.0, 1.), N));
    l1 = smoothstep(0.65, 0.6, l1) - smoothstep(l1, 0.65, 0.6);
    float l2 = length(cross(vec3(0., 0.01, 1.05), N));
    l2 = smoothstep(0.65, 0.6, l2) - smoothstep(l2, 0.65, 0.6);
    float l3 = length(cross(vec3(0.02, 0.0, 1.1), N));
    l3 = smoothstep(0.65, 0.59, l3) - smoothstep(l3, 0.65, 0.59);
    vec3 color = vec3(l1, l2, l3);
    
    fragColor = vec4(color, 1.0);
}
</script>
<script>
  // Canvas
  const canvas = document.querySelector('canvas.webgl')
  // Scene
  const scene = new THREE.Scene();
  // Objects
  const geometry = new THREE.SphereGeometry(5, 50, 50);
  // Materials
  const loader = new THREE.TextureLoader();
  const material = new THREE.ShaderMaterial({
    vertexShader: document.getElementById('vertexShader').textContent,
    fragmentShader: document.getElementById('fragmentShader').textContent,
    uniforms: {
      iResolution: { value: new THREE.Vector3(window.innerWidth, window.innerHeight, 1) },
      iTime: { value: 0 },
      iChannel0: { value: loader.load('https://i.ibb.co/CsjHTSQ/test.png') }
    }
  });
  // Mesh
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
  // Camera
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.z = 5;
  // Renderer
  const renderer = new THREE.WebGLRenderer({ canvas });
  renderer.setSize(window.innerWidth, window.innerHeight);
  // Animation loop
  function animate() {
    requestAnimationFrame(animate);
    // Update uniforms
    material.uniforms.iTime.value += 0.05;
    renderer.render(scene, camera);
  }
  animate();
</script>
</body>
</html>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers