Obrót obiektu wokół własnej osi.

0

Ja już wymiękam nie wiem co jest nie tak. Jak zwykle zacznę od kodu.

Mam taką klasę:

type
  TGameObject2D = class
  private
    fAngle,                               // Kąt obrotu
    fx1,                                  // Współrzędna x lewego górnego rogu
    fy1,                                  // Współrzędna y lewego górnego rogu
    fx2,                                  // Współrzędna x prawego dolnego rogu
    fy2,                                  // Współrzędna y prawego dolnego rogu
    fWidth,                               // Długość
    fHeight,                              // Szerokość
    fCenterX,                             // Współrzędna x środka
    fCenterY  : Real;                     // Współrzędna y środka
    Texture   : gluInt;                   // Tekstura

    procedure SetCenterX(CenterX : Real);
    procedure SetCenterY(CenterY : Real);
  public
    constructor Create(x, y : Real; PathToTexture : String);
    destructor Destroy; override;

    property X : Real read fCenterX write SetCenterX;
    property Y : Real read fCenterY write SetCenterY;
    property Angle : Real read fAngle write fAngle;

    procedure Draw;
  end;

{==============================================================================}

implementation

{==============================================================================}

// Konstruktor klasy. Ustawia x, y, szerokość, wysokość, oraz x i y środka.
//-------------------------------------------------------------------------
constructor TGameObject2D.Create(x, y : Real; PathToTexture : String);
begin
  inherited Create;
  fAngle := 0;

  fCenterX := x;
  fCenterY := y;

  fWidth := 0.1;
  fHeight := 0.1;

  fx1 := fCenterX - (fWidth / 2);
  fx2 := fx1 + fWidth;

  fy1 := fCenterY - (fHeight / 2);
  fy2 := fy1 + fHeight;

  Texture := LoadTexture(PathToTexture);
end;

{------------------------------------------------------------------------------}

// Destruktor klasy. Czyści pamięć pól klasy.
//-------------------------------------------
destructor TGameObject2D.Destroy;
begin
  inherited Destroy;
end;

{------------------------------------------------------------------------------}

// Ustawia x środka i na podstawie tego wylicza fx1 i fx2.
//--------------------------------------------------------
procedure TGameObject2D.SetCenterX(CenterX : Real);
begin
  fCenterX := CenterX;
  fx1 := fCenterX - (fWidth / 2);
  fx2 := fx1 + fWidth;
end;

{------------------------------------------------------------------------------}

// Ustawia y środka i na podstawie tego wylicza fy1 i fy2.
//--------------------------------------------------------
procedure TGameObject2D.SetCenterY(CenterY : Real);
begin
  fCenterY := CenterY;
  fy1 := fCenterY - (fHeight / 2);
  fy2 := fy1 + fHeight;
end;

{------------------------------------------------------------------------------}

// Rysuje obiekt na ekranie.
//--------------------------
procedure TGameObject2D.Draw;
begin
  glPushMatrix();
    glTranslatef(fCenterX, fCenterY, 0);
    glRotatef(fAngle, 0, 0, 1);
    glBindTexture(GL_TEXTURE_2D, texture);
    glBegin(GL_POLYGON);
      glTexCoord2f(0, 0); glVertex3f(fx1, fy1, 0);
      glTexCoord2f(1, 0); glVertex3f(fx2, fy1, 0);
      glTexCoord2f(1, 1); glVertex3f(fx2, fy2, 0);
      glTexCoord2f(0, 1); glVertex3f(fx1, fy2, 0);
    glEnd();
  glPopMatrix;
end; 

Obiekt tej klasy tworzę w ten sposób:

GameObject := TGameObject2D.Create(0, 0, 'texture1.bmp');

Więc znajduje się on na środku ekranu.

I jak chce go obrócić o dany kąt fAngle wokół własnej osi to dopóki obiekt ten znajduje się na środku ekranu to obraca się wokół własnej osi. Jednak gdy przesunę obiekt w inne miejsce ekranu to obiekt obraza się wokół środka ekranu...

Przeczytałem na googlach i w książce, że najpierw trzeba ustawić środek układu współrzędnych na środku obiektu i dopiero potem go obracać i właśnie to robię:

  glPushMatrix();
    glTranslatef(fCenterX, fCenterY, 0);
    glRotatef(fAngle, 0, 0, 1);
    glBindTexture(GL_TEXTURE_2D, texture);
    glBegin(GL_POLYGON);
      glTexCoord2f(0, 0); glVertex3f(fx1, fy1, 0);
      glTexCoord2f(1, 0); glVertex3f(fx2, fy1, 0);
      glTexCoord2f(1, 1); glVertex3f(fx2, fy2, 0);
      glTexCoord2f(0, 1); glVertex3f(fx1, fy2, 0);
    glEnd();
  glPopMatrix;

A i tak nie działa. Gdzie leży błąd?

3

Jesteś bardzo blisko :)

Zauważ, że w obecnym kodzie w zasadzie przesuwasz obiekt dwa razy:

  1. Pierwszy raz za pomocą glTranslatef.
  2. Drugi raz przy rysowaniu (ponieważ nadal rysujesz go za pomocą fx/fy1/2, które są zależne od tego samego fCenterX/Y które używasz w pkt1).

Zazwyczaj robi się to tak (w pseudokodzie):
[code]
glPushMatrix();
glTranslatef(fCenterX, fCenterY, 0);
glRotatef(fAngle, 0, 0, 1);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_POLYGON);
glTexCoord2f(0, 0); glVertex3f(-szerokość / 2, -wysokość / 2, 0);
glTexCoord2f(1, 0); glVertex3f( szerokość / 2, -wysokość / 2, 0);
glTexCoord2f(1, 1); glVertex3f( szerokość / 2, wysokość / 2, 0);
glTexCoord2f(0, 1); glVertex3f(-szerokość / 2, wysokość / 2, 0);
glEnd();
glPopMatrix;
[/code]

Teraz obiekt będzie narysowany ze środkiem w 0,0, ale z uwagi na to, że glTranslate "przesunąłeś cały układ współrzędnych" (a tak naprawdę przemnożyłeś macierze transformacji, przez którą są mnożone wszyskie koordynaty, które wrzucasz w świat za pomocą glVertex3f lub podobnych funkcji), to obiekt pojawi się i tak przesunięty.

Na początku wydaje się to mało intuicyjne, ale szybko załapiesz jak tego używać :)

Cheers,

0

Ale mi dokładnie o to chodzi. Żeby przesunąć środek układu współrzędnych w pozycję fCenterX, fCenterY. A następnie obrócić go o kąt fAngle względem osi Z. No i tu jest problem bo obraca się względem osi Z ale starego układu (tego z przed przesunięcia).

Mój błąd nie doczytałem postu a zabrałem się za odpowiadanie.

Dzięki za wyjaśnienie ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1