L’attirance pour les attracteurs étranges

Accueil / Fractales / L’attirance pour les attracteurs étranges

Nous avons déjà abordés ici la magie quasi surnaturelle des attracteurs étranges et les moyens d’en modéliser avec Blender et JWildfire… Mais aujourd’hui il est devenu tellement facile de coder avec l’aide de l’IA qu’un grand nombre de nouvelles variations de ce genre ont fait leur apparition, notament pour Jwildfire. Naturellement j’ai été attiré (!) par l’une d’entre elles, baptisée « Attractor Flow » proposée au téléchargement sur le Github de Brad Stefanov.

Dans JWildfire

Petite déception : A l’usage, on constate qu’assez peu d’attracteurs sont implémentés. Tout au plus les Clifford Classic, Peter De Jong, Gumowski-Mira et Svensson… Bon, rien n’empêche de modifier le code et d’y ajouter les formules d’autres attracteurs. Quand on aime se salir les mains…

Pour l’utiliser il faut place dans le flux de travail la variation « Custom_wf_full » et la renseigner avec le code en cliquant sur sa roue dentée.

Précisons tout de suite que cette variation ne fonctionne pas seule : il faut impérativement qu’elle suive une première variation, typiquement « Blur » ou, pour une plus grande pureté « Linear 3D ». On a accès dans les réglages de la variation à quelques « presets » mais aussi aux quatre types d’attracteurs et aux quatre types d’onde (Sine, Square, Triangle, Sawtooth)… De quoi générer une grande variété d’attracteurs. Egalement une quyrielle de réglettes pour faire varier (sur les axes X,Y,Z) la taille, la phase, la fréquence et l’amplitude.

Voici quatre exemples avec les  attracteurs proposés. Le Gumoski-Mira rappelle un peu le fameux effet « Plastic ».

Attracteur Gumoski-Mira.

Rien n’empêche de changer la première variation ou d’en ajouter d’autres après l’attracteur pour obtenir une grande variété de formes et d’ambiances…

Dans Swan

On peut aussi travailler en temps réel avec la carte graphique et JWilfire Swan. Il faut installer la dernière version de Swan qui prend en charge les « custom variations » et y installer ce bout de code également proposé par Brad Stefanov :

[PARAM_DEFS]

name = attractorMode, value = 0, type = int, min = 0, max = 3

name = waveMode, value = 0, type = int, min = 0, max = 3

name = yScale, value = -1.7, type = float, min = -3.0, max = 3.0

name = xScale, value = 1.8, type = float, min = -3.0, max = 3.0

name = xAmplitude, value = -0.5, type = float, min = -3.0, max = 3.0

name = yAmplitude, value = -1.9, type = float, min = -3.0, max = 3.0

name = freqX, value = 1.0, type = float, min = -5.0, max = 5.0

name = freqY, value = 1.0, type = float, min = -5.0, max = 5.0

name = phaseX, value = 0.0, type = float, min = -3.14, max = 3.14

name = phaseY, value = 0.0, type = float, min = -3.14, max = 3.14

[VARIATION_CODE]

float newX, newY;

float PI = 3.14159265;

float TWO_PI = 6.2831853;

float PI_2 = 1.5707963;

// --- Attractor and Wave Logic ---

if (attractorMode == 1) { // Peter de Jong

  if (waveMode == 1) { // Square

    newX = sign(sin(yScale * _ty)) - sign(sin(xScale * _tx + PI_2));

    newY = sign(sin(xAmplitude * _tx)) - sign(sin(yAmplitude * _ty + PI_2));

  } else if (waveMode == 2) { // Triangle

    newX = (asin(sin(yScale * _ty)) * (2.0/PI)) - (asin(sin(xScale * _tx + PI_2)) * (2.0/PI));

    newY = (asin(sin(xAmplitude * _tx)) * (2.0/PI)) - (asin(sin(yAmplitude * _ty + PI_2)) * (2.0/PI));

  } else if (waveMode == 3) { // Sawtooth

    float val1 = yScale * _ty; float val2 = xScale * _tx + PI_2;

    float val3 = xAmplitude * _tx; float val4 = yAmplitude * _ty + PI_2;

    newX = (2.0 * (val1 / TWO_PI - floor(0.5 + val1 / TWO_PI))) - (2.0 * (val2 / TWO_PI - floor(0.5 + val2 / TWO_PI)));

    newY = (2.0 * (val3 / TWO_PI - floor(0.5 + val3 / TWO_PI))) - (2.0 * (val4 / TWO_PI - floor(0.5 + val4 / TWO_PI)));

  } else { // Sine

    newX = sin(yScale * _ty) - cos(xScale * _tx);

    newY = sin(xAmplitude * _tx) - cos(yAmplitude * _ty);

  }

} 

