立體顯示原理:設沒有立體顯示的模型視圖矩陣ModelView為Mv,投影矩陣為Mp,則、物體空間的任何一點為P,則變換到屏幕坐標P*=Mp×Mv×P;注意前面已經說過opengl裡面坐標列優先,所以矩陣都是右乘。
左眼和右眼的變換都是由中間的變換矩陣變換而來,則立體顯示中左眼的變換矩陣公式為:
P(L)*=Ms(L) × Mp(L) × Mt(L) × Mv(L) × P;
右眼的矩陣變換公式為:
P(R)*=Ms(R) × Mp(R) × Mt(R) × Mv(R) × P;
其中Ms,Mt是立體顯示需要而增加的變換。
程序裡面有幾個參數,現實世界眼睛到屏幕的距離Fd,兩眼之間的距離Sd,比例尺R,如圖:
如上圖:沒有立體顯示,視點位於就是中間的藍色位置,立體顯示就是將左眼(紅色),右眼(綠色)的視圖分開繪制。
程序中左眼用紅色去畫,右眼同時用綠色和藍色繪制。
代碼:
/*
* @(#)$Id: SteroShow.cpp [4/24/2008 RenYaFei] [email protected] $
* @(#)基於OpenGL的立體顯示實現
* Author: Dizuo.Hangzhou.
* All Rights Reserved.
*/
#include <GL/glut.h>
#include <math.h>
void init(void)
{
GLfloat mat_diffuse[] = { 1.0, 1.0, 0.0 };
GLfloat mat_specular[] = {0.8, 0.8, 0.0, 1.0};
GLfloat mat_shininess[] = { 300. };
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
GLfloat light_diffuse[] = { 1.0, 1.0, 0.0 };
GLfloat light_ambient[] = {0.7, 0.2, 0.2, 1.0};
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_SMOOTH);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}
/**//*----------------------------------------------------------------------------
* 初始化參數
*/
GLfloat PI=3.1415926;
GLfloat Fd=5.0; //fusion distance
GLfloat RealScreenToEyeDistance=1.0;
GLfloat R=Fd/RealScreenToEyeDistance; //比例尺 R = Fd / RealScreenToEyeDistance
GLfloat Sd=0.05; //兩眼之間的距離
GLfloat aspect=1.0; //gluLookAt函數裡面的參數
GLfloat fovy=60.0; //張角
GLfloat f=1/tan( (fovy*PI)/(2*180) ); //f=ctg(fovy/2);
//列優先的矩陣模型視圖矩陣,投影矩陣
GLfloat LeftModelViewMatrix[16]={
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
Sd*R/2.0, 0.0, 0.0, 1.0
};
GLfloat LeftProjectMatrix[16]={
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
-(Sd*f) / (2.0*Fd*aspect), 0.0, 0.0, 1.0
};
GLfloat RightModelViewMatrix[16]={
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
-Sd*R/2.0, 0.0, 0.0, 1.0
};
GLfloat RightProjectMatrix[16]={
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
(Sd*f) / (2.0*Fd*aspect), 0.0, 0.0, 1.0
};
//for the use of rotating
static GLfloat spin = 0.0;
void display(void)
{
GLfloat matrix[16]={0.};
glColorMask(1.0, 1.0,1.0,1.0);
glClearColor(0.0,0.0,0.0,1.0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
//---------------------------------------------------------------------------------------------
//Left Viewport
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glGetFloatv(GL_PROJECTION_MATRIX, matrix);
glLoadIdentity();
glMultMatrixf(LeftProjectMatrix);
glMultMatrixf(matrix);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslated(0.0, 0.0, -Fd);
glPushMatrix();
{
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
glLoadIdentity();
glMultMatrixf(LeftModelViewMatrix);
glMultMatrixf(matrix);
glColorMask(1.0, 0.0, 0.0, 1.0);
/**//*
* 物體的坐標Vp
* 變換到屏幕坐標:Vp'= LeftProjectMatrix×Mp × LeftModelViewMatrix×Mv × Mr×Vp
*/
glPushMatrix();
{
glRotatef(spin, 0.0, 1.0, 0.0); glutSolidTeapot(1.0);
}
glPopMatrix();
}
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glFlush();
//---------------------------------------------------------------------------------------------
//Right Viewport
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glGetFloatv(GL_PROJECTION_MATRIX, matrix);
glLoadIdentity();
glMultMatrixf(RightProjectMatrix);
glMultMatrixf(matrix);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
glLoadIdentity();
glMultMatrixf(RightModelViewMatrix);
glMultMatrixf(matrix);
glColorMask(0.0, 1.0, 1.0, 1.0);
glClearDepth(1.0);
glClear(GL_DEPTH_BUFFER_BIT);
/**//*
* 物體的坐標Vp
* 變換到屏幕坐標:Vp'= RightProjectMatrix×Mp× RightModelViewMatrix×Mv × Mr×Vp
*/
glPushMatrix();
{
glRotatef(spin, 0.0, 1.0, 0.0);
glutSolidTeapot(1.0);
//glutSolidSphere(1.0, 20, 5);
}
}
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glFlush ();
glutSwapBuffers();
}
void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
//投影矩陣:Mp
gluPerspective(fovy, (GLfloat)w/(GLfloat)h, 1.0, 20.0);
}
void spinDisplay(void)
{
spin = spin + 1.0;
if (spin > 360.0)
spin = spin - 360.0;
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
init ();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(spinDisplay);
glutMainLoop();
return 0;
}