OpenGL Rubiks Cube - вращение лица мышью - PullRequest
5 голосов
/ 27 октября 2011

Я работаю над своим первым настоящим проектом OpenGL. Это кубик Рубикса 3x3x3. Вот ссылка на простой скриншот того, что у меня есть ( мой кубик Рубика )

Вращение куба выполняется перетаскиванием мыши, удерживая правую кнопку мыши. Это работает на примере аркбола из NeHe Tutorials ( NeHe Arcball )

У меня есть класс singleCubes, который представляет один куб через 6 реальных квадов, хранящихся в списке отображения, который можно использовать в методе рисования. Класс ComplexCube имеет массив 3x3x3 singleCubes и используется в качестве интерфейса при взаимодействии с полным кубиком Rubiks.

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

Теперь моя проблема в том, что когда я вращаю кубик Рубика в любом направлении с помощью перетаскивания правой кнопкой мыши, он становится, например, вверх ногами. Поэтому, когда я нажимаю на сторону и хочу повернуть грань вправо, она идет в неправильном направлении, потому что я не могу отслеживать, перевернут ли куб или что-то еще. Из-за использования вращения дуги у меня нет угла поворота x или y, который я мог бы использовать, чтобы определить это.

Вопрос 1: Как я могу отслеживать или позже получать информацию, если куб перевернут, наклонен и т. Д., Чтобы перевести информацию о перетаскивании мышью (при вращении одного лица) при использовании дуги пример, связанный выше?

// In render function
glPushMatrix();
{
    glMultMatrixf(Transform.M); // Rotation applied by arcball object
    complCube.draw();           // Draw all the cubes using display lists
}
glPopMatrix();

Установка: C ++ с Microsoft Visual Studio 2008, GLEW, freeglut

Ответы [ 2 ]

4 голосов
/ 27 октября 2011

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

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

Example of the vectors used in the explanation

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

Изменить, чтобы ответить на вопрос более подробно

Итак, продолжая объяснение, я будуприведите пример того, как это вам поможет.Давайте сначала предположим, что ваш экран имеет размер 800x800 пикселей, а кубик Рубика всегда центрирован.Теперь давайте также предположим, что, согласно вашим чертежам в комментариях, мы находимся в случае слева.

Мы перетаскиваем мышь и получаем две позиции, которые с помощью gluUnProject преобразуются в мировые координаты (числа быливыбранный, чтобы показать мою точку зрения, а не каким-либо расчетом):

p1 : (600, 600) -> (1, -0.5, 0)
p2 : (630, 605) -> (1.3, -0.505, 0)

Теперь мы получаем вектор разности: p2 - p1 = v = (0,3, -0,05, 0).Причина, по которой я говорил «проецировать на три оси», заключается в том, что вы извлекаете свое основное движение (которое в данном случае составляет 0,3 по оси x) (поскольку куб Рубика не может вращаться вдоль диагоналей).Чтобы выполнить «проекцию», вам просто нужно взять оси x, y, z по отдельности и создать из них векторы, чтобы получить:

v1 = (0.3, 0, 0)
v2 = (0, -0.05, 0)
v3 = (0, 0, 0)

Теперь возьмите величины и отбросьте наименьшие векторы, так чтомы остались с вектором v1 = (0.3, 0, 0).Это ваш вектор движения в мировом пространстве.Теперь вы берете перекрестное произведение этого вектора с вектором нормали выбранной грани (который в этом случае будет (0, 0, 1)).Это дает вам вектор, который указывает вниз (0, 1, 0) (после нормализации) (на этом этапе вам, вероятно, также придется извлечь только самый большой компонент (0.02, 1.2, 0.8) -> (0, 1, 0)в противном случае вы получите странные повороты, если ваша камера не будет направлена ​​прямо вдоль главных осей).Теперь вы можете использовать этот вектор в качестве оси вращения и использовать 0,3 в качестве величины вращения (если он вращается в направлении, противоположном ожидаемому, просто введите -).

Теперь, как это поможет, если ваш кубСверху вниз?Предположим, мы нажимаем на экран таким же образом.Теперь мы получаем:

p1 : (600, 600) -> (-1, 0.5, 0)
p2 : (630, 605) -> (-1.3, 0.505, 0)

Видите разницу в мировых координатах?Они перевернуты!Поэтому, когда вы берете вектор разности p2 - p1 = v = (-0,3, 0,05, 0).Извлечение вектора наибольшего компонента дает (-0,3, 0, 0).Выполнение перекрестного произведения еще раз дает вам ось вращения, но теперь вращение происходит в противоположном направлении, что вам и нужно.

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

0 голосов
/ 27 октября 2011

Как и большинство из нас, вы столкнетесь со знаменитой проблемой, называемой Gimbal Lock.

см .: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=208925

Эта проблема чрезвычайно хорошо задокументирована, поэтому мне не стоит вдаваться в подробности. Я уверен, что вы найдете массу информации об этом.

...