C\C++/OpenGL

C/C++ OpenGl을 이용한 간단한 태양계 구축 프로젝트(2)

sundori 2023. 11. 18. 20:25

2023.11.08 - [C\C++/OpenGL] - C/C++ OpenGl을 이용한 간단한 태양계 구축 프로젝트(1)

 

C/C++ OpenGl을 이용한 간단한 태양계 구축 프로젝트(1)

Windows MFC (Microsoft Foundation Classes)를 사용하여 OpenGL을 초기화하고 간단한 2D 그래픽을 렌더링 하는 뷰 클래스를 사용하여 간단한 태양계 구축하기. 이번에는 OpenGL을 사용하여 태양계 모델링을 구

sun-dori.tistory.com

저번 글에 이어서 이번에는 조명 효과를 넣어보고자 한다.

 

OpenGL 조명 효과

조명의 종류

  • 주변광 (Ambient Light) : 모든 방향에서 나타나는 조명으로 모든 물체에 균일하게 영향을 미친다.
    주변 어디에서나 나오는 일반적인 빛을 말하는데 물체 전체를 약간 밝게 만들어 물체가 어두운 부분이 너무 어두워 보이지 않게 한다. 따라서 이 광원은 특정 방향이나 위치를 가지지 않고, 모든 방향에서 일정하게 오는 광이며, 물체에 균일하게 분포되는 광을 표현하며, 물체의 입체감을 유지하는데 사용한다.

  • 난반사광 (Diffuse Light) : 난방사광은 한 방향으로부터 나오는 조명으로, 표면의 범선과 빛의 방향 간의 각도에 의해 직접 조명을 조절한다. 이는 물체에서 나오는 빛이 여기저기 흩어지는 것을 말하며, 물체의 입체감을 나타내며 흩어지는 정도에 따라 물체의 표면이 부드럽게 느껴지거나 조각조각해 보이는 느낌을 주기에 물체에서 나오는 빛이 물체 표면과 상호작용하여 여러 방향으로 퍼져나가며 이 난방사 광의 양은 표면이 빛을 얼마나 많이 흡수하고 반사하는지에 따라 결정한다.

 

  • 전반사광 (Specular Light) : 전반사광은 한 방향으로만 반사되는 조명으로, 물체의 표면에서 빛의 반사로 인한 빛의 반사를 나타낸다.  이 반사광은 물체의 소재 특성과 뷰어의 위치에 따라 달라진다.
    빛이 물체 표면에서 반사되어 특정 방향으로 빛나는 것을 말하는데 이는 광택이 생기는 효과, 표면이 빛에 부딪혀 빛나거나 광택이 나는 효과를 주며 물체의 표면에서 나온 빛 중 특정 방향으로 집중이 되기에 물체의 표면에서 높이나 뾰족함을 강조하는 데 사용한다.

밑에 사진을 자세히 들여다보면 미세하게 선이 보일 것이다. 이는 광원이 구의 중심점을 향하고 있다는 의미이다.

공부를 하다가 각각의 광이 무슨 차이를 가지고 있는지 이해가 제대로 되지를 않아 이렇게 코드로 작성해보았다.

빛과 재질 사이의 상호작용

  • 전반사면 (Specular Reflection) : 전반사면은 위에 설명한 것처럼 물체 표면에서 빛이 반사되어 특정 방향으로 향하는 것을 말하며, 광택이나 빛의 반사를 모델링하는 데 사용하며, 표면이 매우 매끄럽고 광택 나는 물체에 주로 나타난다.

 

  • 난반사면 (Diffuse Reflection) : 물체에서 나오는 빛이 다른 물체의 표면과 상호작용하여 여러 방향으로 흩어지는 현상을 구현할 때 사용하는데 표면의 입체감과 질감을 부여하는 데에 사용하고 물체의 표면에서 나온 빛이 무작위로 퍼져 나가는 것을 말한다.

 

  • 반투명면 (Transparency) : 빛이 물체를 통과하는 특성을 나타낼 때 사용하는데, 반투명한 물체는 빛을 일부 흡수하면서 일부는 투과함으로써 뒷 배경이나 뒤에 있는 물체를 볼 수 있게 하며 주로 유리, 물, 투명한 플라스틱과 같은 물체에 주로 나타난다.

전반사면, 난반사면, 반투명면

코드 구현

COpenGLView.h

// 구현입니다.
public:
	GLUquadricObj *m_objQuad; // 구를 그리기 위한 객체

	GLfloat m_fMoon;
	GLfloat m_fEarth;

//--이번 포스트에서 추가되는 부분
	GLfloat m_lightPos[4];
	GLfloat m_sourceLight[4];
	GLfloat m_whiteLight[4];
