我有一些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为零完全不同。
有人能指出一些我不知道的明显事物吗?
谢谢!
最终更新根据以下巴巴和马库斯的答案,我做了一些实验并解决了这个问题。亚当鲍文的评论是提示。我错过了两个重要的事实:
回想起来,第一种是显而易见的。但是对于后者,对于像我这样的其他优秀程序员/坏数学家:原来我的直觉是在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.
答案 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();
}
这是草图运行的图像,绘制了相同的绿色三角形,应用了平移和缩放,然后是红色的三角形,超出了推/弹'块',因此它不受变换的影响:
HTH, 乔治