Continuously unveil a circle in a repetitive sequence

I'm currently working on a project that involves a scanline effect, and I have a Codepen snippet displaying my progress (Codepen link). However, I want to take it a step further by gradually changing the color after the scanline has passed, similar to this example: Example Image.

Despite my efforts to search for solutions in three.js and WebGL, I haven't been able to find exactly what I'm looking for. I'm struggling because I'm not sure what keywords to use in my searches.

Could someone provide me with a solution or guide me in the right direction? Here are some ideas I've considered:

  • Implementing a dynamic mask to reveal a second green circle after the scanline passes. How can I create such a mask in three.js that shows a slice with an increasing angle θ?
  • The CircleGeometry feature in three.js allows me to create a slice with a specified angle θ. However, constantly changing the geometry of my mesh may not be the most efficient approach.
  • Adding tiny circle slices after the scanline passes to give the illusion of revealing a circle, although it's actually just adding small slices.

Just to clarify, I've chosen to use three.js because I plan on incorporating 3D elements into this project later on.

// JavaScript code for the project goes here
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

Answer №1

Here is a comprehensive example demonstrating progressive arcs using both fragment and vertex shader implementations. This code snippet serves as a solid foundation for your own projects.

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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps for generating an observable that mirrors the structure of an observable array

I am in the process of creating an observable array using JSON data retrieved from the server. var ViewModel = function (data) { var self = this; self.list = ko.observableArray(data); self.selected = ko.observable(); } ...

Having issues with clicking on a row in the table while using AJAX functionality

Experiencing a puzzling issue while attempting to add click functionality to table rows with AJAX, here is the JavaScript code used: //for tabs $(document).ready(function () { $("#tabs").tabs(); }); $(window).load(function() { jsf.ajax.addOnEven ...

The "Splash Screen Div" page displayed during transitions and page loading

Creating a "Splash Screen Div" for a loading page involves waiting until everything is loaded and then hiding or moving the div off screen. Below is an example: index.html <div id="loading-Div"> <div id="bear-Logo"> < ...

Selecting JavaScript Libraries During the Development of a Web Application

Transitioning from PHP & Java/Android development to web app development can feel overwhelming, especially with the abundance of Javascript Frameworks available. Check out this comparison of popular JavaScript frameworks View a list of the top JavaSc ...

What is the best way to transfer information between two components in React.js by simply clicking a button?

One of the challenges I am currently facing involves rendering data from the Pokemon API in a table. Within this table, there is a button that allows users to select specific data when pressed. My goal is to send this selected data from the table component ...

What is the process for creating a progress bar in PixiJS?

Can someone guide me on creating a progress bar similar to the one in PixiJS? Screenshot ...

Every time I employ window.location, the Iframe becomes nested

I am experiencing an issue with my HTML structure: <html> <body> This is the container of the iframe <iframe src="/foo.html"> </iframe> </body> </html> (/foo.html) <html> <script type="text/javascript"> $( ...

Understanding Scope in AJAX Development

Is there a method to display the desired length outside of the downloadURL() function in the following code snippet? If so, how can this be achieved? var markers = new Array(); var mlength = 0; downloadUrl("phpsqlajax_genxml.php", function(data) { v ...

Exploring Objects without the need for loops

Currently, I am focusing on optimizing the performance of the following objects: var scheduleFee = { poor = {level1:25,level2:25,level3:25} , good = {level1:15,level2:20,level3:25} , vgood = {level1:10,le ...

Experiencing difficulty in adding a sub-document to an array within a parent

I am currently working with a users model that incorporates a locationsSchema: const locationSchema = require('./location.js'); const userSchema = new mongoose.Schema({ email: { type: String, unique: true, required: true, }, t ...

Troubles encountered when cascading val(), text(), and data()

Here is my JavaScript/jQuery code: $select.append($("<option />") .val(this.id) .text(this.text) .data('name', this.name) .data('isstorage', this.isstorage)); Although it successfully assigns values to t ...

What causes non-reactive variables to act unusual in Vue3?

Check out this code snippet: <template> <input type="button" value="click" @click="clickBtn"/> <div id="reactiveDiv">{{ reactiveVariable }}</div> <div id="noneReactiveDiv"&g ...

What are some techniques for managing scrolling within a particular element?

I am currently working with Vue.js and utilizing Element UI components. I want to incorporate a scroll management function to achieve infinite scrolling. To better understand, please refer to the screenshot in the Example section: Despite trying differen ...

Running into an issue while attempting to generate functions in nodejs

I'm currently working on a function to authenticate a URL for a fetch request. However, when I attempt to call this function within the app.post callback, my Node.js server throws an error: "TypeError: authenticateUrl(...) is not a function". Does Nod ...

Achieving the optimal camera position directly above a .glb model in react-three-fiber: A step-by-step guide

Hey there! I've got a codesandbox demo ready for you, where I'm trying to troubleshoot something. So, I created a basic 3D model in blender and exported it. My aim is to bring this model into my React app using react-three-fiber, and have the ca ...

JavaScript problem encountered when using the forEach() function on $el

I am encountering an issue where I am unable to access the element value inside the forEach() function var filtered = rawData.map(function(x){ return { state : x.state, active : x.active, deaths : x.de ...

What is the correct way to reuse sub-dependencies using NPM?

This inquiry primarily centers around the usage of react-admin, as indicated by the tags, but could also be applicable in other scenarios. In our case, we are utilizing react-admin which relies on @material-ui/core. This grants us the ability to incorpora ...

In JavaScript, implement event listeners exclusively on the main container and its immediate child elements

Is there a way to target just the main container and its second child elements for an event? Specifically, targeting id="container" and all elements with class="secondChild" Currently, I have a listener attached to all elements inside ...

Trigger the select dropdown when a key is clicked

I am currently working on a project in react where I am utilizing the Select component from material. When I open the dropdown and press a key on my keyboard, the option starting with that key gets automatically selected. This behavior is also observed in ...

Enable content to be displayed when hovering over it with a mouse in

As a newcomer to JavaScript, I am eager to learn how to add an interactive feature to my menu item. I want to create an info box that pops up when the menu item is clicked, and can also be displayed when hovering over it. Below is the script I have so far, ...