else if (attractorMode == 2) { // Svensson

  if (waveMode == 1) { // Square

    newX = yAmplitude * sign(sin(yScale * _tx)) - sign(sin(xScale * _ty));

    newY = xAmplitude * sign(sin(yScale * _tx + PI_2)) + sign(sin(xScale * _ty + PI_2));

  } else if (waveMode == 2) { // Triangle

    newX = yAmplitude * (asin(sin(yScale * _tx)) * (2.0/PI)) - (asin(sin(xScale * _ty)) * (2.0/PI));

    newY = xAmplitude * (asin(sin(yScale * _tx + PI_2)) * (2.0/PI)) + (asin(sin(xScale * _ty + PI_2)) * (2.0/PI));

  } else if (waveMode == 3) { // Sawtooth

    float val1 = yAmplitude * (2.0 * ( (yScale*_tx) / TWO_PI - floor(0.5 + (yScale*_tx) / TWO_PI)));

    float val2 = (2.0 * ( (xScale*_ty) / TWO_PI - floor(0.5 + (xScale*_ty) / TWO_PI)));

    newX = val1 - val2;

    float val3 = xAmplitude * (2.0 * ( (yScale*_tx+PI_2) / TWO_PI - floor(0.5 + (yScale*_tx+PI_2) / TWO_PI)));

    float val4 = (2.0 * ( (xScale*_ty+PI_2) / TWO_PI - floor(0.5 + (xScale*_ty+PI_2) / TWO_PI)));

    newY = val3 + val4;

  } else { // Sine

    newX = yAmplitude * sin(yScale * _tx) - sin(xScale * _ty);

    newY = xAmplitude * cos(yScale * _tx) + cos(xScale * _ty);

  }

}

else if (attractorMode == 3) { // Gumowski-Mira

    // This attractor has its own unique formula and does not use waves.

    // 'xAmplitude' is used for 'a' and 'yScale' is used for 'b'.

    float g_x = xAmplitude * _tx + (2.0 * (1.0 - xAmplitude) * _tx * _tx) / (1.0 + _tx * _tx);

    newY = (yScale * _ty) + g_x;

    newX = -_tx + g_x;

}

else { // Clifford (Default)

  if (waveMode == 1) { // Square

    newX = sign(sin(yScale * _ty * freqY + phaseY)) + xAmplitude * sign(sin(yScale * _tx * freqX + phaseX + PI_2));

    newY = sign(sin(xScale * _tx * freqX + phaseX)) + yAmplitude * sign(sin(xScale * _ty * freqY + phaseY + PI_2));

  } else if (waveMode == 2) { // Triangle

    newX = (asin(sin(yScale * _ty * freqY + phaseY)) * (2.0/PI)) + xAmplitude * (asin(sin(yScale * _tx * freqX + phaseX + PI_2)) * (2.0/PI));

    newY = (asin(sin(xScale * _tx * freqX + phaseX)) * (2.0/PI)) + yAmplitude * (asin(sin(xScale * _ty * freqY + phaseY + PI_2)) * (2.0/PI));

  } else if (waveMode == 3) { // Sawtooth

    float val1 = yScale * _ty * freqY + phaseY;

    float val2 = yScale * _tx * freqX + phaseX + PI_2;

    newX = (2.0 * (val1/TWO_PI - floor(0.5+val1/TWO_PI))) + xAmplitude * (2.0 * (val2/TWO_PI - floor(0.5+val2/TWO_PI)));

    float val3 = xScale * _tx * freqX + phaseX;

    float val4 = xScale * _ty * freqY + phaseY + PI_2;

    newY = (2.0 * (val3/TWO_PI - floor(0.5+val3/TWO_PI))) + yAmplitude * (2.0 * (val4/TWO_PI - floor(0.5+val4/TWO_PI)));

  } else { // Sine

    newX = sin(yScale * _ty * freqY + phaseY) + xAmplitude * cos(yScale * _tx * freqX + phaseX);

    newY = sin(xScale * _tx * freqX + phaseX) + yAmplitude * cos(xScale * _ty * freqY + phaseY);

  }

}

// Apply the final transformation

_vx += (newX - _tx) * amount;

_vy += (newY - _ty) * amount;

[INV_VARIATION_CODE]

[CUSTOM_FUNCTIONS]

[FUNC_DEPENDENCIES]

Avec Attractors

Attractors est une l’appli livrée avec Incendia qui permet aussi de générer des attracteurs étranges. Encore une fois, il n’y a pas de détails précis concernant les attracteurs utilisés : c’est plus un lociciel en dévellopement ou de recherches qu’autre chose.

L’interface est simple et très proche d’Incendia : on n’est pas dépaysés !

Il est bien sûr possible d’animer ces fractales. Suivre ce tutoriel pour l’animation de ces formes.

 

 

 

 
Publié le Juil 3, 2025

Catégories

0 commentaires