如何生成用于射线投射的摄影机射线

问题描述 投票:0回答:1

我正在尝试使用OpenGL和C ++创建一个简单的体素引擎。我的第一步是从相机发出光线,并检测光线是否与某物相交(出于测试目的,它仅是两个平面)。通过创建一个全屏四边形并对片段着色器进行编程,可以在不旋转相机的情况下使用它,对每个片段发出光线(现在我只是假设一个片段是一个像素),其方向是texCoord。 x,texCoord.y,-1。现在,我正在尝试实现相机旋转。

我已经尝试在cpu中生成一个旋转矩阵,并将其发送到着色器,该着色器会将其与每条射线相乘。但是,当我旋转相机时,飞机开始以只能用此视频描述的方式拉伸。https://www.youtube.com/watch?v=6NScMwnPe8c

这里是创建矩阵并每帧运行的代码:

float pi = 3.141592;
// camRotX and Y are defined elsewhere and can be controlled from the keyboard during runtime.
glm::vec3 camEulerAngles = glm::vec3(camRotX, camRotY, 0);

std::cout << "X: " << camEulerAngles.x << " Y: " << camEulerAngles.y << "\n";

// Convert to radians
camEulerAngles.x = camEulerAngles.x * pi / 180;
camEulerAngles.y = camEulerAngles.y * pi / 180;
camEulerAngles.z = camEulerAngles.z * pi / 180;

// Generate Quaternian
glm::quat camRotation;
camRotation = glm::quat(camEulerAngles);

// Generate rotation matrix from quaternian
glm::mat4 camToWorldMatrix = glm::toMat4(camRotation);
// No transformation matrix is created because the rays should be relative to 0,0,0

// Send the rotation matrix to the shader
int camTransformMatrixID = glGetUniformLocation(shader, "cameraTransformationMatrix");
glUniformMatrix4fv(camTransformMatrixID, 1, GL_FALSE, glm::value_ptr(camToWorldMatrix));

和片段着色器:

#version 330 core
in vec4 texCoord;

layout(location = 0) out vec4 color;
uniform vec3 cameraPosition;
uniform vec3 cameraTR;
uniform vec3 cameraTL;
uniform vec3 cameraBR;
uniform vec3 cameraBL;
uniform mat4 cameraTransformationMatrix;
uniform float fov;
uniform float aspectRatio;
float pi = 3.141592;

int RayHitCell(vec3 origin, vec3 direction, vec3 cellPosition, float cellSize)
{
    if(direction.z != 0)
    {
        float multiplicationFactorFront = cellPosition.z - origin.z;
        if(multiplicationFactorFront > 0){
            vec2 interceptFront = vec2(direction.x * multiplicationFactorFront + origin.x,
                                       direction.y * multiplicationFactorFront + origin.y);
            if(interceptFront.x > cellPosition.x && interceptFront.x < cellPosition.x + cellSize &&
               interceptFront.y > cellPosition.y && interceptFront.y < cellPosition.y + cellSize)
            {
                return 1;
            }
        }
        float multiplicationFactorBack = cellPosition.z + cellSize - origin.z;
        if(multiplicationFactorBack > 0){
            vec2 interceptBack = vec2(direction.x * multiplicationFactorBack + origin.x,
                                      direction.y * multiplicationFactorBack + origin.y);
            if(interceptBack.x > cellPosition.x && interceptBack.x < cellPosition.x + cellSize &&
               interceptBack.y > cellPosition.y && interceptBack.y < cellPosition.y + cellSize)
            {
                return 2;
            }
        }
    }
    return 0;
}

void main()
{
    // For now I'm not accounting for FOV and aspect ratio because I want to get the rotation working first
    vec4 beforeRotateRayDirection = vec4(texCoord.x,texCoord.y,-1,0);
    // Apply the rotation matrix that was generated on the cpu
    vec3 rayDirection = vec3(cameraTransformationMatrix *  beforeRotateRayDirection);

    int t = RayHitCell(cameraPosition, rayDirection, vec3(0,0,5), 1);
    if(t == 1)
    {
        // Hit front plane
        color = vec4(0, 0, 1, 0);
    }else if(t == 2)
    {
        // Hit back plane
        color = vec4(0, 0, 0.5, 0);
    }else{
        // background color
        color = vec4(0, 1, 0, 0);
    }
}
c++ opengl glsl raycasting rotational-matrices
1个回答
0
投票