// ------------------------------

	HGLRC m_hRC;
	HDC m_hDC;

 

OpenGLView.cpp

// COpenGLView 생성/소멸

COpenGLView::COpenGLView() noexcept
{
	// TODO: 여기에 생성 코드를 추가합니다.
	//m_fAngle = 0.0;
	m_fEarth = 0.0;
	m_fMoon = 0.0;

//--이번 포스트에 추가된 부분
	m_whiteLight[0] = 0.2f;
	m_whiteLight[1] = 0.2f;
	m_whiteLight[2] = 0.2f;
	m_whiteLight[3] = 1.0f;

	m_sourceLight[0] = 0.8f;
	m_sourceLight[1] = 0.8f;
	m_sourceLight[2] = 0.8f;
	m_sourceLight[3] = 1.0f;

	m_lightPos[0] = 0.0f;
	m_lightPos[1] = 0.0f;
	m_lightPos[2] = 0.0f;
	m_lightPos[3] = 1.0f;
//---------------------------
}
//--이번 포스트에 변경 및 추가된 코드
void COpenGLView::SetupRC()
{
	// Quadric 객체 생성
	m_objQuad = gluNewQuadric();

	// Face culling 및 깊이 테스트 활성화
	glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);
	glFrontFace(GL_CCW);

	// 조명 활성화
	glEnable(GL_LIGHTING);

	// 주변 조명 설정
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, m_whiteLight);

	// 광원 속성 설정
	glLightfv(GL_LIGHT0, GL_DIFFUSE, m_sourceLight);
	glLightfv(GL_LIGHT0, GL_POSITION, m_lightPos);

	// LIGHT0 활성화
	glEnable(GL_LIGHT0);

	// 색상 자재 활성화 및 설정
	glEnable(GL_COLOR_MATERIAL);
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

	// 배경색 설정
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
//----------------------------------------------------
//-- 밑에 코드는 수정 전 코드
void COpenGLView::SetupRC()
{
    // 배경색을 검은색(R=0, G=0, B=0)으로 설정하고 투명도(alpha)는 1.0으로 설정
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // OpenGL 배경색을 설정
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

    // 그림자 모드를 설정
    glShadeModel(GL_FLAT);

    // 다각형의 정면을 설정
    glFrontFace(GL_CCW);

    // Quadric 객체를 생성하여 다양한 기하학적 도형을 그릴 수 있음
    m_objQuad = gluNewQuadric();

    // 타이머를 설정하여 200밀리초(0.2초)마다 Timer1 메시지를 생성
    SetTimer(1, 200, NULL);
}
void COpenGLView::RenderScene()
{
	// 색상 및 깊이 버퍼 지우기
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// 양면 제거 및 깊이 테스트 활성화
	glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);

	// 쿼드릭 노말을 플랫으로 설정
	gluQuadricNormals(m_objQuad, GLU_FLAT);

	// 현재 행렬 모드를 모델뷰로 설정
	glMatrixMode(GL_MODELVIEW);

	// 나중에 복원하기 위해 현재 행렬 저장
	glPushMatrix();

	// 광원 위치 설정 (LIGHT0 사용 중인 것으로 가정)
	glLightfv(GL_LIGHT0, GL_POSITION, m_lightPos); // 2023-11-14 추가

    // z 축을 따라 시점을 뒤로 이동
	glTranslatef(0.0f, 0.0f, -300.0f);

	// 태양을 나타내는 빨간 구 그리기
	glColor3ub(255, 0, 0);
	gluSphere(m_objQuad, 15, 64, 64);

	// 광원 위치 다시 설정 (LIGHT0 사용 중인 것으로 가정)
	glLightfv(GL_LIGHT0, GL_POSITION, m_lightPos); // 2023-11-14 추가

	// 지구를 나타내는 파란 구 그리기
	glColor3ub(0, 0, 255);

	// y 축 주위에 지구 회전
	glRotatef(m_fEarth, 0.0f, 0.1f, 0.0f);

	// 태양에서 지구로 이동
	glTranslatef(105.0f, 0.0f, 0.0f);

	// 지구 그리기
	gluSphere(m_objQuad, 15, 64, 64);

	// 달의 색상 설정
	glColor3ub(200, 200, 200);

	// 달을 지구 주위로 회전
	glRotatef(m_fMoon, 0.0f, 1.0f, 0.0f);

	// 지구에서 멀어지도록 이동
	glTranslatef(30.0f, 0.0f, 0.0f);

	// 달 그리기
	gluSphere(m_objQuad, 6, 64, 64);

	// 이전 행렬 복원
	glPopMatrix();
}

 

 

이렇게 조명을 넣음으로써 태양과 지구 그리고 달이 3D 물체처럼 느껴지게 되었다.