OpenGL:scale然后翻译?如何?

时间:2010-02-13 20:24:45

标签: opengl graphics transform

我有一些2D几何体。我想在我的几何体周围采用一些边界矩形,然后在平面上的其他地方渲染一个较小的版本。这里或多或少是我必须进行缩放和翻译的代码:

// 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为零完全不同。

有人能指出一些我不知道的明显事物吗?

谢谢!

最终更新根据以下巴巴和马库斯的答案,我做了一些实验并解决了这个问题。亚当鲍文的评论是提示。我错过了两个重要的事实:

  1. 我需要围绕我关心的几何体的中心进行缩放。
  2. 我需要以直觉的相反顺序应用变换(对我而言)。
  3. 回想起来,第一种是显而易见的。但是对于后者,对于像我这样的其他优秀程序员/坏数学家:原来我的直觉是在Red Book所谓的“大,固定坐标系”中运行,其中有一个绝对平面和几何使用变换在该平面上移动。这是可以的,但考虑到将多个变换堆叠成一个矩阵背后的数学性质,它与事物真正起作用的方式相反(参见下面的答案或更多的红皮书)。基本上,变换以“相反的顺序”“应用”它们在代码中的出现方式。这是最终的工作解决方案:

    // 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.
    

3 个答案:

答案 0 :(得分:18)

在OpenGL中,您指定的矩阵乘以现有矩阵的右侧,顶点位于表达式的最右侧。

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

Bahbar强调您需要考虑缩放的中心点。 (或旋转的枢轴点。)通常你在那里翻译,旋转/缩放,然后翻译回来。 (或者一般来说,应用基础变换,操作,然后反过来)。这称为Change of Basis,您可能需要阅读它。

无论如何,为了获得一些关于它是如何工作的直觉,尝试使用一些简单的值(零等)然后稍微改变它们(可能是一个动画)并看看输出会发生什么。然后,您可以更轻松地查看转换对您的几何体实际执行的操作。

<强>更新

该命令被“逆转”w.r.t.直觉在初学者OpenGL编码器中相当普遍。我一直在辅导计算机图形学课程,许多人以类似的方式做出反应。如果在渲染变换和几何的树(场景图)时考虑使用pushmatrix / popmatrix,则更容易思考OpenGL如何做到这一点。然后,当前的事物顺序变得相当自然,相反的情况会使得完成任何有用的事情变得相当困难。

答案 1 :(得分:6)

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

这就是你通常首先应用Scale的原因(因为对象往往定义在0左右)。

因此,如果要围绕点中心缩放对象,可以将对象从中心转换为原点,在那里缩放,然后转换回来。

旁注,如果您先翻译,然后进行缩放,那么您的比例将应用于之前的翻译,这就是您可能遇到此方法问题的原因。

答案 2 :(得分:1)

我没有使用OpenGL ES,只是使用OpenGL。

听起来你想从不同的位置转换而不是原点,不确定,但是你可以尝试进行转换并在glPushMatrix() and glPopMatrix()内绘制那个位吗?

e.g.

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

glPushMatrix();
  glScalef(scaleX, scaleY, 0.0);
  glTranslatef(translateX, translateY, 0.0);
  // Draw geometry in question with its normal verts.
  //as if it were drawn from 0,0
glPopMatrix();

这是一个简单的处理草图,我写的是为了说明这一点:

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

这是草图运行的图像,绘制了相同的绿色三角形,应用了平移和缩放,然后是红色的三角形,超出了推/弹'块',因此它不受变换的影响:

alt text

HTH, 乔治