티스토리 뷰
고려대학교 정보대학 컴퓨터학과 2019년 1학기 <컴퓨터그래픽스> 9강 라이팅 (2)
강의영상 플레이리스트 [Link]
강의자료 [Link]
컴퓨터그래픽스 라이팅 (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가 보간하는 과정에서, 그 결과물이 단위벡터로 보장되지 않으므로 한번 더 스케일 맞춰준다.
'3D Computer Graphics > Learnings' 카테고리의 다른 글
컴퓨터그래픽스_오일러 변환 및 쿼터니언 (0) | 2022.05.08 |
---|---|
컴퓨터그래픽스_출력병합 (0) | 2022.05.06 |
컴퓨터그래픽스_라이팅(1) (0) | 2022.05.04 |
컴퓨터그래픽스_이미지텍스처링 (0) | 2022.05.02 |
컴퓨터그래픽스_래스터라이저(2) (0) | 2022.04.30 |
- Total
- Today
- Yesterday
- 원유로필터
- tensorflow.js
- vertex shader
- PoseNet
- 컴퓨터그래픽스 좌표계와 변환
- 컴퓨터그래픽스 강의
- 고려대학교 한정현
- 컴퓨터그래픽스
- 메타버스
- 3d affine transform
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |