参考:https://manpag.es/RHEL5/3+gluPerspective
#include <cmath> namespace nu { typedef float real_t; inline real_t cot(real_t theta) { return (real_t)1.0 / tan(theta); } inline real_t to_radian(real_t degree) { return degree * (real_t)3.14159265358979 / (real_t)180.0; } //! @brief 透視投影行列の作成 (視野角で指定) //! @param [out] m 結果の4x4行列 //! @param [in] fovy_degree 視野角 //! @param [in] aspect アスペクト比 //! @param [in] zNear 一番近いz位置 //! @param [in] zFar 一番遠いz位置 //! @return なし inline void myPerspective( real_t* m, real_t fovy_degree, real_t aspect, real_t zNear, real_t zFar) { real_t fovy_rad = to_radian(fovy_degree); real_t f = cot(fovy_rad / (real_t)2.0); m[0] = f / aspect; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = f; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = (zFar + zNear) / (zNear - zFar); m[11] = -1.0; m[12] = 0.0; m[13] = 0.0; m[14] = (2 * zFar * zNear) / (zNear - zFar); m[15] = 0.0; } }
gluPerspectiveの結果はgluPerspectiveを呼び出した後でglGetFloatvで取得する。
#include <windows.h> #include <gl/GLU.h> #include <gl/freeglut.h> #include <cstdio> //検証用 #include <cassert> //自前実装版gluPerspective #include "myperspective.h" #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") #pragma comment(lib,"freeglut.lib") void display(void) { GLfloat glumat[16]; //glu関数で生成 GLfloat mypmat[16]; //自分関数で生成 //gluPerpsective,myPerspectiveへの入力の値を色々変える static int i = 0; static float j = 0.0f; GLfloat fovy=45.0f + i; GLfloat aspect=0.2f + j; GLfloat zNear=0.1f + j; GLfloat zFar=10.0f + j*2; i++; j += 0.01; glMatrixMode(GL_PROJECTION); glLoadIdentity(); //gluで計算 gluPerspective(fovy, aspect, zNear, zFar); glGetFloatv(GL_PROJECTION_MATRIX, glumat); //自前計算 nu::myPerspective(mypmat, fovy, aspect, zNear, zFar); puts("----------------------------------------------"); for (int k = 0; k < 16; k++) { //自前計算 printf("m[%2d] %+5.5lf %+5.5lf \n", k,glumat[k], mypmat[k]); //自前計算とgluPerspective計算の値があまりにかけ離れていたらassertで落ちる assert(abs(glumat[k] - mypmat[k]) < 0.00001); } puts("----------------------------------------------"); } void mouse(int button, int state, int x, int y) { display(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutInitWindowPosition(0, 0); glutInitWindowSize(100,100); glutDisplayFunc(display); glutMouseFunc(mouse); glutMainLoop(); return 0; }