티스토리 뷰

고려대학교 정보대학 컴퓨터학과 2019년 1학기 <컴퓨터그래픽스> 9강 라이팅 (2)

강의영상 플레이리스트 [Link]

강의자료 [Link]

 

 

Books · media lab

Introduction to Computer Graphics with OpenGL ES Review and Recommendations 이 책의 영문 제목 “Introduction to Computer Graphics”를 “A Painless Introduction to Computer Graphics”라는 닉네임으로 바꿔서 부르고 싶다. 수학을

media.korea.ac.kr


컴퓨터그래픽스 라이팅 (2)

Keywords

  • per-fragment lighting
  • fragment shader
  • vertex shader
  • rasterizer

 

Per-fragment Lighting

fragment shader -> \(l, n, r, v\)를 입력으로 받아서 텍스쳐링+라이팅을 수행한다

 

* \(l\) : directional light를 전제하는 상황에서 광원은 모든 surface points에 공통 적용 -> uniform input

* \(n\) : rasterizer가 보간해서 주는 노말 값

* \(v\) : view vector, 카메라 정보도 fragment마다 다르므로 rasterizer가 전달해 주어야 함

* \(r\) : reflection vector, \(n, v\) 값을 이용해서 fragment shader가 직접 계산함

 

 

vertex shader input인 폴리곤 메쉬 vertices -> \(p_1, p_2, ...\)는 object space에서 정의되며, vertex normal 또한 object space

* 하지만 광원 정보를 담은 \(l\) vector는 world space에서 정의되며, \(n, r, v\) 또한 마찬가지로 world space 이어야 함

* fragment shader는 world space에서 정의된 normal 값을 요구한다

* object to world 변환은 누가 담당할까? ---> vertex shader가 수행하여 rasterizer에게 넘겨준다

 

[정리!]

* vertex shader는 normal 정보를 object space -> world space 변환하여 rasterizer에게 전달

* rasterizer는 normal 정보(world space)를 보간하여 fragment shader로 전달

* fragment shader는 normal을 포함하여 world 공간에서 정의된 \(l, v\)를 받는다

 

 

[카메라 정보 \(v\)가 처리되는 순서]

* vertex shader는 object space에서 정의된 vertex를 world 변환한다

* world 변환된 vertex 꼭지점들을 카메라(\(EYE\))와 연결하여 world 공간에서의 view vector \(v\)를 정의한다

* world 공간에서 정의된 view vector \(v\)를 rasterizer에게 넘겨준다

* rasterizer는 world 공간 view vector \(v\)를 fragment 마다 선형보간하여 각 fragment에 view vector로 최종 할당한다 : \(v_1, v_2, ... \rightarrow v_a, v_b, ...\) 

 

이상의 절차를 거쳐 \(l, n, r, v\)가 준비되면 fragment shader 입력값이 모두 준비된 것

-> Phong Model 적용!

 

 

 

Vertex shader in OpenGL ES

#version 300 es

uniform mat4 worldMat, viewMat, projMat;
uniform vec3 eyePos;

layout(location = 0) is vec3 position;
layout(location = 1) is vec3 normal;
layout(location = 2) is vec2 texCoord;

out vec3 v_normal, v_view;
out vec2 v_texCoord;

void main() {
	v_normal = normalize(transpose(inverse(mat3(worldMat))) * normal);
    vec3 worldPos = (worldMat * vec4(position, 1.0)).xzy;
    v_vew = normalize(eyePos - worldPos);
    v_texCoord = texCoord;
    gl_Position = projMat * viewMat * vec4(worldPos, 1.0);
}

 

* 4x4 월드변환 행렬의 left-upper 3x3 행렬부 -> \(L\), linear transform

* 4x4 월드변환 행렬의 right-upper 3x1 행렬부 (column) -> \(t\), translation

 

Vertex shader는 하나의 vertex 당 한번씩 수행된다.

* position : 입력으로 주어진 정점의 object space 좌표

-> homogeneous 4차원 벡터로 변환하여 world transformation

-> view vector 연산에 사용하기 위해서 world space로 변환해준 것

 

gl_Position = projMat * viewMat * vec4(worldPos, 1.0);

rasterizer로 넘겨주기 위해 clip space로 변환하는 최종 작업 (**vertex shader가 반드시 수행해야 함)

* gl_Position은 내부 변수로 저장됨

* 최종적으로 v_normal, v_view, v_texCoord 3개 정보를 return -> rasterizer가 보간하여 fragment에 할당하게 됨

 

$$n_1, n_2 \rightarrow n_a, n_b$$

$$v_1, v_2 \rightarrow v_a, v_b$$

 

 

Phong Model in OpenGL ES

 

[fragment shader]

$$max(n \cdot l, 0)s_d \otimes m_d + (max(r \cdot v, 0))^{sh} s_s \otimes m_s + s_a \otimes m_a + m_e$$

 

Phong Model - 변수 정의 파트

#version 300 es

percision mediump float;

uniform sampler2D colorMap; // texture info
uniform vec3 matSpec, matAmbi, matEmit; // Ms, Ma, Me
uniform float matSh; // shininess
uniform vec3 srcDiff, srcSpec, srcAmbi; // Sd, Ss, Sa
uniform vec3 lightDir; // directional light

in vec3 v_normal, v_view;
in vec2 v_texCoord;

layout(location = 0) out vec4 fragColor;

위 코드에서 정의되지 않은 4개의 값

* \(n\) : rasterizer 반환값

* \(m_d\) : texture 정보로부터 가져옴

* \(v\) : rasterizer 반환값

* \(r\) : \(n, v\) 값을 이용해서 fragment shader가 직접 계산함

 

Phong Model - 연산 파트

void main() {
	// normalization
    vec3 normal = normalize(v_normal);
    vec3 view = normalize(v_view);
    vec3 light = normalize(lightDir);
    
    // Phong - diffuse term
    vec3 matDiff = texture(colorMap, v_texCoord).rgb;
    vec3 diff = max(dot(normal, light), 0.0) * srcDiff * matDiff;
    
    // Phong - specular term
    vec3 refl = 2.0 * normal * dot(normal, light) - light;
    vec3 spec = pow(max(dot(refl, view), 0.0), matSh) * srcSpec * matSpec;
    
    // Phong - ambient term
    vec3 ambi = srcAmbi * matAmbi;
    
    fragColor = vec4(diff + spec + ambi + matEmit, 1.0);
}

 

[Question 1. RGB scale]

*최종적으로 반환하는 fragColor의 RGB 값은 0에서 1 사이로 normalize된 스케일을 사용한다.

*만약 diffuse + specular + ambi + emissive 총합이 1을 넘어간다면? --> 강제로 최대값인 1로 맞춘다.

 

[Question 2. 반투명 색상?]

* RGBA 포맷에서 Alpha 값(0.0~1.0)으로 반투명을 처리, 표현한다.

* 투명이 존재한다면, uniform으로 주어지는 값들이 vec3가 아니라 A값을 포함하는 vec4로 들어온다. (10장 강의 내용)

 

[Question 3. re-normalize]

* Vertex shader는 v_normal, v_view를 normalize 해서 넘겨줌

* 그런데 왜 fragment shader는 v_normal, v_view에 다시 한번 normalize를 하는 걸까?

-> Rasterizer가 보간하는 과정에서, 그 결과물이 단위벡터로 보장되지 않으므로 한번 더 스케일 맞춰준다.

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함