퐁 셰이딩은 픽셀 단위에서 보간된 노말 벡터를 사용해 조명 계산을 수행하는 방식.
부드럽고 자연스러운 하이라이트 표현이 가능함.
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) | 광원의 난반사 성분 |
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
// 정점 속성
layout(location = 0) in vec4 VertexPosition; // 모델 공간의 정점 위치
layout(location = 1) in vec3 Normal; // 모델 공간의 노멀 벡터
// 변환 매트릭스
uniform mat4 ModelViewProjectionMatrix; // 모델 → 뷰 → 프로젝션 변환 행렬 (최종 화면 좌표 계산용)
uniform mat4 ModelViewMatrix; // 모델 → 뷰 변환 행렬 (카메라 공간에서 좌표계 변환용)
uniform mat3 NormalMatrix; // 노멀 벡터를 변환하기 위한 행렬 (ModelViewMatrix의 상단 3x3 역전치)
// 프래그먼트 셰이더로 넘겨줄 변수 (조명 계산용)
out vec3 normalByView; // 뷰(카메라) 공간에서의 노멀 벡터
out vec3 vertexByView; // 뷰(카메라) 공간에서의 정점 위치
void main()
{
// 모델 공간의 노멀 벡터를 뷰 공간으로 변환
normalByView = NormalMatrix * Normal;
// 모델 공간의 정점 위치를 뷰 공간으로 변환
vertexByView = vec3(ModelViewMatrix * VertexPosition);
// 최종 클립 공간 위치 계산 (뷰 → 프로젝션 → NDC → 화면)
gl_Position = ModelViewProjectionMatrix * VertexPosition;
}
Fragment Shader Code
#version 300 es
precision mediump float;
// ---------------------------
// Uniforms: 외부에서 전달되는 Material & Light 속성
// ---------------------------
// Material (재질) 속성
uniform vec3 MaterialAmbient;
uniform vec3 MaterialSpecular;
uniform vec3 MaterialDiffuse;
uniform float ShininessFactor; // 광택 계수
// Light (조명) 속성
uniform vec3 LightAmbient;
uniform vec3 LightSpecular;
uniform vec3 LightDiffuse;
uniform vec3 LightPosition; // 뷰 공간 기준 광원 위치
// ---------------------------
// Inputs: 정점 셰이더에서 전달받는 뷰 좌표계 기준 벡터들
// ---------------------------
in vec3 normalByView; // 뷰 공간 기준 정점 노멀
in vec3 vertexByView; // 뷰 공간 기준 정점 위치
// ---------------------------
// Output: 픽셀 색상
// ---------------------------
layout(location = 0) out vec4 FinalColor;
// ---------------------------
// Phong Shading 함수 (ADS 모델)
// ---------------------------
vec3 PhongShading()
{
// 정규화된 벡터 계산
vec3 N = normalize(normalByView); // 노멀 벡터
vec3 V = normalize(-vertexByView); // 뷰어 벡터 (카메라는 원점에 있으므로)
vec3 L = normalize(LightPosition - vertexByView); // 광원 벡터
// Diffuse: Lambert law (N ⋅ L)
float diffIntensity = max(dot(N, L), 0.0);
// Specular: 반사벡터 R = reflect(-L, N), 시선벡터 V
vec3 R = reflect(-L, N);
float specIntensity = pow(max(dot(R, V), 0.0), ShininessFactor);
// 조명 각 성분 계산 (Material * Light)
vec3 ambient = MaterialAmbient * LightAmbient;
vec3 diffuse = MaterialDiffuse * LightDiffuse * diffIntensity;
vec3 specular = MaterialSpecular * LightSpecular * specIntensity;
// 최종 색상 합산
return ambient + diffuse + specular;
}
// ---------------------------
// Fragment Shader main()
// ---------------------------
void main() {
FinalColor = vec4(PhongShading(), 1.0); // 알파는 항상 1.0
}
'Opengles 3.0 with Android' 카테고리의 다른 글
Chapter 6.0 Warble Effect (0) | 2025.04.16 |
---|---|
Chapter 5.2 Multi Light (0) | 2025.04.15 |
Chapter 5.0 Vertex lighting (0) | 2025.03.24 |
Chapter 4. OBJ Loader (0) | 2025.03.08 |
Chapter 3.3 Primitive Restart < Skip > (2) | 2025.02.24 |