Ouais je n'ouvre pas de post pour un nouveau jeu (mais ça viendra ^^).
J'ai donc décidé de me lancer dans une lib 3D multi-plateforme (dans le sens ou elle visera autre chose que du PC) , comme vous le savez j'aime bien les consoles rétro mais recoder pour chaque machine c'est moyen.
Certe pour les consoles 8/16 bits on peut utilisait du C mais je trouve que cela est plus compliqué a faire du multi-plateforme surtout si on veut exploiter ces machines (ce qui est mon cas ).
Bref donc c'est une lib qui vise ces machines :
-PC (Windows/Linux/MAC OS).
-PlayStation 2
-Dreamcast
-PSP
Si dans le futur j'ai beaucoup de temps :
-WII
-GAMECUBE
-XBOX
Et si j'ai encore plus de temps :
-PlayStation 1
-N64
(Non pas la Saturn ).
Pour la Version PC
J'utilise la SDL 1.2 pour le fenêtrage et les évents , et OpenGL 1
éventuellement mettre une option pour OpenGL 2 voir 3 , mais mon but n'est pas de pousser la version PC , le but de cette lib c'est pas de faire des jeux 3D Moderne
Pour la Version Dreamcast
La version Dreamcast j'avais utilisé un binding OpenGL (que faudra que je m'en passe pour exploiter la machine a 100%).
Pour la Version PS2
Actuellement je travaille sur la version PS2 , donc attendez vous a un gros pavé
Avant de vous parlé Voila quelque truc a savoir :
La PS2 a un processeur principal le EE (Emotion Engine)
Et 2 co processeur mathématique le VU0 et VU1 qui possède respectivement 4 et 16ko.
Et son GPU le GS (Graphic Synthesizer ).
Niveau info intéressante sur PS2 , ben deja la GS utilise des nombres a firgule fixe ! je trouve ça marrant , enfin ça réduit les transferts la PS2 est une console 64/128 bits sur 64 bits en envoie les coordonnées pour X,Y,Z. (ici Z dans le sens Z Buffer) , 16 bits pour X , 16 bits pour Y et 32 bits pour Z.
L'affichage de la PS2 se fait sur un "écran virtuelle" (je sais pas comment appeler ce truc) sur 4096x4096 , du coup si on veut avoir des nombres négatif , le mieux c'est d'afficher dans son centre donc 2048 x)
La PS2 possède 4Mo de VRAM mais cette VRAM prend en compte le Frame Buffer et le Z buffer , et donc ça réduit énormément le nombre de texture mais !
Si on met le Zbuffer en 16 bits.
Le Frame Buffer en 16 bits (mais ça réduit le nombre de couleur).
Le Frame buffer peut être en 640x240 (qui peut être en mode 640x480 en agrandissant par deux la hauteur de l'écran).
De plus si on utilisent des textures en mode palette de couleur (oui c'est la seul console qui peut le faire de cette génération) , d'ailleurs les jeux squaresoft utilisait cette compression , vu que leur textures faisait moins de 256 couleurs !
Donc du 640x256 (c'est le mode NTSC) ça prend 1Mo en mode 16 bits le FB et 1,6 Mo le mode 32 bits.
Une texture peut prendre donc 64ko , donc pour 2Mo on peut avoir 32 texture de 256x256.
On peut faire des transferts dma RAM/VRAM, la PS2 possède des transferts très rapide et je pense qu'on peut rajouter 4-8 textures en plus sans que les perf soit très altérer.
Alors comme vous le savez c'est une console extrêmement compliqué et qui même si elle est la console la plus vendu de l'histoire ben la scène hombrew est quasi inexistante.
Il existe un binding OpenGL fait par des amateurs , je l'ai jamais utilisé mais en regardant son code , il n’afficherait pas plus de 15-20k poly par frame , soit moins 1 millions de poly par seconde
Et le PS2 SDK lui probablement moins de 10k poly par frame si on l'utilise comme tel.
Pour expliquer la prog PS2 , si on fait un affichage 3D en Macro code avec le VU0 (en gros un truc pas en parallèle qui s’exécute sur le EE principal), on affiche 9000 poly.
On peut augmenter a 13000 poly si on fait un Double Buffer !
Oui on peut faire un double buffer sur les transferts DMA vu qu'ils sont en parallèle (bref non bloquant) on peut faire le calcul suivant en attendant
Par exemple sur les vielles machines comme la SNES ou la Mega Drive le DMA est bloquant et donc en attend que le DMA finisse son transfert pour reprendre le main.
J'avais augmenter les perf a 14500 poly en réduisant les transferts DMA.
A vrai dire mon premier test sur PS2 j'avais remarqué un truc , deja que j’affichais que 25k poly (via VU1) et que le temps de calcul était assez bas.
La réponse j'ai eu du mal a la trouver le premier est que mon temps de calcul assez bas est sûrement du a la lecture des entrées qui est sûrement un peu longue.
Le second avec beaucoup de test j'ai remarqué que mes temps de calcul était réparti comme ceci :
-7% DMA
-75% le VU1
-18% GS
Donc j'ai du retravailler la programmation du VU1,enfaîte c'est un processeur qui ne fait que 1 cycle instruction sous certaine condition , sinon le VU va attendre que l’instruction finisse avant de passer a la suivante (qui dure a peu prés 4 cycle par instruction).
Et cela devient très compliqué a optimiser croyait moi , parce que ça demande de faire un code comment dire dégueulasse il faut pas organiser forcément son code de façon 'logique' en gros faut faire tjs faire des calculs , par exemple calculer le vertex suivant ou récupérer la valeur du vertex en même temps (oui c'est un processeur Superscalaire et VLIW) ,ah oui le VU1 c'est en asm que ça se code , un assembleur 128 bits et assez difficile a coder, et c'est lui qui fait tout les calculs 3D (et faire de l'asm en 3D sur un processeur aussi compliqué que le VU1 c'est sportif ! ).
D'un coté ça explique pourquoi la PS2 a mis du temps pour être exploiter (et que en amateur elle ne l'a jamais était exploiter !).
En gros voila ma version du VU1 que j'avais mis (j'ai mis plusieurs semaine quand même pour comprendre tout ce que je faisais ).
Et la certain diront , c'est quand même du code compréhensible , c'est vrai ça reste encore lisible :p
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 .syntax new .name vu1Triangle .vu .init_vf_all .init_vi_all --enter --endenter ;vf01 matrix ;vf02 matrix ;vf03 matrix ;vf04 matrix ;vf05 tmp ;vf06 tmp ;vf07 arg1 ;vf11 max ;vi01 count adress ;vi04 n vertices ;vi05 max ;vi10 z control lq vf01, 0(vi00) lq vf02, 1(vi00) lq vf03, 2(vi00) lq vf04, 3(vi00) lq vf07, 4(vi00) mtir vi04,vf07[w] iaddiu vi01, vi00, 6 vertexLoop: ;vertex 1 lq vf08, (vi01) lq vf06, 2(vi01) mul acc, vf01, vf06[x] madd acc, vf02, vf06[y] madd acc, vf03, vf06[z] madd vf05, vf04, vf06[w] div q, vf00[w], vf05[w] mul.xyz vf06, vf05, q ftoi4 vf06, vf06 div q, vf08[w], vf05[w] mul.xyzw vf08, vf08, q sqi vf08, (vi01++) sqi vf06, (vi01++) sqi vf06, (vi01++) ;vertex 2 lq vf08, (vi01) lq vf06, 2(vi01) mul acc, vf01, vf06[x] madd acc, vf02, vf06[y] madd acc, vf03, vf06[z] madd vf05, vf04, vf06[w] div q, vf00[w], vf05[w] mul.xyz vf06, vf05, q ftoi4 vf06, vf06 div q, vf08[w], vf05[w] mul.xyzw vf08, vf08, q sqi vf08, (vi01++) sqi vf06, (vi01++) sqi vf06, (vi01++) ;vertex 3 lq vf08, (vi01) lq vf06, 2(vi01) mul acc, vf01, vf06[x] madd acc, vf02, vf06[y] madd acc, vf03, vf06[z] madd vf05, vf04, vf06[w] div q, vf00[w], vf05[w] mul.xyz vf06, vf05, q ftoi4 vf06, vf06 div q, vf08[w], vf05[w] mul.xyzw vf08, vf08, q sqi vf08, (vi01++) sqi vf06, (vi01++) sqi vf06, (vi01++) iaddi vi04, vi04, -3 ibne vi04, vi00, vertexLoop iaddiu vi01, vi00, 5 xgkick vi01 --exit --endexit
Voila mon premier set qui optimise le VU1 en prenant compte des spécificités du processeur:
Et ce code m'a permis de monter a 37k poly , j’étais content XD
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 .global vu1Triangle_CodeStart .global vu1Triangle_CodeEnd vu1Triangle_CodeStart: .p2align 8 .vu nop lq VF05, 5(VI00) nop lq VF06, 4(VI00) nop lq VF01, 0(VI00) nop lq VF02, 1(VI00) nop lq VF03, 2(VI00) nop lq VF04, 3(VI00) nop sq VF05, 511(VI00) nop mtir VI04, VF06w nop iaddiu VI01, VI00, 6 nop iaddiu VI02, VI00, 512 vertexLoop: nop lqi VF08, (VI01++) ; vt1 nop lq VF09, 0(VI01) ; v1A nop lq VF10, 0(VI01) ; v1B nop lq VF11, 0(VI01) ; v1C nop lqi VF12, (VI01++) ; v1D mulax ACC, VF01, VF09x lqi VF13, (VI01++) ; vt2 madday ACC, VF02, VF10y lq VF14, 0(VI01) ; v2A maddaz ACC, VF03, VF11z lq VF15, 0(VI01) ; v2B maddw VF05, VF04, VF12w lq VF16, 0(VI01) ; v2C ;3cycle nop div q, VF00w, VF05w mulax ACC, VF01, VF14x lqi VF17, (VI01++) ; v2D madday ACC, VF02, VF15y lqi VF18, (VI01++) ; vt3 maddaz ACC, VF03, VF16z lq VF19, 0(VI01) ; v3A maddw VF06, VF04, VF17w lq VF20, 0(VI01) ; v3B nop lq VF21, 0(VI01) ; v3C nop lqi VF22, (VI01++) ; v3D mulq.xyz VF31, VF05, q nop nop div q, VF00w, VF06w nop sqi VF08, (VI02++); st vt1 mulax ACC, VF01, VF19x nop ftoi4.xyz VF30, VF31 nop madday ACC, VF02, VF20y nop maddaz ACC, VF03, VF21z nop maddw VF07, VF04, VF22w sqi VF08, (VI02++); st color1 mulq.xyz VF28, VF06, q nop nop sqi VF30, (VI02++) ; st v1 ;1 cycle nop div q, VF00w, VF07w nop sqi VF13, (VI02++) ; st vt2 nop sqi VF08, (VI02++) ; st color2 ftoi4.xyz VF27, VF28 nop ;3cycle mulq.xyz VF26, VF07, q waitq nop sqi VF27, (VI02++) ; st v2 nop sqi VF18, (VI02++) ; st vt3 nop sqi VF08, (VI02++) ; st color 3 ftoi4.xyz VF25, VF26 nop nop iaddi VI04, VI04, -3 ;2 cycle nop sqi VF25, (VI02++) ; st v3 nop ibne VI04, VI00, vertexLoop nop nop nop iaddiu VI01, VI00, 511 nop xgkick VI01 nop nop nop b eclip nop nop clip3: clip2: clip1: eclip: nop[E] nop nop nop vu1Triangle_CodeEnd:
Vous remarquerez que j'ai mis en commentaire le nombre de cycle (ce sont le nombre de cycle ou le VU attend) , rigolo de compter les cycles x)
Ensuite j'ai optimiser a droite a gauche 41 puis 45k et la blocage :3
Vous vous souvenez j'ai dit que le GS prenait a peu près 20% , on peut le faire en parallèle et j'ai gagnait donc les 20% , et je suis montait a 64k poly, ensuite j'ai réduit encore l'utilisation du VU1 en optimisant le code , et je suis monté a 69k poly.
La première fois que j'ai fait cela (a 64k poly) ça marchait bien mais quand j'ai encore optimiser a 69k poly , ça marchait bien sur l'ému mais pas sur la PS2 réel ou j'avais de gros bug d'affichage , j'ai remarquer en faite que le souci venait du transfert vers le GS (que pendant le transfert je l'écrivait en court de route ), et maintenant dans le code du VU1 je met un double buffer x)
Voila le résultat sur une PS2 :
Mes 69k poly : https://img15.hostingpics.net/pics/7...0126055420.jpg
L'affichage d'un model ici Zack de FF7 : https://img15.hostingpics.net/pics/5...0126055508.jpg
On faisant des petites optimisation j'ai pu monter encore a 70k poly.
Si je change pas de technique je peux peut être optimiser encore le VU1 pour monter a 76-77k poly d’après mes calculs théoriques (si vous me dites pas pourquoi je ne le fais pas , parce que ça me prend des heures pour optimiser le VU1 ).
Et même pas sur que j'y arrive , la dernière optimisation est complexe.
Après y'a sûrement des spécificités du VU qu je connais pas encore et qu'on peut monter encore monter plus m'enfin bref.
Mais actuellement je me concentre pas sur l'optimisation du VU1 mais sur un truc que j'ai lu d'assez intéressant c'est les transferts DMA peuvent se faire en parallèle a l’exécution du VU1 , dans mon cas peut être monter le nombre de poly a 85k poly (pas encore réussi du coup).
Ce qu'il faut savoir c'est qu'on peut utiliser le VU0 en parallèle qui je pense peut permettre encore d’augmenter les perf de 20-30%.
L'autre technique difficile a mettre en place c'est les index donc la je parle d'une augmentation facile de 100% de poly en plus , je ne détaillerai pas la difficulté de cette technique dans mon cas (non faire un for avec un tableau a la con ça augmente que dalle ).
Niveau code donc je code en C et en assembleur , tout le code relatif a l'affichage je le fait moi même en tapant directement sur les I/O (la plupart des amateur utilise le PS2 SDK mais mon but et d'avoir un contrôle sur les graphisme a 100%).
Voila je pense que j'ai fait globalement le tour ,pour la question des collisions 3D et de l'animation par squelette je l'avais deja codait sur un moteur fait maison , quand l'optimisation de l'affichage de la PS2 sera fait je pense les intégrer , et ensuite je passerait sur l'affichage bas niveau Dreamcast
Pour ma lib si vous voulez savoir a quoi elle ressemble :
Bien sur y'as encore des améliorations a faire
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 void game() { LMP3D_Event event; LMP3D_Camera camera; camera = LMP3D_Camera_Init(); LMP3D_Event_Init(&event); int touche[10],i; Vector3 angle; angle.x = 5.7; angle.y = 2.1; angle.z = 3.0; camera.position.x = 7; camera.position.y = 0; camera.position.z = 100; angle.x = 1.6; angle.y = 1.5; angle.z = 5.0; LMP3D_Model * model; model = LMP3D_Load_Model("DATA/zack/zack.bcm"); while(event.exit == 0) { //evenement LMP3D_Event_Update(&event); for(i = 0;i < 10;i++) touche[i] = 0; if(event.key['k'] == 2) touche[0] = 1; if(event.key['m'] == 2) touche[0] = 2; if(event.key['o'] == 2) touche[2] = 2; if(event.key['l'] == 2) touche[2] = 1; if(event.key['a'] == 2) touche[1] = 1; if(event.key['z'] == 2) touche[1] = 2; //camera LMP3D_Camera_Perspective(camera); LMP3D_Camera_vue_sub(&camera,&angle,0.1,touche); LMP3D_Camera_LookAt(camera); LMP3D_Model_Draw(model); LMP3D_Clear(); LMP3D_VBlank(); } }
D'ailleurs même si c'est une lib 3D mais je compte lui mettre des fonctions 2D software , avoir un affichage de 2,4 ou 8bpp (bits par pixel) peut être avantageux sur des vielles machine même sur PS2/DC !
Je remercie DragonJoker qui m'a bien aidé pour mes questions sur la 3D (et son aide via le code vu que le projet était initialement en C++ pour ma lib).
Et Yahiko pour sa fonction du sinus optimisé :p
Partager