기존 그냥 퐁 쉐이딩에서는 픽셀에서 ray를 쏴서 물체에 맞는 곳을 계산해주면 되었다.
이제 빛의 반사를 계산하기 위해서는 물체에 맞은 위치에서 또 ray를 쏴서 계산해주고, 또 그게 다른곳에 맞으면 거기서도 또 ray를 쏴서 계산해주고... recursive하게 계산을 해야 한다.
처음 ray가 물체에 맞아서 나온 color(그냥 퐁쉐이딩해서 나온color)와 첫번째 반사돼서 맞은 물체의 색,
두번째 반사돼서 맞은 물체의 색, 세번째 반사돼서 맞은 물체의 색... 을 적절히 섞어서 색을 결정하면 된다.
무한히 함수를 재귀호출 할 수 없기때문에 recursive level을 정해 놓고 해야 한다.
// 광선이 물체에 닿으면 그 물체의 색 반환
vec3 traceRay(Ray &ray, const int recurseLevel)
{
if (recurseLevel < 0)
return vec3(0.0f);
// Render first hit
const auto hit = FindClosestCollision(ray);
if (hit.d >= 0.0f)
{
glm::vec3 color(0.0f);
const vec3 dirToLight = glm::normalize(light.pos - hit.point);
// 그림자 생략
//Ray shadowRay = { hit.point + dirToLight * 1e-4f, dirToLight };
//if (FindClosestCollision(shadowRay).d < 0.0f)
{
glm::vec3 phongColor(0.0f);
const float diff = glm::max(dot(hit.normal, dirToLight), 0.0f);
const vec3 reflectDir = 2.0f * hit.normal * dot(dirToLight, hit.normal) - dirToLight;
const float specular = glm::pow(glm::max(glm::dot(-ray.dir, reflectDir), 0.0f), hit.obj->alpha);
// phong ambient
if (hit.obj->ambTexture)
{
phongColor += hit.obj->amb * hit.obj->ambTexture->SampleLinear(hit.uv);
}
else
{
phongColor += hit.obj->amb;
}
// phong diffuse
if (hit.obj->difTexture)
{
phongColor += diff * hit.obj->dif * hit.obj->difTexture->SampleLinear(hit.uv);
}
else
{
phongColor += diff * hit.obj->dif;
}
// phong specular
phongColor += hit.obj->spec * specular;
// 반사되는 양, 투명도 만큼 뺀 가중치를 곱함
color += phongColor * (1.0f - hit.obj->reflection - hit.obj->transparency);
if (hit.obj->reflection)
{
// 여기에 반사 구현
// 수치 오류 주의
// 반사광이 반환해준 색을 더할 때의 비율은 hit.obj->reflection
const vec3 reflectedDirection = glm::normalize(-ray.dir + (-glm::dot(hit.normal, ray.dir)*hit.normal + ray.dir) * 2.0f);
// const auto reflectedDirection = glm::normalize(hit.normal * 2.0f * dot(-ray.dir, hit.normal) + ray.dir);
Ray reflectRay{ hit.point + reflectedDirection * 1e-4f, reflectedDirection };
color += traceRay(reflectRay, recurseLevel - 1) * hit.obj->reflection;
}
if (hit.obj->transparency)
{
// 투명한 물체의 굴절 처리
}
}
return color;
}