在点击时绘制光线投射线的问题

时间:2014-05-09 05:16:49

标签: opengl opengl-3

我上周左右一直致力于将屏幕转换为世界坐标(之前但无关的问题:Depth Component of Converting from Window -> World Coordinates)。

自从那篇帖子以来,我在简化代码方面取得了很多进展,但现在我正在采用光线投射方法进行对象选择,更具体地说,首先通过绘制一条直线来显示光线(它已被绘制但是没有正确的坐标。)

visualizing ray casting

(这4行显示点击方块的每个角落+相机已旋转以更好地查看线条时会发生什么。)

代码:

顶点着色器:

#version 330

layout(location = 0) in vec4 position;
layout(location = 1) in vec4 rcolor;

smooth out vec4 theColor;

uniform vec4 color;
uniform mat4 pv;

void main() {
  gl_Position = pv * position;
  theColor = color;
}

^其中pv是投影矩阵和&的组合。视图矩阵。 Camera类的相关代码:

Camera::Camera()
{
  camPos = glm::vec3(0.0f, 5.0f, 1.0f);
  camLook = glm::vec3(0.0f, 0.0f, 0.0f);

  fovy = 90.0f;
  aspect = 1.0f;
  near = 0.1f;
  far = 100.0f;
}

glm::mat4 Camera::projectionMatrix()
{
  return glm::perspective(fovy, aspect, near, far);
}

glm::mat4 Camera::viewMatrix()
{
  return glm::lookAt(
    camPos,
    camLook,
    glm::vec3(0, 1, 0)
  );
}

glm::mat4 Camera::projectionViewMatrix()
{
  return projectionMatrix() * viewMatrix();
}

点击后我初始化一个Ray对象:

void initializeRay(int x, int y)
{
  Ray rayObj(
    camera.getWorldNear(x, y),
    camera.getWorldFar(x, y)
  );
  rays.push_back(rayObj);
}

(来自Camera类的相关功能) - 可能是问题所在

glm::vec3 Camera::getWorldNear(int x, int y)
{
  GLint viewport[4];
  glGetIntegerv(GL_VIEWPORT, viewport);

  glm::vec3 worldNear = glm::unProject(
    glm::vec3(x, viewport[3] - y, near),
    viewMatrix(),
    projectionMatrix(),
    glm::vec4(0.0f, 0.0f, viewport[2], viewport[3])
  );

  printf("near: (%f, %f, %f)\n", worldNear.x, worldNear.y, worldNear.z);

  return worldNear;
}

glm::vec3 Camera::getWorldFar(int x, int y)
{
  GLint viewport[4];
  glGetIntegerv(GL_VIEWPORT, viewport);

  glm::vec3 worldFar = glm::unProject(
    glm::vec3(x, viewport[3] - y, far),
    viewMatrix(),
    projectionMatrix(),
    glm::vec4(0.0f, 0.0f, viewport[2], viewport[3])
  );

  printf("far: (%f, %f, %f)\n", worldFar.x, worldFar.y, worldFar.z);

  return worldFar;
}

并构建对象....

Ray::Ray(glm::vec3 worldNear, glm::vec3 worldFar)
{
  float temp[] = {
    worldNear.x, worldNear.y, worldNear.z,
    worldFar.x, worldFar.y, worldFar.z,
  };

  vertexData.resize(6);
  for (x = 0; x < 6; x++)
    vertexData[x] = temp[x];

  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(float), &vertexData[0], GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
}

每次调用显示功能时,都会绘制所有光线:

void drawRays()
{
  for (int x = 0; x < rays.size(); x++) {
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, rays[x].vbo);

    glVertexAttribPointer(
      0,
      2,
      GL_FLOAT,
      GL_FALSE,
      0,
      (void*)0
    );

    glUniform4f(colorUniform, 1.0f, 0.0f, 0.0f, 0.0f);

    glDrawArrays(GL_LINES, 0, 2);

    glDisableVertexAttribArray(0);
  }
}

我最初的想法是我以错误的方式使用glm::unProject函数,但我也尝试将光线的起点和终点位置更改为camPos&amp; camLook(相机位置和相机看位置)没有任何运气(再次,光线似乎都聚集在广场的顶部)。

修改

我还创建了一个获取光线方向的函数,但目前我的代码中仍未使用该函数:

glm::vec3 Camera::getRay(int x, int y)
{
  glm::vec3 worldNear = glm::unProject(
    glm::vec3(x, screenHeight - y, near),
    viewMatrix(),
    projectionMatrix(),
    glm::vec4(0.0f, 0.0f, screenWidth, screenHeight)
  );

  glm::vec3 worldFar = glm::unProject(
    glm::vec3(x, screenHeight - y, far),
    viewMatrix(),
    projectionMatrix(),
    glm::vec4(0.0f, 0.0f, screenWidth, screenHeight)
  );

  glm::vec3 direction = worldFar - worldNear;
  direction - glm::normalize(direction);

  printf("(%f, %f, %f)\n", direction.x, direction.y, direction.z);
  return direction;
}

1 个答案:

答案 0 :(得分:1)

要绝对清楚,这些光线在哪里可视化应该来源?我想你正在点击 window-space 中的某个任意位置,并希望光线从那里开始?

glm::UnProject (...)需要窗口空间中的坐标,但实际上您提供 目前在 view-space 中定义。很容易忘记转换到窗口空间由视口定义(NDC x,y - &gt; Win x ,y 也是深度范围(NDC z - &gt; Win z )。

您的近处和远处飞机位置经历多次变换:

开始时:

near = 0.1 far = 100.0 (查看空间)

投影和透视分割后:

near = -1.0 far = 1.0 (NDC空间)

最后,在视口转换 *

之后

near = 0.0 far = 1.0 (窗口空间)

* GL使用的 默认 深度范围为[ 0.0 1.0 ]

这意味着在投影和视口转换后,近平面 0.0 ,远平面 1.0