Необходимо реализовать следующее: имеется выделеный объект в 3D который необходимо перемещать курсором вдоль определенной оси, причем чтобы объект был прикреплен к курсору.(Анология в 3DSMAX). я делаю следующее на OpenGL: Код (Text): glGetIntegerv(GL_VIEWPORT,@vp); glGetDoublev(GL_MODELVIEW_MATRIX,@VmMatrix); glGetDoublev(GL_PROJECTION_MATRIX,@PrMatrix); wx0:=wx; wy0:=wy; wz0:=wz; gluProject(wx0,wy0,wz0,@VmMatrix,@PrMatrix,@vp,w2x,w2y,w2z); gluUnProject(w2x+offX,w2y,w2z,@VmMatrix,@PrMatrix,@vp,wx1,wy1,wz1); vx:=wx0-wx1; vy:=wy0-wy1; vz:=wz0-wz1; wx:=wx+(abs(vx*vx+vy*vy+vz*vz)/(vx)); wx,wy,wz - первоночальная позиция объекта. OffX - смещение мышки. Как видно из примера, я беру позицию объекта проэктирую ее на экранные координаты, потом прибавляю смещение от мыши, узнаю вторую позицию, потом вычесляю по ним позицию для X. Как ни крыво выглядит, но работает, проблема в том что объект при больших сдвигах обгоняет курсор, а при малых отстает. Есть ли способ чтобы все было синхронно? (как это в 3DSMAX) Может все это можно сделать не используя gluProject, ручками?
В состоянии, только вот кде тут та прямая и где тут та плоскость, перспектива делает из прямой кривую, или нет?, если имеется в виду прямая - экранная Z. Я ж говрю туплю, где тут плоскость где прямая... запутался.
_DEN_ Нет там прямой. Перспектива она искажения криволинейные дает. AlexBond Код (Text): vx:=wx0-wx1; vy:=wy0-wy1; vz:=wz0-wz1; wx:=wx+(abs(vx*vx+vy*vy+vz*vz)/(vx)); Зачем, вроде просто Код (Text): wx:=wx0-wx1; wy:=wy0-wy1; wz:=wz0-wz1; Можно и ручками. Но там все равно будут тежи самые преобразования.
На рисунке в аттаче принцип нахождения положения объектов находящихся за и перед экраном. Соответсвенно, при перемещении объекта мышью в плоскости экрана действует "принцип рычага" т.е. реальное перемещение во столько же раз соотносится с перемещение его экранной проекции, во сколько раз расстояние от наблюдателя до объекта соотносится с расстоянием от наблюдателя до экрана (достаточно соотношения Z координат). Для заэкранных объектов реальное перемещение больше экранного, для передэкранных меньше. Не помню где я читал, что в ОГЛ положение наблюдателя относительно экрана жёстко фиксировано в середине экрана а расстояние по оси Z таково, что угол обзора экрана (голубая линия на рисунке) составляет 45° (только я не понял к чему это относятся к вертикали, горизонтали или диагонали экрана . И вроде как изменять это положение нельзя (только не путать положение камеры относительно экрана монитора с положением камеры относительно сцены, которое легко меняется).
Y_Mur Угол изменять можно задается при зодании перспективы параметр Fov выбирается любой, но обычно 45-60-90-120-150. Относится он к высоте экрана.
Pavia Замечательно ) А случаем не знаешь, менять можно только угол обзора или положение камеры тоже можно из центра экрана перенести? AlexBond Значит всё просто - через известный угол обзора определяешь z расстояние от экрана до камеры, затем через подобие прямоугольных треугольников образованных плоскостью экрана, нормалью к экрану проходящей через камеру и лучом камера-объект вычисляешь положение объекта через положение его проекции ) т.е. новые (заданные мышью) координаты (x,y) проекции объекта (относительно центра экрана в который попадает нормаль экран - камера), умножаешь на коэффициент равный отношению z расстояния от камеры до объекта к z расстоянию от камеры до экрана и получишь искомые 3D координаты x,y (они тоже будут относительно центра экрана), а z не изменяется, т.к. мышь ходит в плоскости экрана (x,y)
Да уж просто... Что есть центр экрана в 3D пространстве, это точка куда направлена камера? И что подразумевается под растоянием от камеры до экрана? (у меня камера динамическая) На счет прямой и плоскости, прямая то неопределена, она может быть определена только после нахождения точки, так что способ поиска точки пересеения прямой и плоскости отпадает Повторю данные: 1. Объект c позицией (wx,wy,wz). 2. Экранное смещение offX и offY. 3. Ось или плоскость вдоль которой производится смещение объекта. 4. Песпективная камера. Сложность: Визуальная синхронизация экранного смещения со смещением вдоль плоскости или оси.
AlexBond Я уже писал в #5, что динамическое положение камеры относительно сцены это не тоже самое, что положение камеры относительно экрана. Ты как бы ходишь по виртуальному пространству в виртуальном шлеме, где экран висит у тебя перед носом на заданном расстоянии (как его определить см. #8) и двигается экран относительно сцены вместе с твоей виртуальной головой (камерой). Помедитируй над картинкой в #5, пойми чем проекция отличается от объекта и всё получится ЗЫ: тебе нужно знать размер экрана как 3D объекта, тогда ты сможешь определить расстояние до него (#8), затем зная это расстояние и глядя рисунок в #5 поймёшь как зная координаты проекции найти 3D координаты объекта ЗЗЫ: текстовка у меня в #5, #8 несколько сумбурная, поскольку сабжем занимался давно и не в ОГЛе, но суть верная, вечером попробую сформульровать её получше.
Центр экрана это и есть центр экрана как плоского прямоугольника Но в ОГЛ это одновременно ещё и точка куда попадает перпендикуляр проведённый из камеры на плоскость экрана О'. В ОГЛ насколько я понимаю сместить камеру из центра экрана и смотреть на экран как бы сбоку просто нельзя (что не есть хорошо). Это как раз длина перпендикуляра от камеры к экрану. Например в реальном мире прислони к центру монитора торец линейки перпендикулярно к плоскости экрана и прислонись глазом к другому торцу линейки В виртуальном мире тебе нужно будет смоделировать тоже самое по отношению к камере и плоскости на которую проецируются 3D объекты ОГЛ делает за тебя большую работу не всегда поясняя как это происходит, но тем не менее понимать суть процесса нужно Из подобия треугольников АВО и АВ'О' следует, соотношение: АО'/АО = В'О'/ВО Где АО' - расстояние от камеры до экрана (измеряется по перпендикуляру к экрану, ось Z), АО - расстояние от камеры до объекта, В'О' - расстояние от центра экрана (точнее от точки куда попадает перпендикуляр к экрану АО' ) до проекции твоего объекта на экранную поверхность в 3Д мире (В'О' это как раз экранная координата X' или Y', в зависимости от того какую пару осей ты рассмотришь XZ или YZ), а ВО соответственно уже настоящая 3Д X или Y координата объекта. Алгоритм: зная (wx,wy,wz) и положение виртуального экрана в ОГЛ 3Д мире ты используя соотношение АО'/АО = В'О'/ВО находишь экранные координаты X', Y' (ОГЛ тоже это делает, но не делится с тобой результатами, а они тебе нужны в явном виде , к ним прибавляешь свои требуемые экранные смещения offX и offY (надеюсь я правильно понял что offX и offY как раз те расстояния на которые нужно переместить объект?), и делаешь обратное преобразование - по скорректированным X', Y' находишь новые X, Y (Z не потребует коррекции), помещаешь объект в эту точку, тогда ОГЛ отрисует его точнохонько там где тебе нужно ЗЫ: реализовать сабж без знания расстояния от камеры до плоскости экрана увы не удастся.
Не могли подсказать в моем случае как получается? координаты объекта: (wx,wy,wz) = (1,0,0); координаты мышки старые: x=705 y=323 новые: x=709 y=323 проекция: gluPerspective (90.0, 1.0, 0.5, 100.0); камера: gluLookAt(0.0,0.0,5.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
Приведу свою рабочую функцию, конечно убогая, но работает безотказно, может кому пригодится. Функция GetProjectVert(PTarget.X,PTarget.Y,MAxis,p); Которая по координатам мыши PTarget и заданой плоскости MAxis. Получает координаты в точку P. Суть простая, перед вызовом функции должна быть матрица положения объекта. Мы вычисляем координату центра матрицы объекта на экране. Из них находим треугольник паралельный экрану (он играет роль плоскости). Затем находим две точки p1, p2 максимума и минимума экранна по глубине. Ну и находим точку P пересечение отрезка (p1,p2) c плоскостью (pa,pb,pc) полученой в зависемости от нужной оси Axis. В итоге задав нужную ось, объект будет перемещаться мышью, прикрепленный к мыши, и двигающийся лишь вдоль заданой оси. Код (Text): function LineFacet(p1, p2: TXYZ; Axis: TAxis; var p: TXYZ; wd, wd0: TXYZ): Boolean; var d: Real; denom, mu, Length: Real; n, pa, pb, pc: TXYZ; begin Result := false; p.x := 0; p.y := 0; p.z := 0; pa.x := 0; pa.y := 0; pa.z := 0; case Axis of Axis_X: begin pb.x := 1; pb.y := 0; pb.z := 0; pc := wd; end; Axis_XY: begin pb.x := 1; pb.y := 0; pb.z := 0; pc.x := 0; pc.y := 1; pc.z := 0; end; Axis_Y: begin pb.x := 0; pb.y := 1; pb.z := 0; pc := wd; end; Axis_YZ: begin pb.x := 0; pb.y := 1; pb.z := 0; pc.x := 0; pc.y := 0; pc.z := 1; end; Axis_Z: begin pb.x := 0; pb.y := 0; pb.z := 1; pc := wd; end; Axis_XZ: begin pb.x := 1; pb.y := 0; pb.z := 0; pc.x := 0; pc.y := 0; pc.z := 1; end; Axis_XYZ: begin pb := wd; pc := wd0; end; end; n.x := (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y); n.y := (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z); n.z := (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x); Length := Sqrt(n.x * n.x + n.y * n.y + n.z * n.z); n.x := n.x / Length; n.y := n.y / Length; n.z := n.z / Length; d := -n.x * pa.x - n.y * pa.y - n.z * pa.z; denom := n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z); if (Abs(denom) < 1.0E-8) then Exit; mu := -(d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom; if (mu < 0) or (mu > 1) then Exit; p.x := p1.x + mu * (p2.x - p1.x); p.y := p1.y + mu * (p2.y - p1.y); p.z := p1.z + mu * (p2.z - p1.z); case Axis of Axis_X: begin p.y := 0; p.z := 0; end; Axis_Y: begin p.x := 0; p.z := 0; end; Axis_Z: begin p.y := 0; p.x := 0; end; end; Result := true; end; procedure GetProjectVert(X, Y: Real; axis: TAxis; var p: TXYZ); var p1, p2, wd, wd0, wd1: TXYZ; vp: TVector4i; PrMatrix, VmMatrix: TGLMatrixd4; begin glGetIntegerv(GL_VIEWPORT, @vp); glGetDoublev(GL_MODELVIEW_MATRIX, @VmMatrix); glGetDoublev(GL_PROJECTION_MATRIX, @PrMatrix); case axis of Axis_Y, Axis_X, Axis_Z, Axis_XYZ: begin wd.x := 0; wd.y := 0; wd.z := 0; gluProject(wd.x, wd.y, wd.z, VmMatrix, PrMatrix, vp, @wd.x, @wd.y, @wd.z); gluUnProject(wd.x, wd.y + 10, wd.z, VmMatrix, PrMatrix, vp, @wd0.x, @wd0.y, @wd0.z); gluUnProject(wd.x + 10, wd.y, wd.z, VmMatrix, PrMatrix, vp, @wd1.x, @wd1.y, @wd1.z); if axis = Axis_XYZ then wd := wd0 else begin wd.x := (wd0.x + wd1.x) / 2; wd.y := (wd0.y + wd1.y) / 2; wd.z := (wd0.z + wd1.z) / 2; end; end; end; gluUnProject(X, Y, 0, VmMatrix, PrMatrix, vp, @p1.x, @p1.y, @p1.z); gluUnProject(X, Y, 1, VmMatrix, PrMatrix, vp, @p2.x, @p2.y, @p2.z); LineFacet(p1, p2, axis, p, wd, wd1); end;
Буду краток и попробую без заумностей ))). Берем координаты курсора мыши в окне. При помощи gluUnProject узнаем координаты OpenGl Затем зная глубину погружения объекта по оси Z выполняем следующие действия Вычисляем котангенс угла заданного в gluPerspective (первый параметр (у меня 45 градусов)) и получаем растояние от камеры (глаза) до экрана (у меня получается 2,4142135623730950488016887242097). Делим глубину объекта (координата Z (у меня 8.0f)) на это расстояние и получаем коэфициент смещения. У меня получается 3.3137084989847603904135097936785; Но!!! Это только для оси Y! Не даром первый параметр gluPerspective так и называется fovy. Для Икса делаем следующие делим ширину вьюпорта на высоту. Например, 640/480. Получаем 1,3333333333333333333333333333333. Умножаем на коэфициент смещения по Игрек (тобишь 3.3137084989847603904135097936785) получаем коэфициент для Икс (4.4182779986463471872180130582373). Ну а дальше приращиваем смещение мыши к коородинатам обекта, домножая координаты X и Y на соответствующие коэфициенты. И все будет хокей! Спасибо за внимание, надеюсь комунить помог. И спасибо авторам выше за то что помогли мне!
Уважаемый DEEP! Время ничто - Тема Всё! Тем более, что когда я столкнулся с проблемой перемещения объекта OpenGl мышкой только этот форум помог мне разрешить её (гуглить я умею и еще как, но ни чего толковее чем здешние советы не встречал). Еще раз спасибо Вам. З.Ы. Поисковик то на ваш сайт кажет ))))