20Fermer22
bearbecueLe 15/11/2012 à 21:43
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