在opengl中寻找旋转图像的中心

Finding center of image for rotation in opengl

本文关键字:图像 寻找 opengl 旋转      更新时间:2023-10-16

所以我有这段代码,它几乎在屏幕上绘制了各种2D纹理,尽管有多个精灵必须从纹理(精灵表)中"解剖"出来。问题是旋转不能正常工作;当它旋转时,它不会在纹理的中心旋转,这就是我要做的。我已经把范围缩小到翻译错误:

    glTranslatef(x + sr->x/2 - sr->w/2,
                 y + sr->y/2 - sr->h/2,0);
    glRotatef(ang,0,0,1.f);
    glTranslatef(-x + -sr->x/2 - -sr->w/2,
                 -y + -sr->y/2 - -sr->h/2,0);

X和Y是它被绘制到的位置,薄片矩形结构包含从纹理绘制的精灵的X和Y位置,以及w和h,这是来自纹理的"精灵"的宽度和高度。我试过各种其他的公式,比如:

 glTranslatef(x, y, 0);
 The below three switching the negative sign to positive (x - y to x + y)
 glTranslatef(sr->x/2 - sr->w/2, sr->y/2 - sr->h/2 0 );
 glTranslatef(sr->x - sr->w/2, sr->y - sr->h/2, 0 );
 glTranslatef(sr->x - sr->w, sr->y - sr->w, 0 );
 glTranslatef(.5,.5,0);

这样说可能也会有帮助:

glOrtho(0,screen_width,screen_height,0,-2,10);

正在使用

我试过阅读各种教程,通过各种论坛,问不同的人,但似乎没有一个解决方案,我也找不到任何有用的资源,向我解释我如何找到图像的中心,以便将其翻译为'(0,0)'。我对OpenGL很陌生,所以很多东西需要一段时间来消化。

下面是整个函数:

void Apply_Surface( float x, float y, Sheet_Container* source, Sheet_Rect* sr , float ang = 0, bool flipx = 0, bool flipy = 0, int e_x = -1, int e_y = -1 ) {
 float imgwi,imghi;
 glLoadIdentity();
 glEnable(GL_TEXTURE_2D);
 glBindTexture(GL_TEXTURE_2D,source->rt());     
 // rotation
 imghi = source->rh();
 imgwi = source->rw();
 Sheet_Rect t_shtrct(0,0,imgwi,imghi);
 if ( sr == NULL ) // in case a sheet rect is not provided, assume it's width
                   //and height of texture with 0/0 x/y
    sr = &t_shtrct;
 glPushMatrix();
     // 
     int wid, hei;
     glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&wid);
     glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&hei);
     glTranslatef(-sr->x + -sr->w,
                 -sr->y + -sr->h,0);
     glRotatef(ang,0,0,1.f);
     glTranslatef(sr->x + sr->w,
                 sr->y + sr->h,0);
     // Yeah, out-dated way of drawing to the screen but it works for now.
     GLfloat tex[] = {
        (sr->x+sr->w * flipx) /imgwi, 1 - (sr->y+sr->h  *!flipy )/imghi,
        (sr->x+sr->w * flipx) /imgwi, 1 - (sr->y+sr->h  * flipy)/imghi,
        (sr->x+sr->w * !flipx) /imgwi, 1 - (sr->y+sr->h * flipy)/imghi,
        (sr->x+sr->w * !flipx) /imgwi, 1 - (sr->y+sr->h *!flipy)/imghi
     };
     GLfloat vertices[] = { // vertices to put on screen
          x,        (y + sr->h),
          x,         y,
         (x +sr->w), y,
         (x +sr->w),(y +sr->h)
     };
     // index array
     GLubyte index[6] = { 0,1,2, 2,3,0 };
     float fx = (x/(float)screen_width)-(float)sr->w/2/(float)imgwi;
     float fy = (y/(float)screen_height)-(float)sr->h/2/(float)imghi;
     // activate arrays
     glEnableClientState(GL_VERTEX_ARRAY);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     // pass verteices and texture information
     glVertexPointer(2, GL_FLOAT, 0, vertices);
     glTexCoordPointer(2, GL_FLOAT, 0, tex);
     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, index);
     glDisableClientState(GL_VERTEX_ARRAY);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 glPopMatrix();
 glDisable(GL_TEXTURE_2D);
}

表容器类:

class Sheet_Container {
    GLuint texture;
    int width, height;
public:
    Sheet_Container();
    Sheet_Container(GLuint, int = -1,int = -1);
    void Load(GLuint,int = -1,int = -1);
    float rw();
    float rh();
    GLuint rt();
};

Sheet rect class:

struct Sheet_Rect {
    float x, y, w, h;
    Sheet_Rect();
    Sheet_Rect(int xx,int yy,int ww,int hh);
};

图片加载功能:

Sheet_Container Game_Info::Load_Image(const char* fil) {
    ILuint t_id;
    ilGenImages(1, &t_id);
    ilBindImage(t_id);
    ilLoadImage(const_cast<char*>(fil));
    int width = ilGetInteger(IL_IMAGE_WIDTH), height = ilGetInteger(IL_IMAGE_HEIGHT);
    return Sheet_Container(ilutGLLoadImage(const_cast<char*>(fil)),width,height);
}

你的四边形(两个三角形)居中于:

( x + sr->w / 2,  y + sr->h / 2 )

你需要将该点移动到原点,旋转,然后再移动回来:

 glTranslatef ( (x + sr->w / 2.0f),  (y + sr->h / 2.0f), 0.0f); // 3rd
 glRotatef    (0,0,0,1.f);                                      // 2nd
 glTranslatef (-(x + sr->w / 2.0f), -(y + sr->h / 2.0f), 0.0f); // 1st

这就是我认为你出错的地方。人们自然地认为OpenGL按照它们出现的顺序(从上到下)应用转换,但事实并非如此。OpenGL每次将两个矩阵相乘时都有效地交换操作数:

M1 x M2 x M3
~~~~~~~
  (1)
  ~~~~~~~~~~
      (2)
(1) M2 * M1
(2) M3 * (M2 * M1)   -->   M3 * M2 * M1  (row-major / textbook math notation)

这个技术术语是后乘法,这一切都与矩阵在OpenGL(列为主)中实现的方式有关。可以这么说,您通常应该从下到上阅读glTranslatef, glRotatef, glScalef等呼叫。

这样,你当前的旋转就没有任何意义了。

你告诉GL旋转0度围绕一个轴:<0,0,1>(换句话说就是z轴)。轴是正确的,但是0度旋转不会做任何事情;)