Fox*_*942 5 c++ opengl raytracing glsl glm-math
我有一个 Opengl 光线追踪器,它能够加载 obj 文件并以光线追踪方式将其可视化。我的应用程序使用 assimp 加载 obj 文件,然后使用着色器存储缓冲区将所有三角形面(包括顶点及其索引)发送到片段着色器。之后,片段着色器通过跟踪光线路径来计算像素的颜色。光线来自相机 ( posCamera
) 的位置并穿过虚拟画布的像素。基本结构是将结果渲染到这个四边形画布上。
目前,我正在研究相机。相机始终注视0,0,0
点 ( viewPoint
),并且可以通过以下函数绕 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);
Run Code Online (Sandbox Code Playgroud)
我只想围绕 x 轴旋转场景。为了解决这个问题,我创建了一个新函数:
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);
}
Run Code Online (Sandbox Code Playgroud)
它正在工作,但不幸的是,该比率存在一些失真。更重要的是,有时摄像机只是围绕一个点循环。这是与该问题相关的视频:链接。您可以看到水平旋转效果很好。
这是我的顶点着色器:
#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);
}
Run Code Online (Sandbox Code Playgroud)
这是完整源代码的链接:source
除了相机旋转之外,我不知道这种“渲染到四边形”概念是否可以实现自由飞行相机。任何帮助表示赞赏!
我尝试了Rabbid76的建议并修改了源代码。我也做了一些重构。更新矩形画布尺寸的方法如下所示:
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;
}
Run Code Online (Sandbox Code Playgroud)
处理相机绕 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();
}
Run Code Online (Sandbox Code Playgroud)
视野从45
度 修改为 到45 * (float)M_PI / 180
,因此模型的比例变得更好了一些。不幸的是,在相机绕X轴旋转的过程中,仍然可以发现场景拉伸和扭曲。当镜头达到一定程度时,它也会回头看camera.viewPoint
。我不知道如何“关闭它”。
结果可以在这个视频中看到:链接。首先可以看到绕Y轴的旋转,然后可以看到绕X轴的旋转。
您必须尊重视口的纵横比。
计算射线方向的点时canvasX
会考虑纵横比。canvasY
p = pixel = canvasX * normQuadCoord.x + canvasY * normQuadCoord.y + viewPoint;
Run Code Online (Sandbox Code Playgroud)
如果视口是矩形的,则矢量的大小必须不同。canvasX
是从视口中心到右侧的向量,canvasY
是从视口中心到顶部的向量。为了补偿视图的矩形并实现正确的投影,矢量长度之比必须等于长宽比倒数:
width | canvasY |
-------- = -----------
height | canvasX |
Run Code Online (Sandbox Code Playgroud)
因此, 的长度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;
Run Code Online (Sandbox Code Playgroud)