https://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/
Tutorial 2 : The first triangle
This will be another long tutorial. OpenGL 3 makes it easy to write complicated stuff, but at the expense that drawing a simple triangle is actually quite difficult. Don’t forget to cut’n paste the code on a regular basis. If the program crashes at sta
www.opengl-tutorial.org
1. VAO
2. 화면 좌표
3. 삼각형 그리기
4. 셰이더 (컴파일 / 버텍스 셰이더 / 프래그먼트 셰이더)
5. 모두 합치기
* 예시 코드
* 코드 설명
1) 삼각형 그리기
* VAO : Vertex Array Object(버텍스 배열 객체)
- 버텍스 속성들을 저장하는 객체를 생성하고 바인딩
- 창(OpenGL 컨텍스트)을 만든 후, 다른 OpenGL을 호출하기 전에 해당 작업 수행
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
* 화면 좌표
3D 그래픽 - 점 : 정점(vertex, vertices)으로 표현
-> 삼각형 : 세 개의 점으로 정의
=> 정점 : X, Y, Z의 세 개의 좌표가 있음
<삼각형 세 좌표 (+ 오른손 법칙)>
X : 오른쪽 / 엄지 손가락
Y : 위 / 검지 손가락
Z : 뒤쪽 (앞쪽 x) / 중지

-> 오른손 법칙의 유일한 단점 : 직관적이지 않은 Z
- 유의 : 손 = 자유롭게 움직일 수 있음 ! (= X, Y, Z도 마찬가지)
- 삼각형을 만들기 위한 정점 데이터 (3개의 3차원 점)
// An array of 3 vectors which represents 3 vertices
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f, // 왼쪽 아래
1.0f, -1.0f, 0.0f, // 오른쪽 아래
0.0f, 1.0f, 0.0f // 상단 중앙
};

* 삼각형 그리기
- GPU 메모리에 버텍스 데이터를 저장하기 위한 버퍼를 생성, 데이터 전송
// 정점 버퍼 식별
GLuint vertexbuffer;
// 버퍼 1개 생성, 결과 식별자를 버텍스 버퍼에 넣음
glGenBuffers(1, &vertexbuffer);
// '버텍스 버퍼' 버퍼
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
// 정점을 OpenGL에 전송
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
- 렌더링 내부 : 그리기
// 쉐이더 프로그램 사용
glUseProgram(programID);
// 버텍스 속성 활성화 및 설정
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // 속성 0
3, // 크기
GL_FLOAT, // 데이터 타입
GL_FALSE, // 정규화 여부
0, // stride
(void*)0 // 오프셋
);
// 삼각형 그리기
glDrawArrays(GL_TRIANGLES, 0, 3); // 버텍스 0에서 시작, 3 버텍시스 -> 삼각형 1
glDisableVertexAttribArray(0); // 버텍스 속성 비활성화
* 정리 코드 (마지막)
프로그램 종료 전, 생성했던 OpenGL 객체들을 정리
glDeleteBuffers(1, &vertexbuffer); // 버퍼 정리
glDeleteVertexArrays(1, &VertexArrayID); // VAO 정리
glDeleteProgram(programID); // 쉐이더 프로그램 정리
2) 셰이더
가능한 가장 간단한 구성 : 두 개의 셰이더
- Vertex Shader : 각 정점에 대해 실행
- Fragment Shader : 각 샘플에 대해 실행
-> 4x 앤티앨리어싱을 사용하므로, 각 픽셀에 4개의 샘플이 있음
* 셰이더 : GLSL 언어로 프로그래밍됨
- GLSL (GL Shader Language) : OpenGL의 일부
- GLSL : 런타임에 컴파일해야 함
-> 애플리케이션을 실행할 때마다 모든 셰이더가 다시 컴파일 됨 !
- 직접 액세스할 수 없음 (버퍼와 마찬가지)
- ID만 있음 (실제 구현 : 드라이버 내부에 숨겨져 있음)
* 셰이더 컴파일 (common/loadShader.cpp)
// 프로그램에서 한 번만 이 작업을 하는 경우가 많으므로, 완전히 이해할 필요 x
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){
// 셰이더 생성
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// 파일에서 버텍스 셰이더 코드 읽어오기
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open()){
std::stringstream sstr;
sstr << VertexShaderStream.rdbuf();
VertexShaderCode = sstr.str();
VertexShaderStream.close();
}else{
printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path);
getchar();
return 0;
}
// 파일에서 프래그먼트 셰이더 코드 읽어오기
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::stringstream sstr;
sstr << FragmentShaderStream.rdbuf();
FragmentShaderCode = sstr.str();
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// 버텍스 셰이더 컴파일
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// 버텍스 셰이더 체크
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// 프래그먼트 셰이더 컴파일
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// 프래그먼트 셰이더 체크
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// 프로그램 링크
printf("Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// 프로그램 체크
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
std::vector<char> ProgramErrorMessage(InfoLogLength+1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
* 버텍스 셰이더 (정점 셰이더)
#version 330 core
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}
* 프래그먼트 셰이더
- 각 프래그먼트의 색상을 빨간색으로 설정
- vec3(1, 0, 0) : 녹색, 파란색 없는 완전한 빨간색
#version 330 core
out vec3 color;
void main(){
color = vec3(1,0,0); // red
}
* 에러

* 파일 위치 : 같은 디렉터리 내, 셰이더 파일들 존재

* Run/Debug Configurations 수정
Working directory : 셰이더 파일들이 있는 디렉터리로 지정

* 실행결과
- 빨간색 삼각형 (예제)

- 다른 색
검정색
color = vec3(0,0,0);
흰색
color = vec3(1,1,1);
베이비핑크
color = vec3(1.0, 0.714, 0.757); // Baby pink color (255, 182, 193)



'공부 > OpenGL' 카테고리의 다른 글
| [OpenGL Tutorial]5. 텍스쳐가 입혀진 큐브 (0) | 2024.11.11 |
|---|---|
| [OpenGL Tutorial]4. 컬러 큐브 (0) | 2024.11.08 |
| [OpenGL Tutorial]3. 첫 번째 삼각형 (행렬) (2) | 2024.11.07 |
| [OpenGL Tutorial]1. 윈도우 열기 (2) | 2024.11.04 |
| OpenGL로 배우는 3차원 컴퓨터 그래픽스 - 목차 / 단원별 요약 (1) | 2024.11.02 |