OpenGL:缩放然后平移?怎么做?

OpenGL:缩放然后平移?怎么做?,opengl,graphics,transform,Opengl,Graphics,Transform,我有一些二维几何图形。我想在几何体周围使用一些边界矩形,然后在平面上的其他地方渲染它的较小版本。以下是我必须进行缩放和转换的代码: // source and dest are arbitrary rectangles. float scaleX = dest.width / source.width; float scaleY = dest.height / source.height; float translateX = dest.x - source.x; float translate

我有一些二维几何图形。我想在几何体周围使用一些边界矩形,然后在平面上的其他地方渲染它的较小版本。以下是我必须进行缩放和转换的代码:

// source and dest are arbitrary rectangles.
float scaleX = dest.width / source.width;
float scaleY = dest.height / source.height;
float translateX = dest.x - source.x;
float translateY = dest.y - source.y;

glScalef(scaleX, scaleY, 0.0);
glTranslatef(translateX, translateY, 0.0);
// Draw geometry in question with its normal verts.
当dest原点为0时,这与给定维度的预期效果完全相同。但是,如果x的原点是非零,结果仍然是正确的,但是看起来(?)它在轴上被转换成接近零的值-,结果表明它与dest.x为零的结果并不完全相同

有人能指出我遗漏了什么吗

谢谢

