Cet article explore la création d'un effet visuel dynamique de cercles concentriques rotatifs à l'aide de Three.js et de shaders GLSL personnalisés. L'objectif est de générer une animation hypnotique et interactive sans nécessiter de sources lumineuses externes, s'appuyant uniquement sur les calculs du fragment shader pour la couleur et l'intensité.
Caractéristiques Principales de l'Effet
- Animation de Cercles Radiaux : Plusieurs couches de cercles concentriques animés avec des pulsations.
- Texture de Bruit Triangulaire : Intégration d'un bruit fractal basé sur des ondes triangulaires pour enrichir les détails de la texture.
- Interaction Souris : La position de la souris influence la rotation et la déformation de l'ensemble.
- Palette de Couleurs Dynamique : Changement de couleurs progressif et hypnotique au fil du temps.
- Contexte Visuel : Un arrière-plan sombre est utilisé pour accantuer le contraste et l'effet lumineux auto-émissif.
Détail de l'Implémentation Technique
L'effet est rendu sur une simple géométrie de plan (PlaneGeometry(2, 2)) couvrant l'écran, en utilisant un ShaderMaterial personnalisé qui exécute la logique de rendu complexe directement sur le GPU.
| Composant Visuel | Méthode d'Implémentation |
|---|---|
| Géométrie de base | PlaneGeometry(2, 2) pour un plan à l'échelle de l'écran |
| Motif de cercles concentriques | Conversion en coordonnées polaires et application de fonctions trigonométriques |
| Détails de texture | Bruit fractal synthétisé à partir d'ondes triangulaires |
| Interactivité utilisateur | Passage des coordonnées de la souris en tant qu'uniformes au fragment shader |
| Rendu colorimétrique | Combinaison de fonctions cosinus pour des dégradés de couleurs évolutifs |
Fonctionnalités Clés du Shader GLSL
1. Génération de Cercles Concentriques et Déformation Radiale
Nous convertissons les coordonnées cartésiennes de la texture (uv) en coordonnées polaires pour générer des motifs radiaux. Une fonction sinusoïdale est ensuite appliquée à la distance radiale pour créer l'effet pulsé des cercles. La position de la souris est utilisée pour déformer subtilement ces coordonnées.
// Vertex Shader (vtx.glsl)
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
// Fragment Shader (frag.glsl)
precision highp float;
uniform float u_time;
uniform vec2 u_mouse; // Coordonnées de la souris, normalisées [0,1]
uniform vec2 u_resolution; // Résolution de la fenêtre d'affichage
varying vec2 vUv;
const float PI = 3.14159265359;
// Fonction pour déformer la position spatiale en fonction de l'interaction souris
vec2 deformPosition(vec2 p, vec2 mouse) {
float currentAngle = atan(p.y, p.x);
float currentDist = length(p);
float mouseInfluence = length(mouse - 0.5) * 2.0; // Force d'influence de la souris, de 0 à 1
// Ajout d'une torsion angulaire et d'une ondulation radiale
currentAngle += sin(currentDist * 8.0 + u_time * 0.5) * 0.1 * mouseInfluence;
currentDist += cos(currentAngle * 5.0 + u_time) * 0.05 * mouseInfluence;
return vec2(cos(currentAngle), sin(currentAngle)) * currentDist;
}
void main() {
vec2 p = vUv * 2.0 - 1.0; // Normalise les coordonnées de -1 à 1
p.x *= (u_resolution.x / u_resolution.y); // Correction du ratio d'aspect
vec2 deformedP = deformPosition(p, u_mouse); // Applique la déformation spatiale
float radialDistance = length(deformedP);
float angle = atan(deformedP.y, deformedP.x);
// Création du motif concentrique pulsé avec des modulations temporelles et angulaires
float circlePattern = 0.5 + 0.5 * sin(radialDistance * 18.0 + u_time * 1.5 + angle * 0.2);
circlePattern = pow(abs(circlePattern), 3.0); // Renforce le contraste des cercles
// ... suite du shader pour le bruit et la couleur
2. Bruit Fractal Basé sur des Ondes Triangulaires
Pour ajouter de la complexité et une texture organique, nous utilisons une fonction de bruit fractal. Cette fonction superpose plusiuers octaves d'une onde triangulaire pour créer des détails fins et des irrégularités.
// Fragment Shader (suite)
// ... (code précédent)
// Fonction d'onde triangulaire de base
float triangleWave(float x) {
return abs(mod(x, 1.0) - 0.5);
}
// Génération de bruit fractal par superposition d'ondes triangulaires
float fractalTriangleNoise(vec2 coord) {
float totalValue = 0.0;
float currentFrequency = 1.0;
float currentAmplitude = 0.5;
for (int i = 0; i < 4; i++) { // Itération sur 4 octaves
totalValue += triangleWave(coord.x * currentFrequency + triangleWave(coord.y * currentFrequency)) * currentAmplitude;
currentFrequency *= 2.0; // Double la fréquence pour l'octave suivante
currentAmplitude *= 0.5; // Réduit l'amplitude
coord += vec2(0.1, 0.2); // Décalage pour varier le bruit entre les octaves
}
return totalValue;
}
void main() {
// ... (code précédent)
float noiseComponent = fractalTriangleNoise(deformedP * 5.0 + u_time * 0.1); // Applique le bruit à la position déformée
// Combinaison du motif circulaire et du bruit pour l'intensité finale
float finalIntensity = circlePattern * (0.6 + noiseComponent * 0.4); // Le bruit module l'intensité des cercles
// ... suite du shader pour la couleur
3. Palette de Couleurs Dynamique
La couleur est générée dynamiquement en utilisant des fonctions cosinus. Cela permet de créer des dégradés de couleurs fluides qui évoluent avec le temps et l'intensité, offrant une esthétique vibrante et changeante.
// Fragment Shader (fin)
// ... (code précédent)
// Palette de couleurs générée dynamiquement
vec3 dynamicColorPalette = vec3(0.5, 0.5, 0.5) + 0.5 * cos(u_time * 0.7 + finalIntensity * 4.0 + vec3(0.0, 2.0, 4.0));
// Application de la couleur finale en fonction de l'intensité
vec3 finalColor = dynamicColorPalette * finalIntensity;
gl_FragColor = vec4(finalColor, 1.0);
}
Optimisation et Dépannage
| Problème Courant | Manifestation | Solution Proposée |
|---|---|---|
| Motif radial trop simple | Cercles espacés ou peu nombreux, manque de détail | Ajuster les multiplicateurs dans radialDistance * 18.0 ou la puissance dans pow(..., 3.0). |
| Performance | Chute du framerate, animation saccadée sur des GPU moins puissants | Réduire le nombre d'octaves dans fractalTriangleNoise ou simplifier les calculs de déformation de position. |
| Transition de couleur abrupte | Blocs de couleur visibles, transitions non fluides | Modifier les offsets ou les multiplicateurs dans la fonction cos de la palette de coulerus. |
| Interactivité de la souris absente | L'effet ne réagit pas aux mouvements du curseur | Vérifier que l'uniform u_mouse est correctement mis à jour et passé au shader dans la boucle de rendu Three.js. |
Pistes d'Amélioration et Extensions
| Idée d'Extension | Modification Clé | Complexité Estimée |
|---|---|---|
| Projection sur une sphère 3D | Adapter le motif 2D pour le mapper sur la surface d'un objet sphérique ou d'autres formes 3D complexes. | ⭐⭐⭐ |
| Contrôles GUI interactifs | Intégrer une interface utilisateur graphique (par ex. dat.GUI) pour modifier en temps réel les paramètres de couleur, densité et vitesse d'animation. | ⭐⭐ |
| Réponse audio | Utiliser l'API Web Audio pour analyser le spectre sonore et moduler des aspects de l'animation ou de la palette de couleurs en conséquence. | ⭐⭐⭐⭐ |
| Complexité fractale accrue | Augmenter le nombre d'itérations du bruit fractal ou introduire des fractales de Mandelbrot/Julia dans le motif. | ⭐⭐⭐ |