在循环中逐渐显示圆圈

Progressively reveal circle in loop

我目前有这个:Codepen(下面的嵌入代码段)。

我希望能够在扫描线之后逐渐改变颜色,就像这样:

在网上搜索并试图在 three.js / WebGL 中找到一些东西后,我未能获得我想要的东西,可能是因为我不太清楚我应该搜索什么。

你能帮我解决问题或者给我指明正确的方向吗? 我考虑了以下可能性:

P.S。 - 我正在使用 three.js 因为稍后这个项目会有 3d 元素。

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();

renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const innerRadius = 1;
const outerRadius = innerRadius*2;
const barLenght = innerRadius;

// create scanline
const outerMaterial = new THREE.MeshBasicMaterial({color: 0x34ebd2});
const outerCircle = new THREE.Mesh(new THREE.CircleGeometry(outerRadius, 60), outerMaterial);
scene.add(outerCircle);

// Create innerCircle 
const innerMaterial = new THREE.MeshBasicMaterial({color: 0x0000ff});
const innerCircle = new THREE.Mesh(new THREE.CircleGeometry(innerRadius, 60), innerMaterial);
scene.add(innerCircle);


// create static line
const staticLine = new THREE.Mesh(new THREE.PlaneGeometry(0.05, barLenght), new THREE.MeshBasicMaterial({color: 0xff0000, side: THREE.DoubleSide}));
scene.add(staticLine);

// create scan line
const scanLine = new THREE.Mesh(new THREE.PlaneGeometry(0.05, barLenght), new THREE.MeshBasicMaterial({color: 0xff0000, side: THREE.DoubleSide}));
scene.add(scanLine);

// position static line
staticLine.position.y = innerRadius + barLenght/2;

// position scan line
scanLine.position.y = innerRadius + barLenght/2;

// create pivot to rotate dateline
const pivot = new THREE.Group();
pivot.position.set( 0.0, 0.0, 0 );
pivot.add(scanLine);
scene.add(pivot);

camera.position.z = 5;

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
  
  pivot.rotation.z -= 0.005;
}
animate();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

这是渐进弧的二合一示例(片段和顶点着色器实现),只是从头开始。以此为起点。

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three@0.132.2";
import {OrbitControls} from "https://cdn.skypack.dev/three@0.132.2/examples/jsm/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>