N-PN White-Hat Project
[C] effet plasma C/SDL - Version imprimable

+- N-PN White-Hat Project (https://dev.n-pn.fr/forum)
+-- Forum : Programmation (https://dev.n-pn.fr/forum/forumdisplay.php?fid=72)
+--- Forum : Langages compilés (https://dev.n-pn.fr/forum/forumdisplay.php?fid=25)
+--- Sujet : [C] effet plasma C/SDL (/showthread.php?tid=3311)



[C] effet plasma C/SDL - gruik - 07-09-2013




RE: [C] effet plasma C/SDL - Atlas - 07-09-2013

Vraiment sympa l'effet , je vais essayer de comprendre le code , merci du partage !


RE: [C] effet plasma C/SDL - -Mat- - 07-09-2013

C'est cool en effet, pour l'instant j'ai pas regardé le cœur du code et je pense que j'aurais beaucoup de mal à l'assimiler.
Au début, j'ai juste voulu voir le SDL_Delay() ou autre qui faisait ralentir tout jusqu'à ce que je me rende compte qu'il n'y en avait pas ! Chez moi ça monte pas plus haut que 3/4 FPS. C'est vrai que j'ai pas une super config' (Pentium 4) mais je m'attendais pas à ce que ça bouffe autant de CPU. Il faut que la fenêtre soit en 200 x 200 pour que ça soit bien fluide.

Bref super principe. Bien optimisé, ça doit rendre vraiment classe.


RE: [C] effet plasma C/SDL - gruik - 07-09-2013

(07-09-2013, 19h46)-Mat- a écrit : Chez moi ça monte pas plus haut que 3/4 FPS. (...) je m'attendais pas à ce que ça bouffe autant de CPU.

héhé oui, j'ai hésité à l'optimiser et j'ai flemme j'avoue :p

ce qui fait que ca bouffe c'est que pour chaque pixel on a plusieurs sin/cos et que des calculs sur des double, j'ai sorti deux tables pré-calculées et sur mon proc ça a suffit à fluidifier le bouzin mais c'est de l'optimisation très laxiste Wink
également - et c'est une des optimisations les plus importantes - le principe est souvent de créer 2/3 grands tableaux mappés avec les fonctions et ensuite se contenter de prendre une portion dedans correspondant aux dimensions de ce qu'on veut afficher

pour ce qui est du fonctionnement général je pense que les commentaires dans le code sont pas trop mal sentis et résument bien le truc, le reste c'est de reload le module "trigonométrie de 3e" en mémoire et essayer de se représenter les différentes étapes mais c'est assez simple...


RE: [C] effet plasma C/SDL - Kiwazaru - 08-09-2013

Si ça prend tant que ça des capacités du CPU on pourrait pas se servir de cet exemple pour faire un benchmark ?


RE: [C] effet plasma C/SDL - sakiir - 09-09-2013

C'est vraiment fort ! bravo Smile


RE: [C] effet plasma C/SDL - Jek0 - 10-09-2013

Ah le raytracing, le jour ou il font un jeu avec cette techno faudra une salle serveur pour le faire tourner Smile

Edit : Effectivement, j'avais fait un projet de raytracing y'a quelques années, à vu d’œil (myope et astigmate) ça m'a rappelé ça, my bad.


RE: [C] effet plasma C/SDL - gruik - 10-09-2013

(08-09-2013, 16h08)ReVeRse a écrit : Si ça prend tant que ça des capacités du CPU on pourrait pas se servir de cet exemple pour faire un benchmark ?

(vu en pv) le propos d'un benchmark comme 3DMark par exemple c'est pas uniquement de bencher le CPU, bref non ça en fait pas forcément un bon candidat

(09-09-2013, 22h11)sakiir a écrit : C'est vraiment fort ! bravo Smile

merki ! Big Grin

(10-09-2013, 09h08)Jek0 a écrit : Ah le raytracing, le jour ou il font un jeu avec cette techno faudra une salle serveur pour le faire tourner Smile

humm... oui enfin, le raytracing c'est un rendu 3D "à la main" (comme ici), là il s'agit d'un plasma (même démo, ici), y'a pas trop de rapport ^^


RE: [C] effet plasma C/SDL - gruik - 13-09-2013

l'optimisation spéciale -Mat-, tardive mais y'a un SDL_Delay() maintenant Wink

Code DIFF :
--- a/plasma.c  2013-09-13 20:23:06.017363199 +0200
+++ b/plasma.c  2013-09-13 20:23:12.537281232 +0200
@@ -13,6 +13,7 @@
 #define HAUTEUR        500
 #define PI 3.14159265359
 #define STEP 1000
+#define COEF 1000
 
 double distance (unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2) {
        // trigonometrie de ~15/16 ans : calcul de l'hypothenuse
@@ -29,6 +30,11 @@
        double f1, f2, f3, deg = PI/180;
        double *_sin = calloc(360*STEP,sizeof(double)), *_cos = calloc(360*STEP,sizeof(double));
        if (!_sin || !_cos) return -1; // au cas ou malloc se chie dessus, pas la peine d'aller plus loin
+       unsigned int step = 360 * STEP;
+       double *func1 = calloc(LARGEUR*HAUTEUR*16, sizeof(double));
+       double *func2 = calloc(LARGEUR*HAUTEUR*16, sizeof(double));
+       double *func3 = calloc(LARGEUR*HAUTEUR*16, sizeof(double));
+       if (!func1 || !func2 || !func3) return -2;
 
        // on initialise la sdl et le mode gfx
        SDL_Init(SDL_INIT_VIDEO);
@@ -47,6 +53,14 @@
                        ((unsigned char)(192+63*cos(x*0.1*deg)))
                );
        }
+       // precalcul des images en memoire (optimisation)
+       for (x=0; x<LARGEUR*4;x++) {
+               for (y=0;y<HAUTEUR*4;y++) {
+                       func1[y*LARGEUR*4+x] = sin(distance(x, y, LARGEUR*2, HAUTEUR*2) * deg * 0.3);
+                       func2[y*LARGEUR*4+x] = cos(distance(x, y, LARGEUR*2, HAUTEUR*2) * deg * 0.7);
+                       func3[y*LARGEUR*4+x] = cos(distance(x, y, LARGEUR*2, HAUTEUR*2) * deg * 1.1);
+               }
+       }
 
        // la boucle principale
        while (1) {
@@ -60,9 +74,9 @@
                for (y=0;y<HAUTEUR;y++) { // la routine principale, on balaye l'ecran, pour chaque pixel on calcule son index dans la palette
                        for (x=0;x<LARGEUR;x++) {
                                // nos fonctions trigo horribles et consomatrices de cycles
-                               f1 = sin(distance(x, y, LARGEUR + LARGEUR * _sin[(t*2)%(360*STEP)], HAUTEUR + (hhaut * _sin[(t)%(360*STEP)])) * deg * 0.3);
-                               f2 = cos(distance(x, y, LARGEUR + hlarg * _sin[(t*3)%(360*STEP)], HAUTEUR + (HAUTEUR * _cos[(t*4)%(360*STEP)])) * deg * 0.7);
-                               f3 = sin(distance(x, y, LARGEUR + hlarg * _cos[(t)%(360*STEP)], HAUTEUR + (hhaut * _cos[(t*2)%(360*STEP)])) * deg * 1.1);
+                               f1 = func1[((y+(int)(HAUTEUR + hhaut * _sin[t%step]))*(LARGEUR<<2))+(x+(int)(LARGEUR + LARGEUR * _sin[(t<<1)%step]))];
+                               f2 = func2[((y+(int)(HAUTEUR+HAUTEUR*_cos[(t<<2)%step]))*(LARGEUR<<2))+(x+(int)(LARGEUR+hlarg*_sin[(t*3)%step]))];
+                               f3 = func3[((y+(int)(HAUTEUR+hhaut*_cos[(t<<1)%step]))*(LARGEUR<<2))+(x+(int)(LARGEUR+hlarg*_cos[(t)%step]))];
                                // on somme et fait la moyenne des trois fonctions point a point, et on "anime" en ajoutant t, le tout donne l'indice dans la palette de couleurs
                                c = pal[((unsigned char)(512 + 512 * ((f1+f2+f3)/3))+t)%1024];
                                // putpixel
@@ -76,6 +90,7 @@
                t += STEP;
 
                SDL_UpdateRect(screen,0,0,0,0); // on update l'affichage
+               SDL_Delay(20);
        }
 
        // on quitte proprement
 

le pastebin du nouveau code

finalement ça m'aura également permis de me rendre compte, c'était mon premier plasma, et les formules que j'ai choisi si elles donnent un résultat qu'est joli à regarder sont pour autant pas forcément très heureuses, ce serait à refaire il y aurait moyen de choisir plus habilement tous les paramètres pour un résultat tout aussi eye-candy


RE: [C] effet plasma C/SDL - -Mat- - 14-09-2013

En effet c'est beaucoup plus drôle comme ça, c'est vraiment cool !
Comment t'as fait pour trouver tes formules ? En tâtonnant ?


RE: [C] effet plasma C/SDL - gruik - 14-09-2013

ok tu me confirme que ça passe et que c'est fluide sur ta békane, c'est ce que je voulais savoir surtout Wink

(14-09-2013, 13h50)-Mat- a écrit : Comment t'as fait pour trouver tes formules ? En tâtonnant ?

plus ou moins oui, disons que je suis parti du principe global d'un plasma (le propos étant de le faire entièrement sans repomper un code existant évidement) et ensuite j'ai effectivement tâtonné jusqu'à avoir un résultat pas trop dégueu
du coup pour l'optimisation je tenais malgré tout à conserver les mêmes formules plutôt que de glisser vers des formules plus pratiques en terme de cout mémoire et cpu

il y a moyen de l'accelerer encore énormément, en choisissant des formules qui permettent de ne précalculer qu'une seule image au lieu de trois, 4x plus petites en mémoire, des "mouvements" sinusoïdaux plus simples en termes de calculs, à ça on peut envisager de threader le calcul de chacune des trois fonctions f1,f2,f3 (voire même d'en faire sauter une carrément), d'utiliser un algo type CORDIC pour le calcul des sin/cos... pour les grandes lignes :p