#include (gl glut.h)
#include (math.h)
#define DTOR 0.0174532925 //from degree to radian
// Light and material Data
GLfloat fLightPos[4] = { -100.0f, 100.0f, 50.0f, 1.0f }; // Point source
GLfloat fLightPosMirror[4] = { -100.0f, -100.0f, 50.0f, 1.0f };
GLfloat fNoLight[] = { 0.0f, 0.0f, 0.0f, 0.0f };
GLfloat fLowLight[] = { 0.25f, 0.25f, 0.25f, 1.0f };
GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat yRot = 0.0f; // Rotation angle for animation
static GLfloat zRot = 3.0f; // Rotation angle for animation
static GLfloat zRot_step = 0.1f;
static GLfloat eyePosition[3] = { 0.0f, 0.0f, 4.0f}; // move the camera
typedef enum {LEFT, RIGHT} EyeMode;
void setStereoPerspective(GLdouble fovy, GLdouble aspect, GLdouble znear, GLdouble zfar, GLdouble focalLength, GLdouble eyeSep, EyeMode eyeMode)
/*스테레오스코픽 투시도법 함수 사용자지정*/
{
GLdouble left;
GLdouble right;
GLdouble top = znear*tan(DTOR*fovy/2); // y clipping plane의 0부터의 거리를 계산 // fovy : y방향의 시야각 영역 // znear : 가까운 clipping거리 // zfar : 먼 클리핑거리
GLdouble bottom = -top;
GLdouble halfznearWidth = aspect*top; // aspect에 기초한 x clipping의 0부터의 거리를 계산 // aspect : viewport의 종횡비
GLdouble stereoAdjustment = eyeSep/2*znear/focalLength; // equation 연립에 의한 계산식
if(RIGHT == eyeMode)
{
left = -halfznearWidth - stereoAdjustment; // 오른쪽눈의 left, right 정의
right = halfznearWidth - stereoAdjustment;
}
else
{
left = -halfznearWidth + stereoAdjustment; // 왼쪽눈의 left, right 정의
right = halfznearWidth + stereoAdjustment;
}
glFrustum(left, right, bottom, top, znear, zfar);
/*glFrustum 절두체 즉, 전체공간상에서 랜더링해야하는 공간만을 잘라낸 것, 6개의 인자를 가지며,
첫번째와 두번째는 절두체를 구성하는 왼쪽과 오른쪽의 수직 평면이며 세번째와 네번째는 위와 아래의 수평평면,
다섯번째와 여섯번째는 절두체를 구성하는 시선과 수직인 평면으로써 가장 가까운것과 먼것(반드시 양수)*/
}
void setStereoLookAt(GLdouble eyeX,GLdouble eyeY, GLdouble eyeZ, GLdouble centreX, GLdouble centreY, GLdouble centreZ, GLdouble upX, GLdouble upY, GLdouble upZ, GLdouble eyeSep, GLdouble eyeMode)
/*단순히 카메라는 약간씩 왼쪽 그리고 오른쪽으로 이동한다. 불행히도 어느방향이 왼쪽 오른쪽인지 3D 모델 공간에서는 사실상 알 수 없다.
그러나 우리는 이런 약간의 방향들을 데이터를 Input하여 계산해 LookAt함수에 기존의 좌표에 더해줄 수 있다.
그렇게 해서 stereoLookAt 함수값이 셋팅된다.*/
{
GLdouble inX = centreX - eyeX;
GLdouble inY = centreY - eyeY;
GLdouble inZ = centreZ - eyeZ;
GLdouble factor = (eyeMode == RIGHT)?1:-1;
// eyeMode에서 들어오는값 Right는 1 Left는 -1을 factor인자에 대입하여 오른쪽 왼쪽을 계산
GLdouble realEyeCorX = factor*(inY*upZ - upY*inZ);
GLdouble realEyeCorY = factor*(inZ*upX - upZ*inX);
GLdouble realEyeCorZ = factor*(inX*upY - upX*inY); //vector cross product of "in" with "up"
GLdouble length = sqrt(realEyeCorX*realEyeCorX + realEyeCorY*realEyeCorY + realEyeCorZ*realEyeCorZ);
//realEyeCor 벡터의 길이값 계산
GLdouble corLengthFactor = eyeSep/(2*length); // 축소비 지정
realEyeCorX *=corLengthFactor;
realEyeCorY *=corLengthFactor;
realEyeCorZ *=corLengthFactor; // 각 realEyeCor 좌표에 축소비를 곱해서 누적연산
gluLookAt(eyeX + realEyeCorX, eyeY + realEyeCorY, eyeZ + realEyeCorZ, centreX, centreY, centreZ, upX, upY, upZ);
/* EyeMode가 right이면 realEyeCor은 양수 , left이면 음수*/
/*모델과 Eye와의 거리값에 따른 카메라 시선의 위치가 약간씩 변함*/
/*첫번째 xyz좌표는 바라보는 시선의 위치, 두번째xyz죄표는 모델의 위치, 세번째는 모델의 top 좌표(모델의 꼭대기부분이 바라보는 좌표위치)*/
}
void SetupRC()
{
// Grayish background
glClearColor(fLowLight[0], fLowLight[1], fLowLight[2], fLowLight[3]);
// Cull backs of polygons
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
// Setup light parameters
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fNoLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, fLowLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, fBrightLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
// Mostly use material tracking
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glMateriali(GL_FRONT, GL_SHININESS, 128);
}
void DrawGround(void)
{
GLfloat fExtent = 20.0f;
GLfloat fStep = 0.5f;
GLfloat y = 0.0f;
GLfloat fColor;
GLfloat iStrip, iRun;
GLint iBounce = 0;
glShadeModel(GL_FLAT);
for(iStrip = -fExtent; iStrip <= fExtent; iStrip += fStep)
{
glBegin(GL_TRIANGLE_STRIP);
for(iRun = fExtent; iRun >= -fExtent; iRun -= fStep)
{
if((iBounce %2) == 0)
fColor = 1.0f;
else
fColor = 0.0f;
glColor4f(fColor, fColor, fColor, 0.5f);
glVertex3f(iStrip, y, iRun);
glVertex3f(iStrip + fStep, y, iRun);
iBounce++;
}
glEnd();
}
glShadeModel(GL_SMOOTH);
}
void DrawCube(void)
{
//glLoadIdentity(); // Reset The View
glPushMatrix();
{
glTranslatef(-1.5f,0.0f,-zRot/5.0f); // Move Left And Into The Screen
glRotatef(yRot,0.0f,1.0f,0.0f); // Rotate The Pyramid On It's Y Axis
glBegin(GL_TRIANGLES); // Start Drawing The Pyramid
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Front)
glColor3f(0.0f,1.0f,0.0f); // Green
glVertex3f(-1.0f,-1.0f, 1.0f); // Left Of Triangle (Front)
glColor3f(0.0f,0.0f,1.0f); // Blue
glVertex3f( 1.0f,-1.0f, 1.0f); // Right Of Triangle (Front)
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Right)
glColor3f(0.0f,0.0f,1.0f); // Blue
glVertex3f( 1.0f,-1.0f, 1.0f); // Left Of Triangle (Right)
glColor3f(0.0f,1.0f,0.0f); // Green
glVertex3f( 1.0f,-1.0f, -1.0f); // Right Of Triangle (Right)
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Back)
glColor3f(0.0f,1.0f,0.0f); // Green
glVertex3f( 1.0f,-1.0f, -1.0f); // Left Of Triangle (Back)
glColor3f(0.0f,0.0f,1.0f); // Blue
glVertex3f(-1.0f,-1.0f, -1.0f); // Right Of Triangle (Back)
glColor3f(1.0f,0.0f,0.0f); // Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top Of Triangle (Left)
glColor3f(0.0f,0.0f,1.0f); // Blue
glVertex3f(-1.0f,-1.0f,-1.0f); // Left Of Triangle (Left)
glColor3f(0.0f,1.0f,0.0f); // Green
glVertex3f(-1.0f,-1.0f, 1.0f); // Right Of Triangle (Left)
glEnd(); // Done Drawing The Pyramid
}
glPopMatrix();
glPushMatrix();
{
//glLoadIdentity();
glTranslatef(1.5f,0.0f,zRot); // Move Right And Into The Screen
glRotatef(-yRot,1.0f,1.0f,1.0f); // Rotate The Cube On X, Y & Z
glBegin(GL_QUADS); // Start Drawing The Cube
glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Top)
glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Top)
glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Quad (Top)
glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Quad (Top)
glColor3f(1.0f,0.5f,0.0f); // Set The Color To Orange
glVertex3f( 1.0f,-1.0f, 1.0f); // Top Right Of The Quad (Bottom)
glVertex3f(-1.0f,-1.0f, 1.0f); // Top Left Of The Quad (Bottom)
glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Bottom)
glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Bottom)
glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Front)
glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Front)
glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Front)
glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Front)
glColor3f(1.0f,1.0f,0.0f); // Set The Color To Yellow
glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Back)
glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Back)
glVertex3f(-1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Back)
glVertex3f( 1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Back)
glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Left)
glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Left)
glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Left)
glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Left)
glColor3f(1.0f,0.0f,1.0f); // Set The Color To Violet
glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Right)
glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Right)
glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Right)
glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Right)
glEnd();
}
// Done Drawing The Quad
/*glTranslatef(0.0f, 0.5f, -3.5f);
glPushMatrix();
glRotatef(-yRot * 2.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(1.0f, 0.0f, 0.0f);
glutSolidSphere(0.1f, 17, 9);
glPopMatrix();
glRotatef(yRot, 1.0f, 1.0f, 1.0f);
glutWireCube(0.5f);*/
glPopMatrix();
}
GLvoid RenderScene(EyeMode eyeMode)
{
double fovy = 50.0f; // y방향의 시야각 영역
double aspect = 4/3; // 종횡비
double znear = 1.0f; // 가까운 clipping거리
double zfar = 30.0f; // 먼 clipping거리
double focalLength = 1.5f;
double eyeSep = 0.03;// 왼쪽과 오른쪽눈의 거리
//double eyeX = 0.0f;
//double eyeY = 0.0f;
//double eyeZ = 4.0f; // eye position
double centreX = 0.0f;
double centreY = 0.0f;
double centreZ = -10.0f; // 모델의 중심위치, centre position
double upX = 0.0f;
double upY = 1.0f;
double upZ = 0.0f; // 모델의 top을 바라보는 좌표
glLoadIdentity();//Identity matrix Initializing
setStereoPerspective(fovy, aspect, znear, zfar, focalLength, eyeSep, eyeMode);
setStereoLookAt(eyePosition[0], eyePosition[1], eyePosition[2], centreX, centreY, centreZ, upX, upY, upZ, eyeSep, eyeMode);
//스테레오스코픽 투시도법 함수호출
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
{
glScalef(0.5f,0.5f,0.5f);
glLightfv(GL_LIGHT0, GL_POSITION, fLightPosMirror);
glFrontFace(GL_CCW);
DrawCube();
glPushMatrix();
glFrontFace(GL_CW); // geometry is mirrored, swap orientation
glScalef(1.0f, -1.0f, 1.0f);
DrawCube();
glFrontFace(GL_CCW);
glPopMatrix();
glTranslatef(0.0f,-2.0f,0.0f);
DrawGround();
//glDisable(GL_LIGHTING);
//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glDisable(GL_BLEND);
//glEnable(GL_LIGHTING);
}
glPopMatrix();
}
GLvoid display(GLvoid)
{
glDrawBuffer(GL_BACK);
glClear(GL_COLOR_BUFFER_BIT);
/*각 눈에 하나씩 뿌려주기 위한 버퍼의 분리*/
/*Left Eye를 뿌림*/
glDrawBuffer(GL_BACK_LEFT);
RenderScene(LEFT);
/*Right Eye를 뿌림*/
glDrawBuffer(GL_BACK_RIGHT);
RenderScene(RIGHT);
glutSwapBuffers();
}
void TimerFunction(int value)
{
yRot += 1.0f; // Update Rotation
// Redraw the scene
glutPostRedisplay();
// Reset timer
glutTimerFunc(1,TimerFunction, 1);
}
void TimeFunction_Zaxis(int value)
{
if(zRot >= 3.0f || zRot <= -20.0f)
{
zRot_step = -zRot_step;
}
zRot += zRot_step;
glutPostRedisplay();
glutTimerFunc(1,TimeFunction_Zaxis,1);
}
void KeyPressFunc(unsigned char key, int x, int y)
{
switch (key)
{
case 'x':
eyePosition[0] += 0.1f;
break;
case 'X':
eyePosition[0] -= 0.1f;
break;
case 'y':
eyePosition[1] += 0.1f;
break;
case 'Y':
eyePosition[1] -= 0.1f;
break;
case 'z':
eyePosition[2] += 0.1f;
break;
case 'Z':
eyePosition[2] -= 0.1f;
break;
case 'q':
case 'Q':
case 27 : /* ESC */
exit(0);
}
// Refresh the Window
glutPostRedisplay();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH /*| GLUT_STEREO*/);
glutInitWindowSize(1000,800);
glutCreateWindow("Cube & Stereo");
glutDisplayFunc(display);
glutKeyboardFunc(KeyPressFunc);
glutTimerFunc(10, TimerFunction, 1);
glutTimerFunc(10, TimeFunction_Zaxis, 1);
SetupRC();
glutMainLoop();
return 0;
}