1

De nos jours, dès qu'on cherche une solution de rotation de sprite, les seules réponses qu'on trouve sont du genre "y'a la librairie machin qui propose une fonction rotate bidule...".

Le plus simple que j'ai vu, c'est de parcourir la zone d'arrivée et de chercher le pixel à afficher dans l'image d'origine en fonction de la rotation. (en faisant l'inverse, on risque de laisser des pixels vides dans l'image d'arrivée)

Le truc c'est : comment avoir une équation "propre" qui pour un point d'arrivée, (x1,y1) nous dise quel (x2,y2) du sprite d'origine il faut utiliser avec un angle alpha et un centre de rotation (x3,y3) ?

La question subsidaire : peut on faire de la rotation performante (pas forcément 100% précise) qui n'utilise pas de fonctions trigo ?
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

2

je reponds ce soir si personne l'a fait avant, mais deja, a la question subsidiaire: oui, c'est tout a fait possible, ca revient a faire du mapping de texture, du moment que tu as les coordonnees des 4 coins de ton sprite. (mais bon, pour calculer ces coordonnees, il te faut peut-etre des fonctions trigos, ca depend)

et sinon:
tu as un rectangle fixe et tu veux rotate une image a l'interieur (ie: les coordonnees des coins du sprite ne changent pas), ou t'as un sprite rectangulaire que tu veux rotate (et sa texture avec)?
avatar
HURRRR !

3

Un sprite rectantulaire que je veux rotate (pas de "texture", le sprite est un tableau de valeurs, chaque valeur est un indice de palette/couleur)

Pas besoin d'anticrénelage non plus
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

4

vince (./1) :
Le truc c'est : comment avoir une équation "propre" qui pour un point d'arrivée, (x1,y1) nous dise quel (x2,y2) du sprite d'origine il faut utiliser avec un angle alpha et un centre de rotation (x3,y3) ?

Un rotozoom de facteur z est une simple application linéaire complexe x1+iy1=f(x2+iy2)=z(x2+iy2). Pour une rotation sans zoom, tu as z=e=cos(α)+i sin(α). La fonction qui t'intéresse ici est x2+iy2=f-1(x1+iy1)=z-1(x1+iy1)=e-iα(x1+iy1)=(cos(-α)+i sin(-α))(x1+iy1)=(cos(α)-i sin(α))(x1+iy1)=x1cos(α)+y1sin(α)+i(y1cos(α)-x1sin(α)).
Donc ta formule est (x2, y2)=f-1(x1, y1)=(x1cos(α)+y1sin(α), y1cos(α)-x1sin(α)).