好。真的很难知道出什么问题了,尽管如此我还是会尝试。

这里有一些提示和注释:

1)您可以通过将方向映射到RGB颜色来调试方向。请记住,您应该对向量进行归一化并从(-1,1)映射到(0,1)。只需执行dir*0.5+1.0类型的操作即可。示例:

color = vec4(normalize(rayDirection) * 0.5, 0) + vec4(1);

2)您可以更直接的方式获得旋转矩阵。四元数从正向初始化,它将首先绕Y轴旋转(水平外观),然后且仅然后绕X轴旋转(垂直外观)。请记住,如果您从euler-angles初始化,则旋转顺序取决于实现。尽可能使用mat4_cast避免实验性glm扩展(gtx)。示例:

// Define rotation quaternion starting from look rotation
glm::quat camRotation = glm::vec3(0, 0, 0);
camRotation = glm::rotate(camRotation, glm::radians(camRotY), glm::vec3(0, 1, 0));
camRotation = glm::rotate(camRotation, glm::radians(camRotX), glm::vec3(1, 0, 0));
glm::mat4 camToWorldMatrix = glm::mat4_cast(camRotation);

3]您的beforeRotateRayDirection是一个向量,(可能)从(-1,-1,-1)一直指向(1,1,-1)。这是未规范化,(1,1,1)的长度为√3≈1.7320508075688772 ...请确保已将碰撞数学考虑在内,或仅对向量进行了规范化。

到目前为止我的部分回答...

您的碰撞测试有点奇怪...看来您想将射线投射到给定单元位置的Z平面中(但两次,一次在前面,一次在后面)。我已经检查了您的代码逻辑,这很有意义,但是由于没有顶点程序,因此不知道texCoord范围值是什么,因此无法确定。您可能需要重新考虑以下逻辑:

int RayHitCell(vec3 origin, vec3 direction, vec3 cellPosition, float cellSize)
{
    //Get triangle side vectors
    vec3 tu = vec3(cellSize,0,0);   //Triangle U component
    vec3 tv = vec3(0,cellSize,0);   //Triangle V component

    //Determinant for inverse matrix
    vec3 q = cross(direction, tv);
    float det = dot(tu, q);
    //if(abs(det) < 0.0000001) //If too close to zero
    //  return;
    float invdet = 1.0/det;

    //Solve component parameters
    vec3 s = origin - cellPosition;
    float u = dot(s, q) * invdet;
    if(u < 0.0 || u > 1.0)
        return 0;

    vec3 r = cross(s, tu);
    float v = dot(direction, r) * invdet;
    if(v < 0.0 || v > 1.0)
        return 0;

    float t = dot(tv, r) * invdet;
    if(t <= 0.0)
        return 0;

    return 1;
}

void main()
{
    // For now I'm not accounting for FOV and aspect ratio because I want to get the 
    // rotation working first
    vec4 beforeRotateRayDirection = vec4(texCoord.x, texCoord.y, -1, 0);
    // Apply the rotation matrix that was generated on the cpu
    vec3 rayDirection = vec3(cameraTransformationMatrix * beforeRotateRayDirection);

    int t = RayHitCell(cameraPosition, normalize(rayDirection), vec3(0,0,5), 1);
    if (t == 1)
    {
        // Hit front plane
        color = vec4(0, 0, 1, 0);
    }
    else
    {
        // background color
        color = vec4(0, 1, 0, 0);
    }
}

这应该给您一架飞机,让我知道它是否有效。立方体很容易做。

PS。:uv可以用于纹理映射。

© www.soinside.com 2019 - 2024. All rights reserved.