본문 바로가기
Opengles 3.0 with Android

Chapter 5.0 Vertex lighting

by SimonLee 2025. 3. 24.

GouraudShader

 

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