Комплектация Ray неточна

Я пытаюсь реализовать сбор луч с помощью инструкций от этот сайт.

Прямо сейчас я просто хочу иметь возможность щелкать по земле, чтобы приказать моей маленькой фигуре идти к этой точке.
Поскольку моя земная плоскость плоская, не повернута и не переведена, мне нужно будет найти координаты x и z моего луча, когда y достигает 0.

Пока все хорошо, вот что я придумал:

//some constants
float HEIGHT = 768.f;
float LENGTH = 1024.f;
float fovy = 45.f;
float nearClip = 0.1f;

//mouse position on screen
float x = MouseX;
float y = HEIGHT - MouseY;

//GetView() returns the viewing direction, not the lookAt point.
glm::vec3 view = cam->GetView();
glm::normalize(view);

glm::vec3 h = glm::cross(view, glm::vec3(0,1,0) ); //cameraUp
glm::normalize(h);

glm::vec3 v = glm::cross(h, view);
glm::normalize(v);

// convert fovy to radians
float rad = fovy * 3.14 / 180.f;
float vLength = tan(rad/2) * nearClip; //nearClippingPlaneDistance
float hLength = vLength * (LENGTH/HEIGHT);

v *= vLength;
h *= hLength;

// translate mouse coordinates so that the origin lies in the center
// of the view port
x -= LENGTH / 2.f;
y -= HEIGHT / 2.f;

// scale mouse coordinates so that half the view port width and height
// becomes 1
x /= (LENGTH/2.f);
y /= (HEIGHT/2.f);

glm::vec3 cameraPos = cam->GetPosition();

// linear combination to compute intersection of picking ray with
// view port plane
glm::vec3 pos = cameraPos + (view*nearClip) + (h*x) + (v*y);

// compute direction of picking ray by subtracting intersection point
// with camera position
glm::vec3 dir = pos - cameraPos;

//Get intersection between ray and the ground plane
pos -= (dir * (pos.y/dir.y));

На данный момент я ожидаю pos чтобы быть точкой, где мой луч луча падает на мою плоскость.
Однако, когда я пытаюсь это сделать, я получаю что-то вроде этого:
ошибка
(Курсор мыши не был записан)
Трудно увидеть, поскольку на земле нет текстуры, но камера наклонена, как в большинстве игр RTS.
Моя жалкая попытка смоделировать внешне выглядящее человеческое существо в Blender отмечает точку, где пересечение произошло согласно моим расчетам.

Таким образом, кажется, что трансформация между view а также dir где-то запутался, и мой луч в конечном итоге указывал в неправильном направлении.
Разрыв между рассчитанным положением и фактическим положением увеличивает расстояние, на которое я отошел от центра экрана.

Я узнал, что:

  • ВЫСОТА и ДЛИНА не острые. Поскольку Windows отсекает несколько пикселей для границ, было бы более точно использовать 1006728 в качестве разрешения окна. Я предполагаю, что это может привести к небольшим расхождениям.
  • Если я увеличу fovy с 45 до 78, я получу довольно точный луч. Так что, может быть, что-то не так с тем, что я использую как fovy. Я явно звоню glm::perspective(45.f, 1.38f, 0.1f, 500.f) (fovy, соотношение сторон, fNear, fFar соответственно).

Так вот, где я потерялся. Что мне нужно сделать, чтобы получить точный луч?

PS: я знаю, что есть функции и библиотеки, которые это реализовали, но я стараюсь держаться подальше от этих вещей в учебных целях.

0

Решение

Вот рабочий код, который делает курсор в 3D преобразование, используя информацию буфера глубины:

  glGetIntegerv(GL_VIEWPORT, @fViewport);
glGetDoublev(GL_PROJECTION_MATRIX, @fProjection);
glGetDoublev(GL_MODELVIEW_MATRIX, @fModelview);

//fViewport already contains viewport offsets
PosX := X;
PosY := ScreenY - Y; //In OpenGL Y axis is inverted and starts from bottom

glReadPixels(PosX, PosY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, @vz);

gluUnProject(PosX, PosY, vz, fModelview, fProjection, fViewport, @wx, @wy, @wz);
XYZ.X := wx;
XYZ.Y := wy;
XYZ.Z := wz;

Если вы проверяете только пересечение луча / плоскости, это вторая часть без DepthBuffer:

  gluUnProject(PosX, PosY, 0, fModelview, fProjection, fViewport, @x1, @y1, @z1); //Near
gluUnProject(PosX, PosY, 1, fModelview, fProjection, fViewport, @x2, @y2, @z2); //Far

//No intersection
Result := False;
XYZ.X := 0;
XYZ.Y := 0;
XYZ.Z := aZ;

if z2 < z1 then
SwapFloat(z1, z2);

if (z1 <> z2) and InRange(aZ, z1, z2) then
begin
D := 1 - (aZ - z1) / (z2 - z1);
XYZ.X := Lerp(x1, x2, D);
XYZ.Y := Lerp(y1, y2, D);
Result := True;
end;

Я нахожу это несколько отличным от того, что вы делаете, но, возможно, это будет иметь больше смысла.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]