[EDIT: Le calcul présuppose une rotation autour de l'origine, cf. ./10 pour le centre de rotation.]
La question subsidaire : peut on faire de la rotation performante (pas forcément 100% précise) qui n'utilise pas de fonctions trigo ?

Ça revient essentiellement à approximer le sinus et le cosinus de ton angle α.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

5

perso ce que je ferais :

1 implémenter http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
2 au lieu de blitter la ligne, sauver ses décalages x et y entre les pixels
3 sauver les décalages de la ligne correspondant à l'angle de rotation et la hauteur du sprite
4 sauver les décalages de la ligne angle+90 et largeur du sprite
5 blitter chaque ligne du sprite d'origine avec comme décalage de départ les déplacements donnés en 4 et comme décalage de chaque pixel de ta ligne celle en 3

edit => mais ça ne gererais pas le centre de rotation ^^
et t'auras peut être des soucis entre la longueur en pixel effectif de la ligne par rapport à celle du sprite, il faudrait la "caper"
et la le mec il le pécho par le bras et il lui dit '

6

Kevin Kofler (./4) :
La question subsidaire : peut on faire de la rotation performante (pas forcément 100% précise) qui n'utilise pas de fonctions trigo ?
Ça revient essentiellement à approximer le sinus et le cosinus de ton angle α.


L'idée c'était d'exprimer l'angle sous une forme dx,dy, (donc indirectement la tangente de l'angle alpha)
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

7

Il me *semble* que non à priori. Par contre un accès à une table (hors 68k et 8 bits peut être) est généralement très performant et tu peux garder les mêmes facteurs toute une ligne, donc ce n'est normalement pas l'élément bloquant.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

8

./7> tant que t'as une rotation et un zoom uniforme sur tout le sprite, tu garde les memes facteurs sur tout le sprite hein...

apres, si tu cherche absolument a eviter les fonctions trigos et les tables precalculees, et que tes rotations sont incrementales, tu peux jeter un oeil du cote des resonant filters, cf ce pdf: http://www.research.scea.com/research/pdfs/RGREENfastermath_GDC02.pdf
avatar
HURRRR !

9

vince (./6) :
L'idée c'était d'exprimer l'angle sous une forme dx,dy, (donc indirectement la tangente de l'angle alpha)

Tes dx et dy sont sin(α) et cos(α) à un facteur commun r=||(dx, dy)||=√(dx²+dy²) près. Donc en fin de compte il te faut soit calculer r, soit trouver un moyen d'éviter de le calculer.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

10

robinHood (./5) :
edit => mais ça ne gererais pas le centre de rotation ^^

Ah tiens, j'ai aussi oublié ça dans mes formules. embarrassed

Tu as f(x2+iy2)=z((x2-x3)+i(y2-y3))+x3+iy3 et donc (x2, y2)=f-1(x1, y1)=((x1-x3)cos(α)+(y1-y3)sin(α)+x3, (y1-y3)cos(α)-(x1-x3)sin(α)+y3). Le raisonnement est le même que pour x3=y3=0, juste avec quelques additions et soustractions en plus.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

11

bearbecue (./8) :
./7> tant que t'as une rotation et un zoom uniforme sur tout le sprite, tu garde les memes facteurs sur tout le sprite hein...

Heu ouais. J'ai lu rotozoom et j'ai de toute pensé au mode 7.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

12

Brunni (./11) :
bearbecue (./8) :
./7> tant que t'as une rotation et un zoom uniforme sur tout le sprite, tu garde les memes facteurs sur tout le sprite hein...

Heu ouais. J'ai lu rotozoom et j'ai de toute pensé au mode 7.

sauf que le mode 7 n'utilise pas des facteurs constants, ils changent pour simuler la perspective
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

13

(oui mais justement tu garde les memes par ligne, sauf si c'est une rotozoom pour afficher autre chose qu'un sol horizontal oui
avatar
HURRRR !

14

Je pense que je ne parle pas de la même chose que toi, ou que je n'ai pas compris
(en plissant les yeux ça donne pas mal wink)


Sprite d'origine
0000000000
0000000000
0011111000
0010001000
0010001000
0010001000
0011111000
0000000000
0000000000
0000000000

Sprite rotozoomé
0000000000
0001100000
0010011000
0010001100
0100001000
0111010000
0000110000
0000000000

Sprite mode7isé
0000000000
0001000000
0001100000
0010010000
0100001000
0100000100
1100000100
0011001000
0000110000


A mon sens, vu qu'il y a déformation sur la version "mode7", il faut appliquer un coefficient d'étirement, donc les facteurs ne peuvent pas être constants (même s'ils restentlinéaires)
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

15

pas moyen d'utiliser ça pour calculer les coordonnées des 4 points rotatés?

http://en.wikipedia.org/wiki/Midpoint_circle_algorithm

16

vince> la en fait ton sprite "mode7ise", c'est pas "mode7ise", c'est un sprite transforme en un quad quelconque en 3D projete, sur lequel la problematique de mapping de texture est strictement identique a la vraie 3D.

le mode7 c'est ca, mais uniquement pour les deformations horizontales:

Mode_7_Test-0000.png

cf la page wikipedia du mode7:
"Mode 7 is a graphics mode on the Super NES video game console that allows a background layer to be rotated and scaled on a scanline-by-scanline basis"


et dans le cas du screenshot au dessus, effectivement, les coefficients sont a calculer une seule fois par scanline.
(d'ailleurs comme ca a froid j'aurais tendance a dire que les dx/dy de la rotation sont calculables une seule fois pour toute l'image, et que c'est juste le scale qui change d'une scanline a l'autre. mais bon je dis ptet une connerie)
avatar
HURRRR !

17

bearbecue (./16) :
vince> la en fait ton sprite "mode7ise", c'est pas "mode7ise", c'est un sprite transforme en un quad quelconque en 3D projete, sur lequel la problematique de mapping de texture est strictement identique a la vraie 3D.

le mode7 c'est ca, mais uniquement pour les deformations horizontales:

Mode_7_Test-0000.png

cf la page wikipedia du mode7:
"Mode 7 is a graphics mode on the Super NES video game console that allows a background layer to be rotated and scaled on a scanline-by-scanline basis"


et dans le cas du screenshot au dessus, effectivement, les coefficients sont a calculer une seule fois par scanline.
(d'ailleurs comme ca a froid j'aurais tendance a dire que les dx/dy de la rotation sont calculables une seule fois pour toute l'image, et que c'est juste le scale qui change d'une scanline a l'autre. mais bon je dis ptet une connerie)

et ça reste valable après que ton mode 7 ait rotaté ?
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

18

bah oui smile
avatar
HURRRR !

19

squalyl (./15) :
pas moyen d'utiliser ça pour calculer les coordonnées des 4 points rotatés?

http://en.wikipedia.org/wiki/Midpoint_circle_algorithm

Tel quel, je ne crois pas, mais un algorithme se basant sur les mêmes techniques est peut-être possible. Cela dit, la wikipédia dit:
To draw only a certain arc from an angle α to an angle β, the algorithm needs first to calculate the x and y coordinates of these end points, where it is necessary to resort to trigonometric or square root computations

donc je ne suis pas convaincu.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

20

Vince > c'est sur Lynx ? Y'a pas de la rotation de sprite hardware ?
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

21

bon, alors, comme ca, je vois deux grands chemins viables possibles:

A- calculer les coordonnees des 4 sommets du rectangle de ton sprite rotate, et utiliser un remplissage par scanline.

B- pour chaque pixel du bounding rect de ton sprite rotate, appeller la fonction qui remappe les coordonnees du pixel vers les coordonnees du pixel dans le sprite. et pour eviter le tiling, si les coordonnees sont en dehors de l'image du sprite, skipper le pixel.



suivant l'architecture cible, l'un ou l'autre peut etre mieux, la comme ca je saurais pas trop quoi te conseiller, donc:

pour A:

1 - trier les coordonnees Y des 4 sommets de la plus faible a la plus grande -> ca te fait au pire 3 primitives simples a remplir, au mieux une seule:
- - - soit un triangle plat, un parallepipede, et un autre triangle plat (tres frequent pour des rotations plus ou moins random)
- - - soit deux triangles (tres rare)
- - - soit un parallepipede (juste quand le sprite a une rotation de 0, 90, 180, etc degres...

2 - pour chacune de ces primitives, tu connais les pentes des deux cotes, et tu peux calculer les dtx/dty dans la texture, vu que tu connais les coordonnees des 4 sommets dans la texture. donc, tu iteres de bas en haut en incrementant a chaque fois les positions avec ton dpx/dpy et les coordonnees des pixels avec ton dtx/dty. le resultat est une serie de paires de coordonnees x situees sur la meme ligne : c'est tes scanlines.

3 - pour chaque scanline, dpx = 1, et dpy = 0 (tu avance d'un pixel en x a chaque fois, et bouge pas en y). tu recalcule un dtx/dty pour la scanline entiere, et tu remplis pixel par pixel en incrementant la coordonnee dans la texture.

4- tu lis la couleur de ta texture a ces coordonnees, tu plot dans le framebuffer -> done.


et t'as implemente un affine texture mapper qui peut te servir a coder un software renderer 3D (ou t'affichera des triangles au lieu de quads, ya que la premiere etape a changer, ton triangle se decompose en un ou deux triangles plats.

il y a d'autres subtilites pour que ton remplissage de triangles soit solide lorsque tu affiche des maillages ou les triangles se touchent, mais je pense que tu t'en fous pour des sprites smile


pour B:

version lente:

1 - t'as les coordonnees de ton sprite, son angle, etc...

- sprite.xy est les coordonnees en pixels ecran du centre de rotation de ton sprite. (ex: centre de rotation du sprite au pixel x=200, y=80, sprite.xy = {200,80})
- center.xy est les coordonnees du centre de rotation de ton sprites dans les coordonnees de l'image du sprite (en texels (texel = pixel d'une texture)) (ex: sprite de 128*128, centre de rotation au centre du sprite, center.xy = {64,64})
- size.xy est la taille en pixels de l'image de ton sprite (ex: {128, 128})
- scale.xy est le scale de ton sprite a l'ecran (2.0 affichera un sprite deux fois plus gros, 0.5 moitie moins gros)
- inv_scale = 1 / scale

screen_to_sprite_global(x, y) = { x - sprite.x, y - sprite.y } <----- convertit les coordonnees ecran en coordonnees relatives au centre de rotation de ton sprite
sprite_global_to_sprite_local(x, y) = { cos(-a) * x + sin(-a) * y, cos(-a) * y - sin(-a) * x } <----- convertit les coordonnees relatives au centre de rotation de ton sprite en coordonnees locales au sprite, en appliquant la rotation inverse.
sprite_local_to_sprite_texels(x, y) = { x * inv_scale.x + center.x, y * inv_scale.y + center.y } <----- convertit les coordonnees locales au sprite rotate en coordonnees texel dans l'image du sprite

remap(x, y) = sprite_local_to_sprite_texels(sprite_global_to_sprite_local(screen_to_sprite_global(x, y))); <----- convertit une coordonnee pixel ecran en une coordonnee de texel dans l'image de ton sprite.

2- maintenant, pour savoir si le pixel de l'ecran est dans le sprite, tu fais juste:

is_coord_inside_sprite(x, y) = (x >= 0 && x < size.x && y >= 0 && y < size.y)

3- ce qui te donne:

coords = remap(pixel.x, pixel.y)
if (is_coord_inside_sprite(coords.x, coords.y))
{
   pixel.color = texture.sample(coords.x, coords.y)
}


ok, donc ca c'est fait.

maintenant pour rendre ca rapide, il y a plusieurs trucs faisables:
- precalculer et sortir tout ce qui est possible de la fonction remap() -> notamment le sin(-a) et cos(-a) qui change pas de tout le sprite.
- virer toutes les multiplications en passant par des increments discrets pour chaque ligne de pixels a l'ecran -> meme systeme de dx/dy que la premiere methode, classique quoi.

le truc chiant, c'est le 'if' pour chaque pixel, suivant la plateforme, ca peut etre pas terrible du tout.
l'autre truc chiant, c'est que si tes sprites sont gros, tu vas passer sur pas mal de pixels en dehors du sprite, donc ca sera pas terrible non plus.



en soit la B est a mon avis beaucoup plus simple a coder que la A, mais ptet plus chiante a optimiser, et est sans doute un peu plus lente au final.
mais bon ca peut etre une bonne chose de l'implementer quand meme, et tu peux l'ameliorer iterativement une fois que t'as un truc qui tourne, et apres ptet comparer avec la A smile

(of course, fixed-point obligatoire partout si pas de floats HW...)

EDIT: precisions
avatar
HURRRR !

22

Y'a pas de risque que les raccords entre les polygones soient visibles avec la méthode A ?
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

23

bah vu que c'est des sprites (donc pas attaches entre eux), nan? grin
(apres si c'est pour rendre un maillage 3D, comme je disais, ya "quelques details en plus", pour eviter que les raccords soient visibles cheeky (enfin, sutout pour eviter que certains pixels soient affiches deux fois, ce qui fout la merde si tu fais du blending))
avatar
HURRRR !

24

En fait je pensais surtout aux raccords entre les différentes passes (triangle + parallélogramme par exemple), mais j'avais zappé le fait que c'est dessiné scanline par scanline, donc que les bordures sont forcément horizontales (pas comme les raccords pour un polygones 3D quelconque, qui peuvent avoir une pente arbitraire). Du coup doit pas y'avoir de souci d'arrondi, effectivement smile
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

25

Merci pour les explications, j'ai du décodage à faire, faut que je relise ça à tête reposée ^^
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

26

bearbecue (./21) :
sprite_global_to_sprite_local(x, y) = { cos(-a) * x + sin(-a) * y, cos(-a) * y - sin(-a) * x } <----- convertit les coordonnees relatives au centre de rotation de ton sprite en coordonnees locales au sprite, en appliquant la rotation inverse.

Cette formule est fausse, c'est la rotation directe, pas la rotation inverse:
sprite_global_to_sprite_local(x, y) = { cos(-a) * x + sin(-a) * y, cos(-a) * y - sin(-a) * x }
Le choix de signes ici en rouge correspond à la rotation inverse (car sin(-t)=-sin(t) et la rotation directe utilise les signes opposés), mais la rotation inverse d'angle -a est la rotation directe d'angle a.

Sauf bien sûr si tu utilises des rotations dans le sens indirect de ton système de coordonnées. Si x pointe vers la droite et y vers le haut, le sens direct est le sens contraire aux aiguilles d'une montre et le sens indirect est le sens des aiguilles d'une montre. Si x pointe vers la droite et y vers le bas, le sens direct est le sens des aiguilles d'une montre et le sens indirect est le sens contraire aux aiguilles d'une montre.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

27

x a droite, y en bas, rotations en sens inverse des aiguilles d'une montre. smile

pis au pire si ca marche pas comme il veut dans les coordonnees que vince choisira, ou qu'il veut le faire tourner dans l'autre sens, on s'en fout, il change les signes cheeky
avatar
HURRRR !