body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/example";
import {OrbitControls} from "https://cdn.skypack.dev/controls/OrbitControls.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(-5, 3, 8);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
// fragment shader option
let g = new THREE.CircleGeometry(5, 64);
let m = new THREE.MeshBasicMaterial({
color: 0x7f7f7f,
side: THREE.DoubleSide,
onBeforeCompile: shader => {
shader.uniforms.time = m.userData.uniforms.time;
shader.uniforms.currColor = m.userData.uniforms.currColor;
shader.uniforms.prevColor = m.userData.uniforms.prevColor;
shader.fragmentShader = `
uniform float time;
uniform vec3 currColor;
uniform vec3 prevColor;
${shader.fragmentShader}
`.replace(
`#include <color_fragment>`,
`#include <color_fragment>
vec2 cUv = vUv - 0.5;
float dist = length(cUv);
vec3 col = prevColor;
float ang = mod(atan(cUv.y, cUv.x) + PI * 3.5, PI2);
float aRatio = 1. - ang / PI2;
float slice = 1. - step(time, aRatio);
col = mix(prevColor, currColor, slice);
float innerCirc = 1. - step(0.25, dist);
col = mix(col, diffuseColor.rgb, innerCirc);
diffuseColor.rgb = col;
`
);
console.log(shader.fragmentShader);
}
})
m.defines = {
"USE_UV": " "
};
m.userData = {
uniforms: {
time: {
value: 0.5
},
currColor: {
value: new THREE.Color(0xff00ff)
},
prevColor: {
value: new THREE.Color(0x00ffff)
}
}
}
let o = new THREE.Mesh(g, m);
scene.add(o);
// vertex shader option
let g2 = new THREE.PlaneGeometry(1, 1, 180, 1);
let m2 = new THREE.MeshBasicMaterial({
color: 0xffff00,
wireframe: true,
onBeforeCompile: shader => {
shader.uniforms.rMin = m2.userData.uniforms.rMin;
shader.uniforms.rMax = m2.userData.uniforms.rMax;
shader.uniforms.arcRatio = m2.userData.uniforms.arcRatio;
shader.vertexShader = `
uniform float rMin;
uniform float rMax;
uniform float arcRatio;
mat2 rot(float a){return mat2(cos(a), -sin(a), sin(a), cos(a));}
${shader.vertexShader}
`.replace(
`#include <begin_vertex>`,
`#include <begin_vertex>
float rDiff = rMax - rMin;
float r = rMin + (rDiff * uv.y);
float ang = PI2 * uv.x * arcRatio;
transformed.xy = rot(ang) * vec2(0., r);
`
);
console.log(shader.vertexShader);
}
});
m2.userData = {
uniforms: {
rMin: {value: 2.5},
rMax: {value: 5},
arcRatio: {value: 0.25} // 0..1
}
}
let o2 = new THREE.Mesh(g2, m2);
o2.position.z = 2;
scene.add(o2);
let clock = new THREE.Clock();
window.addEventListener("resize", onResize);
renderer.setAnimationLoop(_ => {
let t = (clock.getElapsedTime() * 0.1) % 1;
m.userData.uniforms.time.value = t;
m2.userData.uniforms.arcRatio.value = t;
renderer.render(scene, camera);
})
function onResize(){
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
}
</script>