Obligement - L'Amiga au maximum

Dimanche 21 juillet 2019 - 19:56  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles en d'autres langues


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Logiciels
 · Jeux
 · Scène démo
 · Divers


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : Assembleur - 3D surface pleine
(Article écrit par Jérôme Étienne et extrait d'Amiga News Tech - septembre 1991)


Le listing en fin d'article est relativement efficace dans son domaine. Je l'ai agrémenté de certaines ruses pour accélérer le temps d'exécution, ce qui est primordial pour une démo digne de ce nom. Il nécessite donc un nombre important de points à expliquer. Dans le désordre, nous avons : le détourage de polygones (derivé du détourage de droites déjà expliqué), la technique des faces cachées en elle-même (encore des formules mathématiques, mais comment faire autrement en 3D ?), la méthode utilisée pour remplir les polygones visibles et enfin la structure de l'objet en mémoire, afin que vous puissiez faire bouger autre chose qu'un simple cube.

La technique des faces cachées

Celle que j'utilise, comme disait Coluche, a des avantages et des inconvénients. Elle permet de déterminer si une face est orientée ou non vers l'observateur. Pour ce faire, on oriente chacune des faces dans un sens constant puis l'on teste si elles sont dirigées vers l'observateur. D'après les résultats, on affiche uniquement celles qui sont bien orientées. Ceci peut s'obtenir grâce à un calcul relativement simple, en utilisant la composante z du produit vectoriel (et c'est reparti pour un cours de maths).

Comme chacun sait, le produit vectoriel est une opération entre deux vecteurs ayant pour résultat un vecteur normal au plan formé par ces deux vecteurs. Ainsi, si l'on effectue cette opération après avoir transformé l'objet spatial dans le plan formé par l'écran, le vecteur résultat sera normal à l'écran si les points étaient bien orientés, ou dirigé vers le fond s'ils ne l'étaient pas. Le signe de la partie z nous permet de connaître l'orientation du vecteur normal. En effet, si la partie z est positive, la face est visible. Dans le cas contraire, la face est invisible, on ne l'affiche pas et l'on passe à la suivante.

Dans notre cas, les deux vecteurs sont deux arêtes consécutives du polygone représentant la face. Pour accélérer le temps d'exécution et simplifier la création des objets, les vecteurs sont codés sous la forme des trois sommets des deux vecteurs (deux extrémités pour chacun, mais il y en a une commune, du fait qu'ils sont consécutifs). On peut noter que ces trois points sont tout bonnement trois points consécutifs du polygone.

Une fois les trois paires de coordonnées (x1,y1), (x2,y2) et (x3,y3) obtenues, on calcule la partie z du produit vectoriel, avec la formule :

z=(y2-y1)*(x3-x1)-(y3-y1)*(x2-x1)

Suivant le signe de z, le vecteur normal à la face sera dirigé soit vers le fond, soit vers l'observateur, ce qui nous permet de choisir si l'on affiche ou pas la face en question.

Les avantages d'une telle technique sont rapidité d'exécution et simplicité de programmation. Mais elle possède également un inconvénient majeur : l'objet doit absolument être convexe (rappel : un objet est dit convexe lorsque toutes ses diagonales sont situées à l'intérieur de l'objet). Ceci est une restriction importante, car elle permet de gérer uniquement des objets tels que le cube, le triangle, la sphère, etc. et en aucun cas des objets de la forme d'un hélicoptère, ou autres formes complexes. Dans le cas d'une routine gérant aussi les formes concaves, il faudrait calculer quelle partie de chaque face est visible, puis tracer les parties apparentes. Cette technique est efficace pour l'affichage mais longue au niveau du calcul ; elle est donc utilisable par exemple sur les gros PC connus pour leur rapidité de calcul et la lenteur de leur mémoire graphique, mais difficilement sur un Amiga 68000. On pourrait également utiliser la méthode dite du "z buffer" (tampon de profondeur), qui consiste à calculer la distance qui sépare chaque face de l'observateur puis à les trier dans l'ordre décroissant afin d'afficher une par une chaque face en commençant par la plus éloignée et finissant par la plus proche. Elle a l'avantage de ne posséder aucune restriction de forme, mais elle est bien plus lente à l'affichage, chaque face de l'objet étant dessinée, qu'elle soit visible ou pas.

L'affichage des polygones

Je passerai sur la description du fonctionnement du mode remplissage du Blitter ; vous pouvez la trouver dans les livres tel que le Hardware Manual.

Grâce à ma technique de calcul très contraignante, il n'y a que deux cas à traiter : soit la face est entièrement visible, soit elle est totalement cachée et nous n'avons pas à l'afficher. Pour faire apparaître l'objet, nous allons donc dans un premier temps tracer toutes les arêtes de chaque polygone dans les bons bitplans. Prenons par exemple une face de couleur 3 : il faut tracer les arêtes sur les bitplans 1 et 2 mais pas sur le 3. Ainsi, après le remplissage, la face ne sera dessinée que sur les bitplans 1 et 2 et sera bien de couleur 3.

Un autre problème se pose. Imaginons en effet le coin d'un polygone qui serait dirigé vers le bas à l'intersection des deux arêtes : il n'y aura plus qu'un seul point sur la ligne horizontale. Le Blitter va donc commencer à remplir, mais ne s'arrêtera pas sur le second côté, car en fait, il était confondu avec le premier, d'où bogue hideux et crapuleux. Pour éviter ce problème, il faut dessiner les droites en mode EOR (minterms $4A) et du haut vers le bas. Je ne vous expliquerai pas pourquoi, ayant moi-même trouvé ceci en tatonant. L'utilisaton du mode EOR implique que si l'on dessine deux fois la même droite, nous revenons à l'état initial. Afin d'éviter une opération inutile, j'exécute une routine qui élimine les droites tracées deux fois ; dans le source, elle est mêlée au calcul du produit vectoriel. Son principe est que, sachant que toutes les arêtes d'une même face ont la même couleur, à chaque nouvelle face, on met sa couleur dans le registre couleur de chaque ligne (le troisième mot dans le tableau tab_line) composant cette face par un EOR. Ainsi une ligne qui aurait du être dessinée deux fois ne le sera pas du tout.

Après avoir convenablement tracé les lignes, il ne reste plus qu'à remplir les faces pour faire apparaître l'objet. Ceci peut s'effectuer de différentes manières : la première, que je n'utilise pas, consiste à encadrer l'objet dans un rectangle de la taille minimum et à le remplir avec le Blitter. Elle paraît la plus efficace car la fenêtre est la plus petite possible, mais il n'en est rien. En effet, son temps d'exécution varie énormément en fonction de la taille de l'objet, ce qui peut être très gênant dans une démo. De plus, on passe une grande partie du temps-machine à attendre le Blitter, ce qui est aussi très mauvais.

J'utilise donc une autre méthode, dont le principe est de remplir tout l'écran en permanence. Cela permet d'avoir un temps d'exécution constant et donc d'utiliser de façon optimum le jumelage Blitter/68000. Je vous avais déjà expliqué lors du premier article sur la 3D, que pour effacer plus vite l'écran, je me servais simultanément du 68000 et du Blitter. Ici, on utilise à nouveau cette technique, en l'améliorant toutefois un peu. En effet, non seulement le 68000 efface l'écran en même temps que le Blitter, mais aussi pendant que celui-ci le remplit ! Ceux qui suivent encore doivent se demander comment je fais pour effacer l'écran tout en le remplissant ? Eh bien c'est une bonne question, et je me remercie de me l'avoir posée. En fait, ce cas ne se produit jamais car j'utilise trois pages pour le "flipping" : une qui apparaît à l'écran, une que je remplis au Blitter et une que j'efface au 68000 et au Blitter.

Le détourage de polygones

Résumé des épisodes précédents : la technique utilisée est la dichotomie. Le détourage de droite est le moyen de connaître les coordonnées de la partie visible de la droite. Le détourage de polygone s'inspire fortement de ce dernier, car en fait, il équivaut à un détourage de droite sur chacune des arêtes, plus un léger additif pour le cas où le polygone dépasserait sur la droite de l'écran.

Pour être plus clair, prenons pour exemple un losange régulier dont les quatre bords sortent de chaque côté de l'écran. Les détourages haut et bas se font avec une déconcertante facilité. Il suffit en effet de bien déterminer le registre BLTSIZE de manière à ce que le Blitter commence son action en bas de la partie visible et la termine en haut. Le détourage gauche est lui aussi relativement aisé, car il ne nécessite absolument rien à part le simple détourage de droite qui est commun à chaque cas de détourage. Nous en arrivons au détourage droit qui engendre le supplément de travail évoqué plus haut. Le problème est que si l'extrémité droite du losange (polygone exemple) dépasse du côté droit de l'écran, les points les plus à droite seront théoriquement allumés. De plus, on sait que le Blitter remplit de la droite vers la gauche. Donc, si nous effectuons un unique détourage de droite, les points les plus à droite de l'écran seront vides et le Blitter sera persuadé qu'il ne doit pas remplir cette surface, d'où, encore une fois, un horrible et méchant bogue, la surface théoriquement pleine apparaissant en partie vide.

Pour palier à ce problème, il faut dessiner une droite verticale le long du bord droit de l'écran, allant du y de l'extrémité droite de la droite détourée jusqu'au y prévu avant le détourage. Affinons l'exemple avec une droite de coordonnées (300,0)-(340,40). Pour détourer convenablement cette arête, il faudra afficher non seulement la droite simplement détourée (300,0)-(320,20) mais en plus une droite verticale (320,20)-(320.40). Grâce à cette droite supplémentaire, le Blitter rencontrera des points allumés à l'extrémité droite de l'écran et remplira donc la surface comme prévu.

La structure des objets

La structure est composée de quatre zones de données :

coor_e regroupe les coordonnées spatiales des points les unes à la suite des autres, la première donnée décrivant le nombre total de points composant l'objet.

coor_p sert uniquement à stocker les coordonnées planes des points après rotation et projection.

tab_line définit les lignes par groupe de trois valeurs. Deux sont en fait les numéros des points extrémités, prémultipliés par 4 pour ne pas avoir à le faire au moment de l'accès à la table des coordonnées planes. La troisième valeur est initialisée à 0 et sert, lors du dessin de la ligne, à savoir dans quel(s) bitplan(s) la tracer, afin de ne pas afficher deux fois la même ligne inutilement. La valeur nb_line doit contenir le nombre de lignes dont l'objet est composé.

tab_face détermine les faces, leur orientation et leur couleur. Le premier mot est le nombre de faces de l'objet. Vient ensuite la description de chaque face une par une, ainsi décomposée : trois mots (là encore prémultipliés par 4) contenant les numéros des trois points d'orientation (qui doivent se suivre dans le sens inverse des aiguilles d'une montre lorsque l'on se trouve devant la face), un mot contenant le nombre d'arêtes qui composent cette face, un mot contenant la couleur puis tous les numéros (prémultipliés par 6) des lignes du polygone. Pourquoi prémultipliés par 6 ? Simplement parce que chaque ligne est codée sur trois mots, soit six octets !

Conclusion

Je m'insurge contre la vague de conformisme qui s'empare des demomakers depuis trop longtemps. En effet, il y en a un, en Scandinavie, qui a trouvé un effet original, et le reste de l'Europe l'use jusqu'à la corde en le reproduisant sans vergogne. Et ce n'est encore pas le pire... Il y a aussi la vague de démos purement graphiques qui prend une forte ampleur. Revenons aux sources mes frères ! N'oublions jamais qu'en des temps reculés, le terme "démo" signifiait réellement "démonstration". Le but était de montrer les capacités de la machine...

Prions le Dieu 68000 ! Honorons-le avec des offrandes ne pouvant pas être programmées en BASIC ni même en C ! Pour votre pénitence, vous me ferez chacun une démo originale, demandant un bon niveau technique !

Ainsi finit le sermon du nostalgique. Je reprends le calme qui a fait la réputation du grand prêcheur charismatique que je suis, pour vous annoncer que la prochaine fois, nous verrons comment dépasser allégrement les limites du matériel en mettant plus de huit sprites sur une même ligne de raster.

assembleur
assembleur
assembleur
assembleur
assembleur
assembleur
assembleur
assembleur
assembleur


[Retour en haut] / [Retour aux articles]