[英]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
除了相机旋转之外,我不知道这种“渲染到四边形”概念是否可以实现自由飞行的相机。 任何帮助表示赞赏!
我尝试了 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 轴的旋转。
您必须尊重视口的纵横比。
在计算射线方向的点时, canvasX
和canvasY
会考虑纵横比。
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.