퐁 라이팅 모델을 구현한다.
라이트 소스를 2개를 적용 결과.
빛의 방향 좌측 상단 (-10, 10, 0);
vec3 lightDirection = normalize(vec3(-10,10,0) - p);
col += phong(lightDirection, normal, rd, s.mat) * 0.6;
빛의 방향 우측 상단 (50, 10, 0);
vec3 lightDirectionA = normalize(vec3(50,10,0) - p);
col += phong(lightDirectionA, normal, rd, s.mat) * 0.6;
2개의 광원의 방향에 따라서 반사하는 라이팅이 적용된 모습을 볼 수 있다.
퐁 라이팅 모델은 ambient + diffuse + specular + emissive 컬러 값이며, 빛 반사된 물체를 표현하는 유명한 방식.
emissive는 자체발광이라 제외하고 ambient (주변광)은 커스텀 색상이라 중요하지 않음.
diffuse 계산은 이전 챕터에서 구현했었고,
반사광인 specular가 중요한데, 반사 벡터 r을 구하는 공식은 이미 reflect 함수로 제공한다.
reflect 함수 사용하지 않고 직접 구현도 해본다.
reflectV = (2. * normal * clamp(dot(normal, lightDir), 0., 1.)) - lightDir;
퐁라이팅 코드 >>
struct Material {
vec3 ambientColor; // k_a * i_a
vec3 diffuseColor; // k_d * i_d
vec3 specularColor; // k_s * i_s
float alpha; // shininess
};
vec3 phong(vec3 lightDir, vec3 normal, vec3 rd, Material mat) {
float diffuse = clamp(dot(lightDir, normal), 0.3, 1.);
vec3 diffuseCol = mat.diffuseColor * diffuse;
vec3 reflectV = reflect(lightDir, normal);
reflectV = (2. * normal * clamp(dot(normal, lightDir), 0., 1.)) - lightDir;
float specular = pow(clamp(dot(reflectV, -rd),0.3, 1.), mat.alpha);
vec3 specColor = mat.specularColor * specular;
vec3 ambientCol = mat.ambientColor;
return diffuseCol + ambientCol + specColor;
}
전체 코드 >>
const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float PRECISION = 0.001;
struct Material {
vec3 ambientColor; // k_a * i_a
vec3 diffuseColor; // k_d * i_d
vec3 specularColor; // k_s * i_s
float alpha; // shininess
};
struct Surface {
int id; // id of object
float sd; // signed distance
Material mat;
};
Surface getCloser(Surface a, Surface b) {
if (a.sd < b.sd) return a;
return b;
}
Material gold() {
vec3 aCol = 0.5 * vec3(0.7, 0.5, 0);
vec3 dCol = 0.6 * vec3(0.7, 0.7, 0);
vec3 sCol = 0.6 * vec3(1, 1, 1);
float a = 5.;
return Material(aCol, dCol, sCol, a);
}
Material silver() {
vec3 aCol = 0.4 * vec3(0.8);
vec3 dCol = 0.5 * vec3(0.7);
vec3 sCol = 0.6 * vec3(1, 1, 1);
float a = 5.;
return Material(aCol, dCol, sCol, a);
}
Surface sdFloor(int id, vec3 p) {
Material mat;
mat.diffuseColor = vec3(0.5 + 0.7 * mod(floor(p.x) + floor(p.z), 2.));
return Surface(id, p.y+1., mat);
}
Surface sdSphere(int id, vec3 p, float r, vec3 offset, Material mat) {
p -= offset;
return Surface(id, length(p) - r, mat);
}
Surface scene(vec3 p) {
Surface l = sdSphere(1, p, 1., vec3(-2, 0, 0), gold());
Surface r = sdSphere(2, p, 1., vec3(+2, 0, 0), silver());
Surface f = sdFloor(3, p);
Surface rst = getCloser(l, r);
rst = getCloser(rst, f);
return rst;
}
Surface rayMarch(vec3 ro, vec3 rd) {
float d = MIN_DIST;
Surface s;
for (int i=1; i<255; i++) {
vec3 p = ro + rd * d;
s = scene(p);
d += s.sd;
if (d < PRECISION || d > MAX_DIST) break;
}
s.sd = d;
return s;
}
vec3 calcNormal(in vec3 p) {
vec2 v = vec2(1, -1) * 0.001;
return normalize(
v.xyy * scene(p + v.xyy).sd +
v.yxy * scene(p + v.yxy).sd +
v.yyx * scene(p + v.yyx).sd +
v.xxx * scene(p + v.xxx).sd);
}
mat3 camera(vec3 cameraPos, vec3 lookAtPoint) {
vec3 cd = normalize(lookAtPoint - cameraPos);
vec3 cr = cross(vec3(0,1,0), cd);
vec3 cu = cross(cd, cr);
return mat3(-cr, cu, -cd);
}
vec3 phong(vec3 lightDir, vec3 normal, vec3 rd, Material mat) {
float diffuse = clamp(dot(lightDir, normal), 0.3, 1.);
vec3 diffuseCol = mat.diffuseColor * diffuse;
vec3 reflectV = reflect(lightDir, normal);
reflectV = (2. * normal * clamp(dot(normal, lightDir), 0., 1.)) - lightDir;
float specular = pow(clamp(dot(reflectV, -rd),0.3, 1.), mat.alpha);
vec3 specColor = mat.specularColor * specular;
vec3 ambientCol = mat.ambientColor;
return diffuseCol + ambientCol + specColor;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
vec3 background = mix(vec3(1, .341, .2), vec3(0, 1, 1), uv.y) * 1.6;
vec3 col = vec3(0);
vec3 ro = vec3(0, 0, 5);
vec3 lp = vec3(0);
mat3 camTrans = camera(ro, lp);
vec3 rd = camTrans * normalize(vec3(uv, -1));
Surface s = rayMarch(ro, rd);
if (s.sd < MAX_DIST) {
vec3 p = ro + rd * s.sd;
vec3 normal = calcNormal(p);
vec3 lightDirection = normalize(vec3(-10,10,0) - p);
col += phong(lightDirection, normal, rd, s.mat) * 0.6;
vec3 lightDirectionA = normalize(vec3(50,10,0) - p);
col += phong(lightDirectionA, normal, rd, s.mat) * 0.6;
}
else {
col = background;
}
fragColor = vec4(col,1.0);
}
'Shader CG' 카테고리의 다른 글
08. RayMarching - Shadow (0) | 2024.08.10 |
---|---|
07. RayMarching - Frenel effect (0) | 2024.08.10 |
05. RayMarching - Camera move (0) | 2024.08.05 |
04. RayMarching - Rotation (0) | 2024.08.04 |
03. RayMarhcing - Rendering Many Object (0) | 2024.08.02 |