Здрассьте, господа кодеры. Итак, дано: отрезок [P0; P1]; координаты точки P0 == (0, 0, 0); позиция точки P1 задана углами поворота этой точки α, β и γ вокруг осей x, y и z соответственно, а также длинной L данного отрезка. Требуется: формула, по которой можно будет найти координаты точки P1. Вот с такой-вот задачкой я столкнулся, когда примитивный способ перемещения по 3D-миру игры, которую я пишу (при котором, по нажатию клавиши, точка обзора сдвигалась лишь параллельно одной из координатных осей, а две другие координаты не менялись), перестал меня удовлетворять. Найденные координаты точки P1 должны являться величинами, на которые следует сдвинуть точку обзора перед показом следующего кадра. Тогда точка обзора будет двигаться не параллельно координатным осям, а в направлении центра обзора. Я попытался решить эту задачу самостоятельно, но, так как в тригонометрии я не силён, получилось так, что при одних значениях углов всё работает правильно, а при других точка обзора движется в неверном направлении. Быстродействие формулы приветствуется. Если в формуле присутствуют элементы высшей математики (например производятся действия с матрицами) – прошу свести формулу к элементам алгебры и геометрии, которые преподают в средних школах (в.т.ч. в 10-11 классах).
Три угла не нужно - два угла и длина отрезка однозначно определяют точку на сфере. x = L * sin(a) * cos(b); y = L * sin(a) * sin(b); z = L * cos(a); a - угол поворота, в плосокости перпендикулярной xy b - угол поворота, в плоскости xy Учите матчасть http://ru.wikipedia.org/wiki/Сфера
Код (Text): void HandleControls() { double PI = 3.14f; static long xCurPosOld = 0, yCurPosOld = 0; float Speed = (KeysState[VK_SHIFT])?1.06f:0.03f; POINT Point; GetCursorPos(&Point); VertAngle += (yCurPosOld-Point.y)*0.09f; HorizAngle -= (xCurPosOld-Point.x)*0.09f; if(VertAngle < -45.0) VertAngle = -45.0; if(VertAngle > 90.0) VertAngle = 90.0; if(HorizAngle < 0.0) HorizAngle = 359.0; if(HorizAngle > 359.0) HorizAngle = 0.0; if( GetAsyncKeyState(VK_RIGHT) < 0) { CameraZ -= (float)sin((HorizAngle/180)*PI) * Speed; CameraX -= (float)cos((HorizAngle/180)*PI) * Speed; } if( GetAsyncKeyState(VK_LEFT) < 0) { CameraZ += (float)sin((HorizAngle/180)*PI) * Speed; CameraX += (float)cos((HorizAngle/180)*PI) * Speed; } if( GetAsyncKeyState(VK_UP) < 0 ) { CameraZ += (float)sin(((HorizAngle+90)/180)*PI) * Speed; CameraX += (float)cos(((HorizAngle+90)/180)*PI) * Speed; } if( GetAsyncKeyState(VK_DOWN) < 0 ) { CameraZ += (float)sin(((HorizAngle-90)/180)*PI) * Speed; CameraX += (float)cos(((HorizAngle-90)/180)*PI) * Speed; } if(Point.x==Width-1) { Point.x = 1; SetCursorPos(Point.x,Point.y); } if(Point.y==Height-1) { Point.y = 1; SetCursorPos(Point.x,Point.y); } if(Point.x==0) { Point.x = Width; SetCursorPos(Point.x,Point.y); } if(Point.y==0) { Point.y = Height; SetCursorPos(Point.x,Point.y); } xCurPosOld = Point.x; yCurPosOld = Point.y; }
А мне кажется, что лучше все-таки разобраться с матричными преобразованиями. Ведь сами матричные операции (сложение и умножение) достаточно просты, вполне доступны ученикам 10-11 классов. Когда дело перестанет ограничиваться парой точек и однократным поворотом, с тригонометрией все будет только сложнее, формулы будут разрастаться как плесень, тогда как в матричном виде ВСЕГДА ЛЮБУЮ сложную последовательность перемещений/вращений можно осуществить умножением всего лишь на ОДНУ матрицу 4х4. http://ru.wikipedia.org/wiki/%D0%A3%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BC%D0%B0%D1%82%D1%80%D0%B8%D1%86 http://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%82%D1%80%D0%B8%D1%86%D0%B0_%D0%BF%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D1%82%D0%B0 Немного поднапрячься вначале, зато потом любые движения в 3D будут элементарно понятны, а если воспользоваться однородными координатами - то вообще песня.
Dmitry_Milk: Коллеги! Пожалуйста, не поймите меня не правильно - я далеко не нуб! Я нуждался только в формуле, а тут уже готовый код предоставили, да ещё и с обработкой мышиного и клавиатурного ввода! Подробнее отпишусь позже.
А, ну приношу извинения. Надеюсь, что вы понимаете, что такое некоммутативность поворотов в трехмерном пространстве и не наступите на грабли. Желаю удачи.
Прошу извинить меня за столь долгое отсутствие. dinoweb: dinoweb: если смотреть исходные данные задачи, то под это описание подходят 2 угла – α (лежащий в плоскости yz) и β (лежащий в плоскости xz). Тем не менее, я думаю, что ты имел ввиду другой угол, который отсутствует в исходных данных. Прочти ещё раз внимательно то, что дано: . Я составил код на основе выделенного зелёным (если хочешь, могу запостить его с подробными комментариями), но он работает не корректно. rmn: я чистокровный, так сказать, Asm-кодер, но, тем не менее, C я практически не знаю %) . Но всё равно – спасибо за выложенный код ) . Dmitry_Milk: Dmitry_Milk, в таком случае создаётся процедура, выполняющая 1 относительно мелкую операцию (например, поворот всех точек объекта вокруг осей x, y и z (при желании можно и в другом порядке, так как порядок поворотов влияет на результат) (пока координаты центра объекта = (0,0,0)) и последующее перемещение всех точек объекта в нужное местоположение). В дальнейшем, достаточно будет вызвать эту процедуру, набрав всего 1 достаточно короткую строку кода. Если использование такой матрицы, которая содержит большую комбинацию перемещений/поворотов, будет более резонным с точки зрения быстродействия, чем каждый раз совершать все операции “с нуля”, то такую матрицу всегда можно получить средствами графической библиотеки и сохранить её в памяти, как вещественный массив 4x4. А вот имеет ли OpenGL собственные средства, с помощью которых можно было бы извлечь из данных видовой матрицы текущие координаты точки обзора – этого я не знаю (кстати, если кто-нибудь из вас такие средства знает – просьба меня в этом просветить). IMO, здесь не за что извиняться ) . В общем, хотелось бы получить корректные тригонометрические формулы для вычисления координат. Работать с матрицами «вручную” (не используя для их создания и модификации OpenGL) я пока, всё же, не буду, но если в дальнейшем я почувствую, что это действительно необходимо, то задам дополнительные вопросы в этой теме.
Три декартовы координаты смещения точки обзора относительно точки отсчета в такой матрице всегда располагаются в 4-м столбце, если матрица нормирована (то есть, если в 4-й строке в 4-м столбце стоит 1). А вот с ориентацией направления взора и ориентацией наблюдателя вокруг этого направления - явных средств, чтоб достать это, в OpenGL нет. Надо помнить, что с матрицей 4х4 может не быть однозначности, поскольку она в общем случае может косоугольно искажать пространство (хотя, если все преобразования являются только поворотами, смещениями и масштабированиями, то косоугольных искажений быть не должно). Теоретически из подматрицы 3х3 этой матрицы, соответствующей именно ориентации, можно вывести обратное получение синусов и косинусов трех последовательных поворотов в предзаданном порядке (если матрица не создает косоугольных искажений). На первый взгляд задача "найти углы трех поворотов в предзаданном порядке такие, которые приводят к точно такой же ориентации направления взора и наблюдателя вокруг направления взора, как и произвольная последовательность различных поворотов" всегда должна иметь однозначное решение. Вот только надо ли ее решать? Мне почему-то кажется, что проще так и хранить матрицу, чем после каждого произвольного поворота решать обратную задачу нахождения трех углов. Решать мне лень наверное можно найти готовое решение.
Я перечитал ваш первый пост и понял, что возможно погорячился. Вы ведь не собираетесь писать симулятор полетов, а пишете что-то более близкое к обычной 3Д-ходилке (то есть, ходилке по поверхности с гравитацией, с однозначно заданным направлением верх-низ). А в таких ходилках обычно специально нарушают некоммутативность, чтоб основной, первый угол поворота всегда находился в горизонтальной плоскости, а только потом - вертикальный угол подъема-опускания головы. То есть, задрав голову и совершая поворот влево/вправо, вы будете не заваливаться на бок (как должно быть при некоммутативности), а вращаться опять же в исходной гравитационно-горизонтальной плоскости. А угол заваливания/вращения вокруг оси взора вообще практически не используют. В таком случае действительно можно обойтись формулами, аналогичными приведенным dinoweb, а частные повороты суммировать отдельно, горизонтальные всегда в альфа, вертикальные - всегда в бета. Точнее формулы тогда вообще не нужны как таковые, поскльку в OpenGL есть готовые трансформации поворотов glRotate на заданый угол вокруг заданной оси.