用glTranslate,glRotate来模拟gluLookAt,即gluLookAt的模视矩阵能由glTranslate,glRotate实现:
float t= pow( 3, 0.5);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); //重置当前的模型观察矩阵
gluLookAt( t* 3, 2.0f, 3.0f, 0.0f, 8.0f, 0.0f, 0.0f, 1.0f, 0.0f);
double adModelMatrix[ 10][ 16];
glGetDoublev( GL_MODELVIEW_MATRIX, adModelMatrix[ 0]);//模視矩陣
glLoadIdentity(); //重置当前的模型观察矩阵
glRotatef(-45,1.0f,0.0f,0.0f);//绕y轴旋转三角形
glRotatef(-60,0.0f,1.0f,0.0f);//绕y轴旋转三角形
glTranslatef(-t* 3,-2.0,-3.0); //左移1.5单位,并移入屏幕6.0
glGetDoublev( GL_MODELVIEW_MATRIX, adModelMatrix[ 1]);//模視矩陣
///
RRT(任意角度,R表示旋转glRotate,T表示平移glTranslate)
Vec3 ptEye, ptRef, ptDir;
//视点和参考点任意(取随机数)
ptEye.x= ( rand()% 1000+ 1)/ 10;
ptEye.y= ( rand()% 1000+ 1)/ 10;
ptEye.z= ( rand()% 1000+ 1)/ 10;
ptRef.x= ( rand()% 1000+ 1)/ 10;
ptRef.y= ( rand()% 1000+ 1)/ 10;
ptRef.z= ( rand()% 1000+ 1)/ 10;
ptDir.x= ptRef.x- ptEye.x;
ptDir.y= ptRef.y- ptEye.y;
ptDir.z= ptRef.z- ptEye.z;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); //重置当前的模型观察矩阵
gluLookAt( ptEye.x, ptEye.y, ptEye.z, ptRef.x, ptRef.y, ptRef.z, 0, 1.0f, 0.0f);
glGetDoublev( GL_MODELVIEW_MATRIX, adModelMatrix[ 0]);//获取模視矩陣
glLoadIdentity(); //重置当前的模型观察矩阵
constdouble PI= 3.14159265358979;
double a1= 90- acos( ptDir.y/ sqrt(ptDir.z* ptDir.z+ ptDir.x* ptDir.x+ ptDir.y* ptDir.y))
* 180/ PI;//竖直角度
double dx= -ptDir.x, dz= -ptDir.z;
double a2= acos( dz/ sqrt( dz* dz+ dx* dx)) * 180/ PI;//水平角度
if ( dx < 0)
{
a2= -a2;
}
glRotatef(-a1,1.0f,0.0f,0.0f);//绕x轴旋转-a1,如-45度
glRotatef(-a2,0.0f,1.0f,0.0f);//绕y轴旋转-a2,如-60度
glTranslatef(-ptEye.x, -ptEye.y, -ptEye.z);//反向平移
glGetDoublev( GL_MODELVIEW_MATRIX, adModelMatrix[ 1]);//模視矩陣
for (int i= 0; i< 16; ++i)
{
if ( abs(adModelMatrix[ 1][ i] - adModelMatrix[ 0][ i] ) >= 1e-4)
{
float t= 0;
++t;
}
}
//经验证,gluLookAt的模视矩阵确实能由glTranslate,glRotate实现,glRotate旋转时对角度有误差,
//但不是很大,一般可在e-4内.
―――――
获取模视矩阵:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( -2.0f, 0.0f, 0.0f, -2.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);
double adModelMatrix[ 16];
glGetDoublev( GL_MODELVIEW_MATRIX, adModelMatrix);//获取模視矩陣
/*此例中的模视矩阵为:
1 0 0 2
0 1 0 0
0 0 1 0
0 0 0 1
*/
如下图:
可以看出gluLookAt()将视点由(0,0,0)向左移动到(-2,0,0),相当于模视矩阵MV为向右移动2个单位。模视矩阵MV是作用于物体点的,对点p,它在视点坐标系下的新点p’=MV*p,相当于把物体向右移动2个单元,也即视点向左移动2个单元。就是说,对视点(及其局部opengl坐标系)经过先平移T、再旋转R后,得到的综合变换矩阵为A(如A=T*R),则最终设置的视图矩阵实际为setViewMatrix(A~)。
附:
OpenGL中的矩阵:
m[0] m[4] m[8] m[12]
m[1] m[5] m[9] m[13]
m[2] m[6] m[10] m[14]
m[3] m[7] m[11] m[15]
//
完整源代码如下:
#include<windows.h>
#include<cmath>
//my addings
#include<gl/gl.h>
#include<gl/glu.h>
#pragmacomment(lib,"opengl32.lib")
#pragmacomment(lib,"glu32.lib")
HDC g_hDC=NULL; // 窗口着色描述表句柄
HGLRC g_hRC=NULL; // OpenGL渲染描述表句柄
HWND g_hWnd=NULL; // 保存我们的窗口句柄
HINSTANCE g_hInstance;
static TCHAR szAppName[] = TEXT ("HelloWin") ; //程序标题
struct Vec3
{
float x;
float y;
float z;
};
//#include <GL/glaux.h>
//#include <gl/glut.h> //包含OpenGL实用库
//#pragma comment(lib, "glaux.lib")
//my addings
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
ATOM RegistWnd( HINSTANCE hInstance);//注册窗口
BOOL InitWnd( HINSTANCE hInstance,int iCmdShow);//窗口初始化
GLvoid ReSizeGLScene(GLsizei width, GLsizei height); //重置OpenGL窗口大小
int InitGL(GLvoid) ; // 此处开始对OpenGL进行所有设置
int DrawGLScene(GLvoid) ; // 从这里开始进行所有的绘制
GLvoid KillGLWindow(GLvoid) ; // 正常销毁窗口