最终更新根据Bahbar和Marcus下面的回答,我做了更多的实验并解决了这个问题。亚当·伯恩的评论就是一条线索。我遗漏了两个关键事实:

  • 我需要围绕我关心的几何体的中心进行缩放
  • 我需要以与直觉相反的顺序应用转换(对我来说)
  • 首先,回顾过去,这是显而易见的。但对于后者,对于像我这样的优秀程序员/糟糕的数学家来说:事实证明我的直觉是在所谓的“大的、固定的坐标系”中运行的,在这个坐标系中有一个绝对平面,你的几何体通过变换在这个平面上移动。这是可以的,但考虑到将多个变换叠加到一个矩阵背后的数学本质,这与实际情况相反(更多信息,请参见下面的答案或红皮书)。基本上,转换是以“相反的顺序”应用于它们在代码中的显示方式。以下是最终的工作解决方案:

    // source and dest are arbitrary rectangles.
    float scaleX = dest.width / source.width;
    float scaleY = dest.height / source.height;
    Point sourceCenter = centerPointOfRect(source);
    Point destCenter = centerPointOfRect(dest);
    
    glTranslatef(destCenter.x, destCenter.y, 0.0);
    glScalef(scaleX, scaleY, 0.0);
    glTranslatef(sourceCenter.x * -1.0, sourceCenter.y * -1.0, 0.0);
    // Draw geometry in question with its normal verts.
    

    “缩放”与“旋转”一样,从原点开始操作。因此,如果将跨越段[10:20]的对象缩放一半(例如,在X轴上),则得到[5:10]。因此,对象被缩放,并移近原点。正是你观察到的

    这就是为什么通常首先应用“缩放”(因为对象往往在0左右定义)

    因此,如果要围绕点中心缩放对象,可以将对象从中心平移到原点,在那里缩放,然后向后平移


    旁注,如果先平移,然后缩放,则缩放将应用于上一次的平移,这就是您可能会遇到此方法问题的原因。

    在OpenGL中,您指定的矩阵将相乘到现有矩阵的右侧,并且顶点位于表达式的最右侧

    因此,您指定的最后一个操作在几何体本身的坐标系中。 (第一种通常是视图变换,即相机到世界变换的逆变换。)

    BaBar提出了一个很好的观点,你需要考虑缩放的中心点。(或旋转的轴心点。)通常在那里平移,旋转/缩放,然后向后平移。(或者通常,应用基础变换、运算,然后是逆运算)。这就是所谓的,你可能想读一读

    无论如何,为了获得一些关于它如何工作的直觉,尝试使用一些简单的值(零等),然后稍微改变它们(可能是动画),看看输出会发生什么。这样就更容易看到变换对几何体的实际作用

    更新


    在OpenGL初学者中,直觉的顺序是“颠倒的”。我一直在教一门计算机图形学课程,很多人的反应都类似。如果你考虑使用PuxMask/PopMatLs来渲染树(场景图)的变换和几何图形,那么OpenGL是如何变得更容易的。然后,当前的事情顺序变得相当自然,反之则会使做任何有用的事情变得相当困难。

    我没有玩过OpenGL ES,只玩过一点OpenGL

    听起来你想从与原点相反的不同位置变换,不确定,但你能尝试进行变换并在其中绘制该位吗

    下面是我为说明这一点而编写的一个简单的处理示意图:

    import processing.opengl.*;
    import javax.media.opengl.*;
    
    
    void setup() {
      size(500, 400, OPENGL);
    }
    
    void draw() {
      background(255);
      PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
      GL gl = pgl.beginGL();  
    
    
      gl.glPushMatrix();
        //transform the 'pivot'
        gl.glTranslatef(100,100,0);
        gl.glScalef(10,10,10);
        //draw something from the 'pivot'
        gl.glColor3f(0, 0.77, 0);
        drawTriangle(gl);
      gl.glPopMatrix();
      //matrix poped, we're back to orginin(0,0,0), continue as normal
      gl.glColor3f(0.77, 0, 0);
      drawTriangle(gl);
      pgl.endGL();
    }
    
    void drawTriangle(GL gl){
      gl.glBegin(GL.GL_TRIANGLES);
      gl.glVertex2i(10, 0);
      gl.glVertex2i(0, 20);
      gl.glVertex2i(20, 20);
      gl.glEnd();
    }
    
    这是草图运行的图像,绘制了相同的绿色三角形,应用了平移和缩放,然后是红色三角形,超出了推/弹出“块”,因此不受变换的影响:

    嗯,,
    乔治

    谢谢你的答复。你能为一个矩阵数学的傻瓜解释一下我会做什么操作,做适当的转换到原点,然后缩放,再转换回原点吗?在绘制几何体之前,我尝试在三次调用中依次叠加这三件事(按源原点的负数平移,然后按比例因子缩放,然后按目标原点平移),但没有得到明显的结果。啊,也许我需要相对于矩形的中心而不是原点进行平移。我会试试这个。不。无骰子:按源的负中心平移,然后缩放,然后按目标的正中心平移。简言之,将顺序更改为GLTRANSE(目标);glScale(量表);glTranslate(来源);亚当:这似乎不像你所说的那样有效,尽管我很好奇——你能详细解释一下为什么排序会是这样的吗?也许能提供一个更明确的想法,说明与现有代码相比,排序会是怎样的?也许我只是误解了你的伪代码。谢谢Nevermind:在本例中,“不起作用”是一个命中注定的值。修好之后,我们就开始做生意了。有关更多信息,请参阅更新的问题。谢谢谢谢George,但是推送/弹出并不是真正的问题;我已经在编写代码片段的代码之外进行了推/弹出操作。不过,感谢您用图片进行说明!很好的视觉效果。
    import processing.opengl.*;
    import javax.media.opengl.*;
    
    
    void setup() {
      size(500, 400, OPENGL);
    }
    
    void draw() {
      background(255);
      PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
      GL gl = pgl.beginGL();  
    
    
      gl.glPushMatrix();
        //transform the 'pivot'
        gl.glTranslatef(100,100,0);
        gl.glScalef(10,10,10);
        //draw something from the 'pivot'
        gl.glColor3f(0, 0.77, 0);
        drawTriangle(gl);
      gl.glPopMatrix();
      //matrix poped, we're back to orginin(0,0,0), continue as normal
      gl.glColor3f(0.77, 0, 0);
      drawTriangle(gl);
      pgl.endGL();
    }
    
    void drawTriangle(GL gl){
      gl.glBegin(GL.GL_TRIANGLES);
      gl.glVertex2i(10, 0);
      gl.glVertex2i(0, 20);
      gl.glVertex2i(20, 20);
      gl.glEnd();
    }