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

Posted

技术标签:

【中文标题】在opengl中找到旋转的图像中心【英文标题】:Finding center of image for rotation in opengl 【发布时间】:2014-05-23 02:15:47 【问题描述】:

所以我有这段代码,它几乎可以在屏幕上绘制各种 2D 纹理,尽管必须从纹理(spritesheet)中“剖析”多个精灵。问题是旋转不能正常工作;当它旋转时,它不会在纹理的中心旋转,这就是我想要做的。我已将其范围缩小到翻译不正确:

    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 是它被绘制到的位置,sheet rect 结构包含从纹理中绘制的精灵的位置 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();
;

表格矩形类:

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);

【问题讨论】:

您的描述与我有关:“它不会在纹理的中心旋转”相当模糊。我假设您正在绘制一个纹理映射的四边形,而您要旋转的是那个四边形?您使用的 GL 版本仍然支持纹理矩阵,因此您同样可能指代纹理坐标的旋转和平移(尽管在使用精灵表时这会产生一些奇怪的结果)。 是的,我正在使用 devIL 库的 ilLoadImage 函数加载图像。我相信这是一个四边形。基本上,draw 函数绑定了 GL_TEXTURE_2D 纹理,推送一个新矩阵,进行旋转,然后绘制到屏幕上。如有必要,我可以发布整个功能。但是,无论如何,我试图围绕精灵/图像本身的“中心”旋转它。目前,如果我不翻译它,它会在图像的左上角旋转。 好的,所以你想围绕它的中心旋转这个四边形。我认为您将不得不发布更多代码,我无法从您显示的内容中弄清楚您的四边形的尺寸。 我发布了更多代码;当显示多个时,四边形的尺寸会随着纹理的变化而变化。 在“整个函数”中,您有 0 度的旋转。这只是复制/粘贴错误吗? 【参考方案1】:

你的四边形(两个三角形)的中心是:

( 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 中实现矩阵的方式有关(以列为主)。可以这么说,您通常应该从下到上阅读glTranslatefglRotatefglScalef等调用。

除此之外,您当前的轮换没有任何意义。

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

【讨论】:

是的,0度旋转是偶然的,我只是把它放在那里是为了不旋转,因为我测试了一些其他的东西。没有注意到我将它复制/粘贴到那里。是的,我知道的后乘法。但是您发布的代码有效,非常感谢!我遇到的麻烦是如何找到中心,但我现在更好地掌握了如何去做。

以上是关于在opengl中找到旋转的图像中心的主要内容,如果未能解决你的问题,请参考以下文章

opengl旋转的对象不居中

如何在 OpenGL 中更改旋转中心

如何在 OpenGL 中围绕 Z 轴中心旋转对象?

OpenGL 旋转 2D 纹理

如何在openGL中旋转图像?

如何在opengl的3d空间中旋转单个形状?