Bonjour à tous, je but sur un problème depuis quelques jour. (encore une fois mathématique, et vue que je n'avais pas choisie une branche S, je patoge un peu). J'ai fais des recherches sur le web mais je n'ai rien trouvé dans ce sens pour des transformations inverse cylindrique ou sphérique
A l'heure actuelle j'ai 2 méthodes qui me permette de rendre une texture soit sphérique soit cylindrique.
Afin d'éviter toute dispersion, je vais commencé par le placage de texture sur un cylindre.
La formule de transformation de coordonnées cartésiennes vers cylindrique et vice versa (wiki et paul bourke):
Si le point P a les coordonnées cylindriques ρ, φ, z alors ses coordonnées cartésiennes correspondantes sont :
Si le point P a les coordonnées cartésiennes x, y, z alors ses coordonnées cylindriques correspondantes sont :
Voici ma texture d'origine
Maintenant, mon code de plaquage de texture sur un cylindre en 2D avec la possibilité de faire "tourner" sur l'axe x ou y suivant l'orientation du cylindre choisie
Code:
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 procedure CylindricalMappingFrom(Texture: TBZBitmap; OffsetX, OffsetY, Radius, CylinderLen: Integer; Const Horizontal: Boolean; Const Rotation: Single); var L, LL : Single; vx, vy, vz : Single; i, j, u, v : Integer; aColor : TBZColor; procedure RotZ(angle : Single; var x : Single; var y : Single); var x1, y1, c, s : Single; begin s := Sin(Angle); c := Cos(Angle); x1 := x * c - y * s; y1 := x * s + y * c; x := x1; y := y1; end; begin if Horizontal then begin L := (c2PI / Texture.Height); LL := (CylinderLen / Texture.Width); end else begin L := (c2PI / Texture.Width); LL := (CylinderLen / Texture.Height); end; for j := 0 to Texture.MaxHeight do begin vz := J * LL; for i := 0 to Texture.MaxWidth do begin if Horizontal then vx := (Radius * cos(i * L)) else vx := -(Radius * cos(i * L)); vy := (Radius * sin(i * L)); if (Rotation <> 0) then RotZ(DegToRadian(Rotation), vx, vy); if (vy > 0.0) then // on dessine que les pixels visible begin aColor := Texture.getPixel(i,j); if Horizontal then begin u := OffsetX + Floor(vz); v := OffsetY + Radius + Floor(vx); end else begin u := OffsetX + Radius + Floor(vx); v := OffsetY + Floor(vz); end; // On dessine un carré de 3x3 pixel pour éviter au maximum les artefacts OwnerBitmap.setPixel(u, v, aColor); OwnerBitmap.setPixel(u - 1, v, aColor); OwnerBitmap.setPixel(u + 1, v, aColor); OwnerBitmap.setPixel(u, v - 1, aColor); OwnerBitmap.setPixel(u, v + 1, aColor); OwnerBitmap.setPixel(u - 1, v - 1, aColor); OwnerBitmap.setPixel(u + 1, v - 1, aColor); OwnerBitmap.setPixel(u - 1, v + 1, aColor); OwnerBitmap.setPixel(u + 1, v + 1, aColor); end; end; end; end;
Le résultat n'est pas mauvais, mais n'est pas très bon, surtout suivant le ratio du "Radius/Longueur" avec les dimensions de la texture. C'est pour cela que je cherche à faire une transformation inverse pour obtenir un rendu de meilleur qualité.
Résultat du code ci-dessus pour un cylindre horizontal (la texture tourne dans le sens vertical suivant la rotation)
Maintenant le code pour "essayer de faire" la transformation inverse (je cherche donc les coordonnées (i,j) dans la texture suivant le point (u,v) sur l'image de destination.
Ici c'est juste l'orientation horizontal et sans prendre en compte la rotation
Code:
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 procedure CylindricalMappingFromInv(Const ATexture: TBZBitmap; OffsetX, OffsetY, Radius, CylinderLen: Integer; Const Horizontal: Boolean; Const Rotation: Single); var u, v, r2 : Integer; i, j, w, L, LL : Single; InColor : TBZColor; begin r2 := Radius + Radius; if Horizontal then begin L := (c2PI / Texture.Height); LL := (CylinderLen / Texture.Width); for v := OffsetY to (OffsetY + CylinderLen) - 1 do begin //u := (y / LL) - OffsetX; for u := OffsetX to (OffsetX + R2) - 1 do begin //------------------------------------ //---> vz := (j / LL) - OffsetX; //---> u := OffsetX + Floor(vz); //u := OffsetX + (J * LL) //u -(J * LL) := OffsetX //-(J * LL) := OffsetX - u; //-J := (OffsetX - u) / LL; //-J := u // J := -u //--------------------------------- i := ((OffsetX - v) / LL); //--------------------------------- //--> vx := (Radius * cos(i * L)) //--> v := OffsetY + Radius + Floor(vx); // v-vx := OffsetY + Radius; // -vx := (OffsetY + Radius - v) // vx := -(OffsetY + Radius - y) = (Radius * cos(i * L) // cos(I * L) = vx / Radius; = (u / sqrt(sqr(u) + sqr(v)) //(I * L) = ArcCos(vx / Radius) // I := ArcCos(vx / Radius) / L; //--------------------------------- w := (OffsetY - Radius - u) ; //j := ArcCos((u / sqrt(sqr(u) + sqr(v)))) / L; //j := (ArcCos(w / Radius) / L) ; //j := sqrt(sqr(u) + sqr(v)); j := sqrt(sqr((OffsetX - u)) + sqr(w)); // / L ; // AXE ZX - vue de haut //i := ((OffsetX - u) / LL); //j := sqrt(sqr((OffsetX - u)) + sqr(w)) ; //j := BZMath.arcTan2(w,(OffsetX - u)); InColor := OwnerBitmap.GetSamplePixel(i, j, psmBicubic, 3, peaWarp); ATexture.setPixel(u,v, InColor); end; end; end; end;
Mes essais ne sont pas bons, il me manque surement quelques chose ou c'est mon cheminement qui est mauvais.
J'ai laissé en commentaire entre les //------------- ma façon dont j'ai posé le problème.
Et j'ai laissé mes autres essais pour (i,j) également en commentaire.
Pièce jointe 577664
Dans la transformation inverse, j'aimerai bien sur également prendre en compte la rotation
Merci d'avance pour votre aide
Cordialement
Jérôme