2014-11-26 5 views
0

Не был уверен, стоит ли размещать это здесь или в GameDev, но поскольку это не игра, я решил спросить здесь.Перевод и ротация OpenGL ES

Я пытаюсь использовать OpenGL ES 2 на Android, и сейчас у меня простая настройка. Я загружаю объект из файла .obj, отображаю его на экране, затем могу поворачивать камеру вокруг объекта, используя сенсорные элементы управления. Мой viewMatrix настроен так:

double[] dist = {DISTANCE * Math.sin(yawAngle) * Math.abs(Math.cos(pitchRollAngle)), 
     DISTANCE * Math.sin(pitchRollAngle), 
     DISTANCE * Math.cos(yawAngle) * Math.abs(Math.cos(pitchRollAngle))}; 

Matrix.setLookAtM(viewMatrix, 0, (float) dist[0], (float) dist[1], (float) dist[2], 0f, 0f, 0f, 0f, 1.0f, 0.0f); 

И моя проекция матрица просто так:

Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 100); 

Я поставил рыскания/угол pitchRoll от событий прикосновения. Теперь это работает нормально, когда объект находится в центре экрана, я могу вращаться, как я должен. Но если я пытаюсь переместить объект, скажем, 1 единицу по оси X, как это:

float[] modelMatrix = new float[16]; 
Matrix.setIdentityM(modelMatrix, 0); 
Matrix.translateM(modelMatrix, 0, 1, 0, 0); 

И затем умножьте все из них, как это:

float[] MVPMatrix = new float[16]; 
Matrix.multiplyMM(MVPMatrix, 0, modelMatrix, 0, viewMatrix, 0); 
Matrix.multiplyMM(MVPMatrix, 0, projectionMatrix, 0, MVPMatrix, 0); 

объект вращается вокруг на своем месте , но я хочу, чтобы он вращался вокруг точки (0, 0, 0). Что я делаю не так?

ответ

1

Это один из наиболее общих вопросов о матричном умножении. В вашем случае вам нужно сначала повернуть объект, а затем перевести его. Поэтому, если вы сначала переведёте на X и затем повернете, объект появится в позиции X, но повернется вокруг собственной оси. Если вы сначала повернете, а затем переведете на X, объект не появится в X, а в точке, полученной при вращении самого X. Это ожидаемый результат и как это работает.

Итак, чтобы понять, что происходит: матрица фактически состоит из трех базовых векторов и центра. При идентичности базовыми векторами являются (1,0,0), (0,1,0), (0,0,1), (0,0,0). Теперь при умножении этой матрицы на некоторое преобразование базовые векторы фактически преобразуются. Это приводит к тому, что матрица содержит свою собственную систему координат, в которой преобразования кажутся «логическими». Это приводит к тому, что матрица вращения никогда не изменит центр объекта.

Я знаю, что это слишком сложно, но на самом деле очень легко представить себе эффект: Возьмите его так, как если бы матричное умножение было фактически командами персонажа, смотрящего с первого взгляда.Поэтому, когда вы говорите «идти вперед» (переводить), вы делаете шаг вперед, теперь «поворачиваетесь на 90 градусов», и вы поворачиваетесь на 90 градусов и все еще находитесь в одном месте, теперь «идите вперед», вы делаете еще один шаг вперед, но это фактически не в том же направлении, как это было в начале ...

Итак, что вы делаете, вы говорите «вперед вперед на 1», теперь поверните ANGLE градусов. Это приводит к тому, что объект хранится в одном месте и вращается вокруг собственной оси. И что вы должны сделать, это сказать «поверните на свою цель» (поверните на ANGLE) сейчас «вперед вперед на 1» и, возможно, даже «поверните назад на -ANGLE», чтобы вы оказались в том же направлении, что и в начале.

Надеюсь, это объяснение вам поможет.

+0

Хорошее объяснение @Matic, кажется логичным сейчас, когда я думаю об этом! Меня беспокоит одно, но сейчас все хорошо и хорошо, так как моя камера вращается вокруг объекта. Но что произойдет, если я захочу переместить камеру с помощью метода lookAt? Тогда матрица вида будет иметь в себе как поворот, так и перевод? Как бы я правильно его умножить? Или я должен создать другую матрицу с переводом для камеры и работать оттуда, чтобы матрица вида только когда-либо содержала поворот? Или я должен избегать метода lookAt и просто делать все вручную? – Squeazer

+0

Я считаю, что лучше всего отслеживать 3 матрицы, один из которых содержит проекцию (усеченный или такой), один для камеры (посмотрите) и модельную матрицу. Затем просто умножьте эти 3 каждого кадра. Проецирование обычно является постоянным, за исключением случаев, когда изменяется окно просмотра, камера меняется обычно один раз за кадр max и матрица модели изменяется для каждой модели. LookAt очень полезно, вы должны использовать его, если это возможно. Что касается вашего вращающегося объекта, лучше всего, чтобы сам объект удерживал местоположение и вращение и восстанавливал матрицу, используя эти 2 значения. Поэтому в вашем случае вы будете менять место жительства. –

1

Я помню, что у меня была аналогичная проблема в Delphi 2010, когда мне приходилось использовать OpenGL. Трюк состоял в том, чтобы вернуть объект в положение < 0, 0, 0>, применить поворот, а затем поместить его обратно в исходное положение перед рисованием рамки. Я не могу вспомнить, как я это сделал, и у меня нет доступа к этому коду, поскольку он принадлежал моему предыдущему работодателю, но это то, что я помню.

+0

Я не уверен, что это сработало бы, если бы я перевел объект с '(0, 0, 0)' на '(1, 0, 0)' и повернул его на 180 ° вокруг оси Y I ' d хотите, чтобы он находился на '(-1, 0, 0)'. Или это ожидаемый результат с вашим методом? – Squeazer

+0

Получил! Ваш ответ помог, я просто переключил модель и матрицу просмотра, то есть порядок, в котором они умножаются (до того, как матрица модели была умножена на матрицу вида, и теперь это наоборот). – Squeazer

+0

Нет проблем, и рад, что вы это поняли. – Zubaja

0

Проблема была в этой строке:

Matrix.multiplyMM(MVPMatrix, 0, modelMatrix, 0, viewMatrix, 0); 

Я просто включил модель и вид матрицы таким образом, чтобы они умножаются наоборот, и это работает! Например:

Matrix.multiplyMM(MVPMatrix, 0, viewMatrix, 0, modelMatrix, 0); 

Спасибо @Zubaja за то, что указали мне в правильном направлении!

+0

Это может работать для вашего дела, потому что у вас всего 2 операции, но, как правило, это очень плохая идея. –

Смежные вопросы