Подтвердить что ты не робот

OpenGL: масштабировать, а затем переводить? и как?

У меня есть 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 были равны нулю.

Может ли кто-нибудь указать что-то очевидное, я не хватает?

Спасибо!

ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ В ответах ниже на 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.
4b9b3361

Ответ 1

В OpenGL указанные вами макросы умножаются справа от существующей матрицы, а вершина находится в крайнем правом углу выражения.

Таким образом, указанная последняя операция находится в системе координат самой геометрии. (Первым обычно является преобразование вида, т.е. Обратное преобразование камеры в мир.)

Bahbar делает хороший вывод, что вам нужно рассмотреть центр для масштабирования. (или точкой поворота для поворота.) Обычно вы переводите туда, вращайте/масштабируйте, а затем переводите назад. (или, вообще говоря, применить базисное преобразование, операцию, затем обратную). Это называется Изменение основы, которое вы, возможно, захотите прочитать.

В любом случае, чтобы получить некоторую интуицию о том, как это работает, попробуйте с некоторыми простыми значениями (ноль и т.д.), затем немного измените их (возможно, анимацию) и посмотрите, что происходит с выходом. Тогда гораздо легче увидеть, что ваши преобразования на самом деле делают с вашей геометрией.

Обновление

Чтобы порядок был "отменен" w.r.t. интуиция довольно распространена среди начинающих OpenGL-кодеров. Я преподавал курс компьютерной графики, и многие реагируют аналогичным образом. Легче думать о том, как это работает OpenGL, если вы считаете использование pushmatrix/popmatrix при рендеринге дерева (сцены-графика) преобразований и геометрий. Тогда текущий порядок вещей становится довольно естественным, и наоборот, было бы довольно сложно сделать что-нибудь полезное.

Ответ 2

Масштаб, как и Rotate, работает от начала координат. поэтому, если вы масштабируете половину объекта, который охватывает сегмент [10:20] (например, на оси X), вы получаете [5:10]. Поэтому объект был масштабирован и приближен к началу координат. Именно то, что вы наблюдали.

Вот почему вы сначала применяете масштаб в целом (потому что объекты, как правило, определяются вокруг 0).

Итак, если вы хотите масштабировать объект вокруг центра точек, вы можете перевести объект из центра в начало, масштабировать его и перевести назад.

Обратите внимание: если вы сначала переводите, а затем масштабируете, то ваш масштаб применяется к предыдущему переводу, поэтому у вас, вероятно, были проблемы с этим методом.

Ответ 3

Я не играл с OpenGL ES, просто с OpenGL.

Похоже, вы хотите преобразовать из другой позиции в противоположность исходному, но не уверен, но можете ли вы попытаться сделать преобразования и нарисовать этот бит в glPushMatrix() и 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();
}

Вот изображение запущенного эскиза, нарисован тот же самый зеленый треугольник, приложенный трансляцией и шкалой, затем красный, отключает блок push/pop ', поэтому на него не влияет преобразование:

alt text

НТН, Джордж