Как вычислить 2D координату курсора в 3D мире?
Доброго времени суток! Прошу подсобить советом в решении одной задачи. В созданной 3D сцене нужно узнать точную координату X,Y,Z на которую указывает курсор мыши. А именно есть координаты X,Y,Z камеры и X,Y 2D координата курсора, ну и Z1 расстояние до предполагаемой 3D точки. По возможности напишите пожалуйста формулу для реализации этой процедуры. Спасибо.
|
Ответ: Как вычислить 2D координату курсора в 3D мире?
Если просто, то CameraPick
|
Ответ: Как вычислить 2D координату курсора в 3D мире?
К сожалению будь всё так элементарно и не спрашивал бы. CameraPick не совсем что нужно. В вашем варианте прийдёться создавать объект, а в дальнейшем передвигать его в нужную 3D точку по отношению к курсору. Вполне реалистично, но как-то заморочно. Математическими вычислениями было-бы как-то солидней. :) Перелопатил уже уйму материала. Пока совсем не въехал. Математик ещё тот...
|
Ответ: Как вычислить 2D координату курсора в 3D мире?
Цитата:
То есть получится вектор XYZ в пространстве экрана. Потом этот вектор надо умножить на инверсную матрицу камеры, и получится этот же вектор но уже в пространстве камеры. Затем его умножить на инверсную матрицу трансформации камеры. И получатся координаты в пространстве мира, которые мы и хотели. Это была теория. А вот практика уже грустнее. Применительно к блицу, у него нет встроенных инструментов для работы с линейной алгеброй. Элементы матрицы трансформации можно достать с помощью GetMatElement. Достать матрицу проекции камеры вроде нельзя. Но можно её самостоятельно сделать, зная её параметры (угол обзора и т.д.). Так как у Блица нет встроенных инструментов для работы с линейной алгеброй, то инвертирование матриц и умножение вектора на них тебе придётся писать самому, что в целом не сложно, достаточно только вооружиться учебником по математике 1-го курса института. Другой вопрос: в связи с особенностями Блица такой способ всё равно будет медленнее, чем если поставить полигон перед камерой и сделать на него CameraPick. Поэтому если стоит практическая задача, то лучше делать через CameraPick и не париться. На других движках, наверное, операциями с математикой было бы и лучше, но не в случае Блица. |
Ответ: Как вычислить 2D координату курсора в 3D мире?
Вот моя попытка соорудить что-то вроде определителя 3D координаты под курсором мыши. Пока есть недостатки. Для нормального вычисления нельзя вращать камеру по XY осям, так-как сбиваются координаты. Есть ощущение что решение этого недостатка где-то рядом, не пока не могу сообразить где. Если вас не затруднит взгляните на код. Может будут какие-либо советы, предложения. Буду весьма благодарен. Спасибо.
P.S. Управление камерой на стрелочках и правые шифт и контрол. Вращение по Z оси=7 и 9 на NUM PAD, то бишь ЦИФРОКЛАВА. )) ; перечень работоспособных разрешений всегда должны быть 4/3 ; 640,480 \ 800,600 \ 1024,768 camW=800: camH=600 Graphics3D camW,camH,32,2 SetBuffer BackBuffer () ; стартовое позиционирование камеры XYZ camX#=0: camY#=0: camZ#=-40 cam = CreateCamera() PositionEntity cam,camX,camY,camZ ; стартовое вращение камеры по осям XYZ anglX#=0: anglY#=0: anglZ#=0 RotateEntity cam,anglX#,anglY#,anglZ#,True ; стартовая дистанция до 3Д точки distance#=-40 ; для наглядности сфера будет прикреплена к курсору sph=CreateSphere (4) ScaleEntity sph,2,2,2 arial20=LoadFont ("arial",20) SetFont arial20 ; основной цикл ==================================== While Not KeyDown(1) mx=MouseX(): my=MouseY() ; изменения позиции камеры If KeyDown (203) Then camX=camX-1; (Left) If KeyDown (205) Then camX=camX+1; (Right) If KeyDown (200) Then camZ=camZ-1; (Up) If KeyDown (208) Then camZ=camZ+1; (Down) If KeyDown (54) Then camY=camY+1; (r Shift) If KeyDown (157) Then camY=camY-1; (r Cntrl) PositionEntity cam,camX,camY,camZ ; вращение камеры по XYZ оси ; кроме оси Z пока вращать нельзя (СБОЙ НАВЕДЕНИЯ) ; If KeyDown (72) Then anglX=anglX-1; (8) ; If KeyDown (80) Then anglX=anglX+1; (2) ; If KeyDown (75) Then anglY=anglY-1; (4) ; If KeyDown (77) Then anglY=anglY+1; (6) If KeyDown (71) Then anglZ=anglZ-1; (7) работает нормально If KeyDown (73) Then anglZ=anglZ+1; (9) работает нормально RotateEntity cam,anglX,anglY,anglZ ; что-бы не делать вычислений в пустую If oldmxy<>mx+my+camX+camY+camZ+anglX+anglY+anglZ Then oldmxy=mx+my+camX+camY+camZ+anglX+anglY+anglZ XYZ$=FF_2Dto3D(cam,camW,camH,distance); XYZ$=полученные результаты ; передача результата от функции происходит в тексте "\"=разделитель между параметрами oldi=1: kol=0 For i=1 To Len(XYZ$) If Mid$(XYZ$,i,1)="\" Then If kol=0 Then pxx#=Mid$(XYZ$,oldi,i-1) ; получина X координата If kol=1 Then pyy#=Mid$(XYZ$,oldi,i-1) ; получина Y координата If kol=2 Then pzz#=Mid$(XYZ$,oldi,i-1) ; получина Z координата oldi=i+1: kol=kol+1 EndIf Next EndIf PositionEntity sph,pxx,pyy,pzz,True RenderWorld Color 250,250,0: Rect mx-8,my-8,16,16,0 Color 250,250,250 Text 400,0,"X\Y\Z координаты сферы="+XYZ$,True CXYZ$=camX+"\"+camY+"\"+camZ Text 400,20,"X\Y\Z координаты камеры="+CXYZ$,True CAXYZ$=anglX+"\"+anglY+"\"+anglZ Text 400,40,"X\Y\Z вращение камеры="+CAXYZ$,True Flip Wend End ; ================================================ ; ---------------------------------------------------------------------------------- ; ПЕРЕВОД ПОЗИЦИИ 2Д КУРСОРА В 3Д КООРДИНАТУ ; cam=личный номер камеры, camW,camH=разрешение экрана, ; distance#=предполагаемая дистанция до 3Д точки Function FF_2Dto3D$(cam,camW,camH,distance#) mx=MouseX(): my=MouseY() ; определяю местоположения камеры camX#=EntityX#(cam) camY#=EntityY#(cam) camZ#=EntityZ#(cam) ; поворот камеры по осям XYZ anglX#=EntityPitch#(cam) anglY#=EntityYaw#(cam) anglZ#=EntityRoll#(cam) ; вычисляю шаг движения 3Д точки с учётом дистанции до камеры ; разрешение всегда должно иметь соотношение сторон 4/3 для правильной работы. ccz#=(camW/4)/((distance/2)+(camZ/2)) ; смещаю нулевую координату курсора в центр экрана cx#=(camW/2)-mx cy#=(camH/2)-my ; вычисляю новую 3Д координату по отношению к позиции камеры ccx#=camX+cx/ccz ccy#=camY-cy/ccz ; узнаю дистанцию и угол между камерой и 3Д точкой alldist#=FF_getdist#(camX,camY,ccx,ccy,1) allug#=FF_getdist#(camX,camY,ccx,ccy,2)+anglZ ; вычисляю координаты новой точки зная угол и дистанцию pxx#=camX+Sin(allug)*alldist pyy#=camY-Cos(allug)*alldist pzz#=-distance ; передаю XYZ координаты для использования XYZ$=pxx+"\"+pyy+"\"+pzz+"\" Return XYZ$ End Function ; ---------------------------------------------------------------------------------- ; _____________________________________________ ; ЗАМЕР ДИСТАНЦИИ И УГЛА между точками ; px,py,pxx,pyy=первая и вторая точки измерения ; direc=1 возврат дистанции direc=2 возврат угла 0=верх 90=право и т д по Ч стрелке Function FF_getdist#(px#,py#,pxx#,pyy#,direc) dx#=pxx#-px# dy#=pyy#-py# ; вычисляю дистанцию между координатами If direc=1 Then dist#=Sqr((dx#*dx#)+(dy#*dy#)) ; определяю угол между точками от px,py и к pxx,pyy If direc=2 dist#=180+ATan2(dx#,dy#): dist#=360-dist# EndIf Return dist# End Function ; ---------------------------------------------------------------------------------UOTE][/quote][/quote] |
Ответ: Как вычислить 2D координату курсора в 3D мире?
Цитата:
А просто читать код сложнее хелловорлда без возможности его оттестировать даже при наличии времени и желания ничего не даст. Если у тебя вычисляется 3D-координата при нулевом положении камеры, значит, ты на верном пути. Теперь надо полученный вектор выводить из пространства камеры в пространство мира, похоже, проблема кроется в этой части. Как ты решаешь конкретно эту часть задачи? |
Ответ: Как вычислить 2D координату курсора в 3D мире?
От своей ранее изложенной идеи не отказываюсь, но всё-же слишком надолго застревать на одном месте наверное не стоит. Пока-же реализую функцию по определению 3Д координаты по отношению к 2Д курсору другим способом, который мне предложили АВТОМАТ и КИРПИ4. За что им очень благодарен!
Суть функции такова. Создаётся Mesh в позиции камеры и направляется в ту-же сторону, далее Mesh отодвигаю от камеры на необходимое расстояние. MoveEntity msh,0,0,-distance# Далее в цикле при помощи. CameraProject (cam,EntityX(msh),EntityY(msh),EntityZ(msh)) iccx=ProjectedX #() iccy=ProjectedY #() Узнаю 2Д координату Mesh и передвигаю его в сторону курсора. Когда 2Д координаты относительно сошлись вывожу 3Д позицию Mesh в тексте "X\Y\Z\"... Ну как-то так. Вот та самая функция, может кому нужно будет. ; ------------------------------------------------------------------------------- ; ПОЗИЦИЯ 2Д КУРСОРА В 3Д КООРДИНАТУ ; cam=личный номер камеры, camW,camH=разрешение экрана, ; distance#=предполагаемая дистанция до 3Д точки Function FF_2Dto3D$(cam,distance#) mx=MouseX(): my=MouseY() ; определяю местоположения камеры camX#=EntityX#(cam) camY#=EntityY#(cam) camZ#=EntityZ#(cam) ; поворот камеры по осям XYZ anglX#=EntityPitch#(cam) anglY#=EntityYaw#(cam) anglZ#=EntityRoll#(cam) ; создаю Mesh, ориентирую его в направлении камеры ; и отодвигаю на нужную дистанцию msh=CreateMesh () PositionEntity msh,camX#,camY#,camZ# RotateEntity msh,anglX#,anglY#,anglZ# MoveEntity msh,0,0,-distance# ; цикл выравнивания Repeat ; узнаю координату Mesh в 2Д области экрана CameraProject (cam,EntityX(msh),EntityY(msh),EntityZ(msh)) iccx=ProjectedX #() iccy=ProjectedY #() ; передвижение Mesh в сторону курсора noko=0: xxx#=0: yyy#=0 If iccx<mx-1 Then xxx#=.1: noko=1 If iccx>mx+1 Then xxx#=-.1: noko=1 If iccy<my-1 Then yyy#=-.1: noko=1 If iccy>my+1 Then yyy#=.1: noko=1 MoveEntity msh,xxx#,yyy#,0 Until noko=0 ; узнаю координату Mesh в 3Д области xxx#=EntityX(msh): yyy#=EntityY(msh): zzz#=EntityZ(msh) ; удаляю msh за ненадобностью FreeEntity msh ; передаю XYZ координаты для использования XYZ$=xxx#+"\"+yyy#+"\"+zzz#+"\" Return XYZ$ End Function ; ------------------------------------------------------------------------------- |
Часовой пояс GMT +4, время: 20:47. |
vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot