繁体   English   中英

如何解决相机沿 X 轴的旋转问题?

[英]How to solve camera rotation along the X-axis?

我有一个 Opengl 光线追踪器,它能够加载 obj 文件并以光线追踪的方式将其可视化。 我的应用程序使用 assimp 加载 obj 文件,然后使用着色器存储缓冲区将所有三角形面(包括顶点及其索引)发送到片段着色器。 之后,片段着色器通过跟踪光线的路径来计算像素的颜色。 光线来自相机 ( posCamera ) 的 position 并穿过虚拟 canvas 的像素。 基本结构即将将结果渲染到这个四边形 canvas。

目前,我正在研究相机。 相机始终注视着0,0,0点 ( viewPoint ),并且可以通过下面的 function 围绕 y 轴旋转:

void setCamera(float param) {
    connect = posCamera - viewPoint;

    posCamera = glm::vec3(connect.x * cos(param) + connect.z * sin(param), connect.y,
                          -connect.x * sin(param) + connect.z * cos(param)) + viewPoint;

    canvasX = cross(upVector, connect) * getLength(connect) * tanf(fieldOfview / 2);
    canvasY = cross(connect, canvasX) * getLength(connect) * tanf(fieldOfview / 2);

    setCam(posCamera,viewPoint, canvasY, fieldOfview);

我也只想围绕 x 轴旋转场景。 为了解决这个问题,我创建了一个新的 function:

void rotateAroundX(float param) {
    connect = posCamera - viewPoint;
    posCamera = glm::vec3(posCamera.x,
                          connect.y * cos(param) + connect.z * sin(param),
                          -connect.y * sin(param) + connect.z * cos(param))+viewPoint;
    canvasX = cross(upVector, connect) * getLength(connect) * tanf(fieldOfview / 2);
    canvasY = cross(connect, canvasX) * getLength(connect) * tanf(fieldOfview / 2);

    setCam(posCamera,viewPoint, canvasY, fieldOfview);
}

它正在工作,但不幸的是,该比率存在一些失真。 更重要的是,有时相机只是围绕一个点循环。 这是一个与问题相关的视频:链接 你可以看到水平旋转做得很好。

这是我的顶点着色器:

#version 460 core
layout(location = 0) in vec2 normQuadCoord;

uniform vec3 viewPoint;
uniform vec3 canvasX, canvasY;
out vec3 pixel;

void main()
{
    pixel = canvasX * normQuadCoord.x + canvasY * normQuadCoord.y + viewPoint;
    gl_Position = vec4(normQuadCoord, 0, 1);
}

这是完整源代码的链接: source

除了相机旋转之外,我不知道这种“渲染到四边形”概念是否可以实现自由飞行的相机。 任何帮助表示赞赏!


更新 1

我尝试了 Rabbid76 的建议并修改了源代码。 我也做了一些重构。 更新矩形 canvas 尺寸的方法如下所示:

void Init::updateCanvasSizes() {
    connect = camera.getPosCamera() - camera.getViewPoint();

    float aspect = (float)SCR_W_H.first/(float)SCR_W_H.second;
    float length = tanf(camera.getFieldOfview() / 2);

    canvasX = glm::normalize(glm::cross(camera.upVector, connect)) / length / aspect;
    canvasY = glm::normalize(glm::cross(connect, canvasX)) / length;

}

处理相机绕 X 轴旋转的方法修改为:

void Init::rotateCamAroundX(float param) {
    camera.posCamera = glm::vec3(camera.posCamera.x,
               (camera.posCamera.y - camera.viewPoint.y) * cos(param) + (camera.posCamera.z - camera.viewPoint.z) * sin(param) + camera.viewPoint.y,
               -(camera.posCamera.y - camera.viewPoint.y) * sin(param) + (camera.posCamera.z - camera.viewPoint.z) * cos(param) + camera.viewPoint.z);

    updateCanvasSizes();
}

视野已从45度修改为45 * (float)M_PI / 180 ,因此 model 的比率变得更好一些。 不幸的是,在相机绕 X 轴旋转的过程中,仍然可以发现场景拉伸和失真。 当相机达到一定程度时,它也会回过头来查看camera.viewPoint 我不知道如何“关闭它”。

结果可以在这个视频中看到: 链接 首先可以看到绕 Y 轴的旋转,然后可以看到绕 X 轴的旋转。

您必须尊重视口的纵横比。

在计算射线方向的点时, canvasXcanvasY会考虑纵横比。

p = pixel = canvasX * normQuadCoord.x + canvasY * normQuadCoord.y + viewPoint;

如果视口是矩形的,则向量的大小必须不同。 canvasX是从中心到右侧的向量, canvasY是从中心到视口顶部的向量。 为了补偿视图的矩形性并获得正确的投影,矢量长度的比率必须等于纵横比的倒数:

 width     | canvasY |
-------- = -----------
 height    | canvasX |

因此, canvasX的长度必须按倒数纵横比进行缩放。 纵横比是视图的宽度和高度的商( (float)SCR_WIDTH/(float)SCR_HEIGHT ):

float aspect = (float)SCR_WIDTH/(float)SCR_HEIGHT;
float length = tanf(fieldOfview / 2);

canvasX = glm::normalize(glm::cross(upVector, connect)) / length / aspect;
canvasY = glm::normalize(glm::cross(connect, canvasX)) / length;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM