立體顯示原理:設沒有立體顯示的模型視圖矩陣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,
如:沒有立體顯示,視點位於就是中間的藍色位置,立體顯示就是將左眼(紅色),右眼(綠色)的視圖分開繪製。
程式中左眼用紅色去畫,右眼同時用綠色和藍色繪製。
代碼:
/*<br /> * @(#)$Id: SteroShow.cpp [4/24/2008 RenYaFei] dizuo@126.com $<br /> * @(#)基於OpenGL的立體顯示實現<br /> * Author: Dizuo.Hangzhou.<br /> * All Rights Reserved.<br /> */<br />#include <GL/glut.h><br />#include <math.h><br />void init(void)<br />{<br /> GLfloat mat_diffuse[] = { 1.0, 1.0, 0.0 };<br /> GLfloat mat_specular[] = {0.8, 0.8, 0.0, 1.0};<br /> GLfloat mat_shininess[] = { 300. };<br /> GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };<br /> GLfloat light_diffuse[] = { 1.0, 1.0, 0.0 };<br /> GLfloat light_ambient[] = {0.7, 0.2, 0.2, 1.0};</p><p> glClearColor (0.0, 0.0, 0.0, 0.0);<br /> glShadeModel (GL_SMOOTH);</p><p> glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);<br /> glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);<br /> glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);<br /> glLightfv(GL_LIGHT0, GL_POSITION, light_position);<br /> glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);<br /> glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);</p><p> glEnable(GL_LIGHTING);<br /> glEnable(GL_LIGHT0);<br /> glEnable(GL_DEPTH_TEST);<br />}<br />/**//*----------------------------------------------------------------------------<br />* 初始化參數<br />*/<br />GLfloat PI=3.1415926;<br />GLfloat Fd=5.0; //fusion distance<br />GLfloat RealScreenToEyeDistance=1.0;<br />GLfloat R=Fd/RealScreenToEyeDistance; //比例尺 R = Fd / RealScreenToEyeDistance<br />GLfloat Sd=0.05; //兩眼之間的距離<br />GLfloat aspect=1.0; //gluLookAt函數裡面的參數<br />GLfloat fovy=60.0; //張角<br />GLfloat f=1/tan( (fovy*PI)/(2*180) ); //f=ctg(fovy/2);</p><p>//列優先的矩陣模型視圖矩陣,投影矩陣<br />GLfloat LeftModelViewMatrix[16]={<br /> 1.0, 0.0, 0.0, 0.0,<br /> 0.0, 1.0, 0.0, 0.0,<br /> 0.0, 0.0, 1.0, 0.0,<br /> Sd*R/2.0, 0.0, 0.0, 1.0<br />};</p><p>GLfloat LeftProjectMatrix[16]={<br /> 1.0, 0.0, 0.0, 0.0,<br /> 0.0, 1.0, 0.0, 0.0,<br /> 0.0, 0.0, 1.0, 0.0,<br /> -(Sd*f) / (2.0*Fd*aspect), 0.0, 0.0, 1.0<br />};</p><p>GLfloat RightModelViewMatrix[16]={<br /> 1.0, 0.0, 0.0, 0.0,<br /> 0.0, 1.0, 0.0, 0.0,<br /> 0.0, 0.0, 1.0, 0.0,<br /> -Sd*R/2.0, 0.0, 0.0, 1.0<br />};</p><p>GLfloat RightProjectMatrix[16]={<br /> 1.0, 0.0, 0.0, 0.0,<br /> 0.0, 1.0, 0.0, 0.0,<br /> 0.0, 0.0, 1.0, 0.0,<br /> (Sd*f) / (2.0*Fd*aspect), 0.0, 0.0, 1.0<br />};</p><p>//for the use of rotating<br />static GLfloat spin = 0.0;</p><p>void display(void)<br />{<br /> GLfloat matrix[16]={0.};</p><p> glColorMask(1.0, 1.0,1.0,1.0);<br /> glClearColor(0.0,0.0,0.0,1.0);<br /> glClearDepth(1.0);</p><p> glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);<br /> glColor3f(1.0, 1.0, 1.0);</p><p> //---------------------------------------------------------------------------------------------<br /> //Left Viewport<br /> glMatrixMode(GL_PROJECTION);<br /> glPushMatrix();<br /> glGetFloatv(GL_PROJECTION_MATRIX, matrix);<br /> glLoadIdentity();<br /> glMultMatrixf(LeftProjectMatrix);<br /> glMultMatrixf(matrix);</p><p> glMatrixMode(GL_MODELVIEW);<br /> glLoadIdentity();<br /> glTranslated(0.0, 0.0, -Fd);<br /> glPushMatrix();<br /> {<br /> glGetFloatv(GL_MODELVIEW_MATRIX, matrix);<br /> glLoadIdentity();<br /> glMultMatrixf(LeftModelViewMatrix);<br /> glMultMatrixf(matrix);<br /> glColorMask(1.0, 0.0, 0.0, 1.0);<br /> /**//*<br /> * 物體的座標Vp<br /> * 變換到螢幕座標:Vp'= LeftProjectMatrix×Mp × LeftModelViewMatrix×Mv × Mr×Vp<br /> */<br /> glPushMatrix();<br /> {<br /> glRotatef(spin, 0.0, 1.0, 0.0); glutSolidTeapot(1.0);<br /> }<br /> glPopMatrix();<br /> }<br /> glPopMatrix();<br /> glMatrixMode(GL_PROJECTION);<br /> glPopMatrix();<br /> glFlush(); </p><p> //---------------------------------------------------------------------------------------------<br /> //Right Viewport<br /> glMatrixMode(GL_PROJECTION);<br /> glPushMatrix();<br /> glGetFloatv(GL_PROJECTION_MATRIX, matrix);<br /> glLoadIdentity();<br /> glMultMatrixf(RightProjectMatrix);<br /> glMultMatrixf(matrix);</p><p> glMatrixMode(GL_MODELVIEW);<br /> glPushMatrix();<br /> {<br /> glGetFloatv(GL_MODELVIEW_MATRIX, matrix);<br /> glLoadIdentity();<br /> glMultMatrixf(RightModelViewMatrix);<br /> glMultMatrixf(matrix);</p><p> glColorMask(0.0, 1.0, 1.0, 1.0);<br /> glClearDepth(1.0);<br /> glClear(GL_DEPTH_BUFFER_BIT);<br /> /**//*<br /> * 物體的座標Vp<br /> * 變換到螢幕座標:Vp'= RightProjectMatrix×Mp× RightModelViewMatrix×Mv × Mr×Vp<br /> */<br /> glPushMatrix();<br /> {<br /> glRotatef(spin, 0.0, 1.0, 0.0);<br /> glutSolidTeapot(1.0);<br /> //glutSolidSphere(1.0, 20, 5);<br /> }<br /> }<br /> glPopMatrix();</p><p> glMatrixMode(GL_PROJECTION);<br /> glPopMatrix();<br /> glFlush ();</p><p> glutSwapBuffers();<br />}</p><p>void reshape (int w, int h)<br />{<br /> glViewport (0, 0, (GLsizei) w, (GLsizei) h);<br /> glMatrixMode (GL_PROJECTION);<br /> glLoadIdentity();<br /> //投影矩陣:Mp<br /> gluPerspective(fovy, (GLfloat)w/(GLfloat)h, 1.0, 20.0);<br />}<br />void spinDisplay(void)<br />{<br /> spin = spin + 1.0;<br /> if (spin > 360.0)<br /> spin = spin - 360.0;<br /> glutPostRedisplay();<br />}</p><p>int main(int argc, char** argv)<br />{<br /> glutInit(&argc, argv);<br /> glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);<br /> glutInitWindowSize (500, 500);<br /> glutInitWindowPosition (100, 100);<br /> glutCreateWindow (argv[0]);<br /> init ();<br /> glutDisplayFunc(display);<br /> glutReshapeFunc(reshape);<br /> glutIdleFunc(spinDisplay);<br /> glutMainLoop();<br /> return 0;<br />}
相關立體顯示連結:http://local.wasp.uwa.edu.au/~pbourke/projection/stereorender/