
Gouraud Shader는 버텍스 셰이딩 방식으로 조명을 계산해서 부드러운 음영(Smooth Shading)을 만드는 기법.
버텍스마다 조명값을 계산하고 프래그먼트 셰이더에 컬러 값을 넘겨서 화면에 출력함.
Vertex Shading ( Gouraud ) VS Fragment Shading ( Phong )
Vertex Shading ( Gouraud ) | Fragment Shading (Phong) | |
조명 계산 위치 | **정점(Vertex)**에서 조명 계산 | 픽셀(Fragment)**마다 조명 계산 |
보간(interpolation) | 조명 결과(색상)를 보간 | 법선(Normal)**을 보간 → 픽셀에서 조명 계산 |
성능 | 빠름 (정점 수 적을수록 빠름) | 느림 (픽셀마다 계산하니까 연산 많음) |
품질 | 낮음 (하이라이트 등 디테일 손실 있음) | 높음 (부드럽고 정확한 조명 효과) |
버텍스 버퍼에 버텍스 포지션, 텍스처 좌표, 노말 3개의 값을 저장하여 어트리뷰트로 버텍스 셰이더로 넘겨주자.
stride = (2 * sizeof(vec3) )+ sizeof(vec2) + sizeof(vec4);
offsetTexCoord = ( GLvoid*) ( sizeof(glm::vec3) );
offset = ( GLvoid*) ( sizeof(glm::vec3) + sizeof(vec2) );
// Create the VBO for our obj model vertices.
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, objMeshModel->vertices.size() * sizeof(objMeshModel->vertices[0]), &objMeshModel->vertices[0], GL_STATIC_DRAW);
// Create the VAO, this will store the vertex attributes into vectored state.
glGenVertexArrays(1, &OBJ_VAO_Id);
glBindVertexArray(OBJ_VAO_Id)
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(VERTEX_POSITION);
glEnableVertexAttribArray(TEX_COORD);
glEnableVertexAttribArray(NORMAL_POSITION);
glVertexAttribPointer(VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, stride, 0);
glVertexAttribPointer(TEX_COORD, 2, GL_FLOAT, GL_FALSE, stride, offsetTexCoord);
glVertexAttribPointer(NORMAL_POSITION, 3, GL_FLOAT, GL_FALSE, stride, offset);
glBindVertexArray(0);
필요한 계수 및 색상
종류 | Uniform 이름 | GLSL 타입 | 설정 값 | 설명 |
Material | MaterialAmbient | vec3 | (0.1, 0.1, 0.1) | 주변광 반사 계수 (ambient reflectivity) |
Material | MaterialSpecular | vec3 | (1.0, 0.5, 0.5) | 정반사 반사 계수 (specular reflectivity) |
Material | MaterialDiffuse | vec3 | (0.75, 0.375, 0.0) | 난반사 반사 계수 (diffuse reflectivity) |
Material | ShininessFactor | float | 40 | 광택 계수 (shininess) |
Light | LightAmbient | vec3 | (1.0, 1.0, 1.0) | 광원의 주변광 (ambient light) |
Light | LightSpecular | vec3 | (1.0, 1.0, 1.0) | 광원의 정반사 성분 |
Light | LightDiffuse | vec3 | (1.0, 1.0, 1.0) | 광원의 난반사 성분 |
Light | LightPosView (LightPosition) | vec3 | (0, 10, 0) | 뷰 공간에서의 광원 위치 |
- Material : light의 반응 특성 ( 얼마나 밝아지는지, 하이라이트가 얼마나 보이는지 등 )
- Light : 광원의 색상과 세기
코드에서 uniform을 사용하여 다음과 같이 셰이더로 전달한다.
// -----------------------------
// Get Material property uniform variables
// -----------------------------
// Material의 Ambient 계수 uniform 위치 가져오기
char MaterialAmbient = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"MaterialAmbient");
// Material의 Specular 계수 uniform 위치 가져오기
char MaterialSpecular = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"MaterialSpecular");
// Material의 Diffuse 계수 uniform 위치 가져오기
char MaterialDiffuse = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"MaterialDiffuse");
// Material의 Shininess 계수 uniform 위치 가져오기
char ShininessFactor = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"ShininessFactor");
// -----------------------------
// Get Light property uniform variables
// -----------------------------
// Light의 Ambient 계수 uniform 위치 가져오기
char LightAmbient = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"LightAmbient");
// Light의 Specular 계수 uniform 위치 가져오기
char LightSpecular = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"LightSpecular");
// Light의 Diffuse 계수 uniform 위치 가져오기
char LightDiffuse = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"LightDiffuse");
// 뷰 공간 기준 Light 위치 uniform 위치 가져오기
char LightPosition = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"LightPosView");
// -----------------------------
// Set Material uniform values
// -----------------------------
if (MaterialAmbient >= 0) {
LOGI("MaterialAmbient Setting");
// 주변광 반사 계수: 어두운 회색
glUniform3f(MaterialAmbient, 0.1f, 0.1f, 0.1f);
}
if (MaterialSpecular >= 0) {
LOGI("MaterialSpecular Setting");
// 정반사 반사 계수: 빨간 기가 도는 흰색
glUniform3f(MaterialSpecular, 1.0f, 0.5f, 0.5f);
}
....
Vertex Shader Code
#version 300 es
// -------------------------------
// Vertex Attributes (입력 속성)
// -------------------------------
layout(location = 0) in vec4 VertexPosition; // 모델 공간에서 정점 위치
layout(location = 1) in vec3 Normal; // 모델 공간에서 노멀 벡터
// -------------------------------
// Uniforms (외부에서 전달되는 행렬/조명/재질 정보)
// -------------------------------
// 변환 행렬
uniform mat4 ModelViewProjectionMatrix; // MVP
uniform mat4 ModelViewMatrix; // MV
uniform mat3 NormalMatrix; // 노멀 벡터를 위한 변환 행렬 (MV 행렬의 상단 3x3)
// 재질 속성
uniform vec3 MaterialAmbient;
uniform vec3 MaterialSpecular;
uniform vec3 MaterialDiffuse;
uniform float ShininessFactor;
// 광원 속성
uniform vec3 LightAmbient;
uniform vec3 LightSpecular;
uniform vec3 LightDiffuse;
uniform vec3 LightPosView; // 뷰 공간에서의 광원 위치
// -------------------------------
// Varying (프래그먼트 셰이더로 넘김)
// -------------------------------
out vec4 FinalColor; // 정점 색상 출력 (인터폴레이션됨)
// -------------------------------
// Gouraud Shading 함수 (정점 단위)
// -------------------------------
vec3 GouraudShading()
{
vec3 nNormal = normalize(NormalMatrix * Normal); // 노멀을 뷰 공간 기준으로 정규화
vec3 vertexViewPos = vec3(ModelViewMatrix * VertexPosition); // 정점 위치를 뷰 공간으로 변환
// 광원 방향 벡터 (정점 → 광원)
vec3 nLight = normalize(LightPosView - vertexViewPos);
// 난반사 계산 (Lambert)
float ndotl = max(dot(nNormal, nLight), 0.0);
// 정반사 계산 (Phong)
// 뷰 공간에서는 카메라가 원점 (0,0,0) -vertexViewPos는 정점 → 카메라 방향
vec3 V = normalize(-vertexViewPos); // 시선 방향 (정점 → 카메라 원점)
// reflect(I, N) GLSL 내장 함수는,
// 📐 입사 벡터 I와 노멀 N을 기준으로 반사 벡터를 계산.
vec3 R = reflect(-nLight, nNormal);
float sIntensity = pow(max(dot(R, V), 0.0), ShininessFactor); // 반사 강도
// 조명 계산 (ADS 모델)
vec3 ambient = MaterialAmbient * LightAmbient;
vec3 diffuse = MaterialDiffuse * LightDiffuse * ndotl;
vec3 specular = MaterialSpecular * LightSpecular * sIntensity;
return ambient + diffuse + specular;
}
// -------------------------------
// 메인 함수
// -------------------------------
void main()
{
FinalColor = vec4(GouraudShading(), 1.0); // 정점 색상 계산 후 전달
gl_Position = ModelViewProjectionMatrix * VertexPosition; // 위치 변환
}
reflect() 함수의 정의
reflect(I, N) 함수는 다음과 같이 정의됩니다:

- I: 입사 벡터 (여기서는 -normalizeLightVec)
- N: 노멀 벡터 (normalizeNormal)
- N dot I: 노멀 벡터와 입사 벡터의 내적(dot product)
'Opengles 3.0 with Android' 카테고리의 다른 글
Chapter 5.2 Multi Light (0) | 2025.04.15 |
---|---|
Chapter 5.1 Phong Shader (0) | 2025.03.24 |
Chapter 4. OBJ Loader (0) | 2025.03.08 |
Chapter 3.3 Primitive Restart < Skip > (2) | 2025.02.24 |
Chapter 3.2 Instancing 렌더링 (0) | 2025.02.24 |