大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE稳定放心使用
首先,重要的是要记住OpenGL中的矩阵是使用列主顺序(而不是行主顺序)定义的。在所有的OpenGL书籍和参考文献中,OpenGL中使用的透视投影矩阵定义为:
我们可以简单地转置矩阵,就能得到下面的以行向量为顺序的矩阵:
下面对透视投影矩阵的参数做一些说明:
l, r:立方体的左,右在X轴上的投影
b, t:立方体的下,上在X轴上的投影
n:近平面在Z轴上的投影
f:远平面在Z轴上的投影
关于OpenGL透视投影矩阵的推导,可参考链接link.
在这里我们推荐另外一种大佬关于投影矩阵的推导方法,是基于计算机图形学投影矩阵的推导,求出来的结果会和OpenGL的透视投影矩阵有差别,但是在推导过程上更加简单,易于理解。可参照以下链接: link.
关于透视投影矩阵的使用
在旧的固定函数渲染管道中,使用两个函数来设置屏幕坐标和投影矩阵,这两个函数分别是gluPerspective(它是glu库的一部分)和glFrustum。
设置投影矩阵 glFrustum()
在OpenGL中设置透视投影矩阵是通过调用glFrustum来完成的。该函数有六个参数:
// 定义
glFrustum(float left, float right, float bottom, float top, float near, float far);
设置屏幕坐标 gluPerspective()
gluPerspective函数用于设置屏幕坐标。它将视角、图像长宽比(图像宽度除以图像高度)和剪切平面作为增广量。
fovy是垂直视角,也就是从近平面的上边的中心和下边的中心分别连一条线到摄像机所成的角度。 aspect是宽高比,aspect= width/height。
// 定义
void gluPerspective(float fovy, float aspect, float near, float far);
思考: 如何利用FOVY和Aspect确定近平面的 l,r,b,t参数?
注:n,f是固定值,不用确定!
write:
tan(FOVY/2)=opposite/adjacent=BC/AB=t/n
therefore:
t=tan(FOVY/2)∗n
由于相机的下半部分与上半部分是对称的,则:
b=−t
已知点C在Y轴的分量是 t,下方点D在Y轴的分量是 –t,由此我们可以知道平面高度是 2t。同理可知,平面宽度是 2r。
所以宽高比:
Aspect = 2r/2t = r/t
则可进一步得知:
r = Aspect * t
l = -r
综上:只要定义视锥的宽高比和视角,即可得
l,r,b,t 参数用于定义正交投影的立方体。
附参考代码:
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include "geometry.h"
#include "vertexdata.h"
// compute screen coordinates first
void gluPerspective(
const float &angleOfView,
const float &imageAspectRatio,
const float &n, const float &f,
float &b, float &t, float &l, float &r)
{
float scale = tan(angleOfView * 0.5 * M_PI / 180) * n;
r = imageAspectRatio * scale, l = -r;
t = scale, b = -t;
}
// set the OpenGL perspective projection matrix
void glFrustum(
const float &b, const float &t, const float &l, const float &r,
const float &n, const float &f,
Matrix44f &M)
{
// set OpenGL perspective projection matrix
M[0][0] = 2 * n / (r - l);
M[0][1] = 0;
M[0][2] = 0;
M[0][3] = 0;
M[1][0] = 0;
M[1][1] = 2 * n / (t - b);
M[1][2] = 0;
M[1][3] = 0;
M[2][0] = (r + l) / (r - l);
M[2][1] = (t + b) / (t - b);
M[2][2] = -(f + n) / (f - n);
M[2][3] = -1;
M[3][0] = 0;
M[3][1] = 0;
M[3][2] = -2 * f * n / (f - n);
M[3][3] = 0;
}
void multPointMatrix(const Vec3f &in, Vec3f &out, const Matrix44f &M)
{
//out = in * Mproj;
out.x = in.x * M[0][0] + in.y * M[1][0] + in.z * M[2][0] + /* in.z = 1 */ M[3][0];
out.y = in.x * M[0][1] + in.y * M[1][1] + in.z * M[2][1] + /* in.z = 1 */ M[3][1];
out.z = in.x * M[0][2] + in.y * M[1][2] + in.z * M[2][2] + /* in.z = 1 */ M[3][2];
float w = in.x * M[0][3] + in.y * M[1][3] + in.z * M[2][3] + /* in.z = 1 */ M[3][3];
// normalize if w is different than 1 (convert from homogeneous to Cartesian coordinates)
if (w != 1) {
out.x /= w;
out.y /= w;
out.z /= w;
}
}
int main(int argc, char **argv)
{
uint32_t imageWidth = 512, imageHeight = 512;
Matrix44f Mproj;
Matrix44f worldToCamera;
worldToCamera[3][1] = -10;
worldToCamera[3][2] = -20;
float angleOfView = 90;
float near = 0.1;
float far = 100;
float imageAspectRatio = imageWidth / (float)imageHeight;
float b, t, l, r;
gluPerspective(angleOfView, imageAspectRatio, near, far, b, t, l, r);
glFrustum(b, t, l, r, near, far, Mproj);
unsigned char *buffer = new unsigned char[imageWidth * imageHeight];
memset(buffer, 0x0, imageWidth * imageHeight);
for (uint32_t i = 0; i < numVertices; ++i) {
Vec3f vertCamera, projectedVert;
multPointMatrix(vertices[i], vertCamera, worldToCamera);
multPointMatrix(vertCamera, projectedVert, Mproj);
if (projectedVert.x < -imageAspectRatio || projectedVert.x > imageAspectRatio || projectedVert.y < -1 || projectedVert.y > 1) continue;
// convert to raster space and mark the position of the vertex in the image with a simple dot
uint32_t x = std::min(imageWidth - 1, (uint32_t)((projectedVert.x + 1) * 0.5 * imageWidth));
uint32_t y = std::min(imageHeight - 1, (uint32_t)((1 - (projectedVert.y + 1) * 0.5) * imageHeight));
buffer[y * imageWidth + x] = 255;
//std::cerr << "here sometmes" << std::endl;
}
// export to image
std::ofstream ofs;
ofs.open("./out.ppm");
ofs << "P5\n" << imageWidth << " " << imageHeight << "\n255\n";
ofs.write((char*)buffer, imageWidth * imageHeight);
ofs.close();
delete [] buffer;
return 0;
}
参考链接:
- https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/opengl-perspective-projection-matrix
- https://zhuanlan.zhihu.com/p/144329075
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/185835.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...