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 ниже, я сделал еще некоторое экспериментирование и решил это. Комментарий Adam Bowen был подсказкой прочь. Я пропускал два критических факта:

  1. Я должен был масштабироваться вокруг центра геометрии, о которой я заботился.
  2. Я должен был применить преобразования в противоположном порядке интуиции (для меня).

Первое довольно очевидно ретроспективно. Но для последнего, для других хороших программистов / плохих математиков как я: Оказывается, что моя интуиция работала, в каком Красная книга называет "Главную, Фиксированную Систему координат", в котором существует абсолютная плоскость, и Ваша геометрия перемещается на том плоском использовании, преобразовывает. Это в порядке, но, учитывая природу математики позади укладки нескольких преобразований в одну матрицу, это - противоположность того, как вещи действительно работают (см. ответы ниже или Красную книгу для больше). В основном преобразования "применяются" в "обратном порядке" к тому, как они появляются в коде. Вот заключительное рабочее решение:

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

23
задан genpfault 18 June 2010 в 15:03
поделиться

3 ответа

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

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

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

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

Обновление

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

18
ответ дан 29 November 2019 в 02:48
поделиться

Я не играл с 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();
}

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

alt text

HTH, Джордж

1
ответ дан 29 November 2019 в 02:48
поделиться

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

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

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

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

6
ответ дан 29 November 2019 в 02:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: