Graphics Techniques

[Ray Tracing] - 빛의 반사(거울반사)

doyyy_0 2024. 10. 22. 14:27

빛의반사(reflection)란 여러 물체가 있을 때 빛이 반사되어 오는 색 또한 할당하는 방법입니다. 예를들어 쇠구슬 여러개가 눈 앞에 있다고 생각해봅시다. 빛 반사 없이 쇠구슬만 그리면 보고있는 하나의 쇠구슬에 비춰지는 옆에있는 쇠구슬들이 보이지 않게되어 현실감이 떨어질 것입니다. 따라서 현실감을 반영하기 위해 빛 반사를 넣어야합니다.

 

그냥 구 두개와 텍스쳐를 입힌 평면을 하나 그린 그림입니다

 

 

 

여기서 반사를 입혀보겠습니다.

 

무엇이 바뀌었을까요?

 

서로 빛 반사가 됨과 동시에, 구와 평면의 색이 약간 옅어졌습니다. 일반적으로 원래 할당된 Color값에 반사된 물체의 color값을 더해주기 때문에 그 값만큼 기존의 값에서 빼야하기 때문입니다.

 

다음 그림을 보며 원리를 이해해봅시다. 원리는 https://pdy0930.tistory.com/54 

이전 퐁 모델 글의 Specular부분에서와 똑같습니다. n과 d는 유닛벡터라는 점을 생각하여 유도하면 반사된 빛의 방향을 구할 수 있습니다.여기서 재귀문을 써서 몇번 반사될 것인지를 반드시 정해야 합니다. 그렇지 않으면 무한 반사되어 코드가 끊임없이 돌아가기 때문입니다.

 

 

다음 코드를 보며 명확히 이해해봅시다.

// 광선이 물체에 닿으면 그 물체의 색 반환
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);

		{
			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);

			if (hit.obj->ambTexture)
			{
				phongColor += hit.obj->amb * hit.obj->ambTexture->SampleLinear(hit.uv);
			}
			else
			{
				phongColor += hit.obj->amb;
			}

			if (hit.obj->difTexture)
			{
				phongColor += diff * hit.obj->dif * hit.obj->difTexture->SampleLinear(hit.uv);
			}
			else
			{
				phongColor += diff * hit.obj->dif;
			}

			phongColor += hit.obj->spec * specular;

			color += phongColor * (1.0f - hit.obj->reflection);

			if (hit.obj->reflection)
			{
				// 여기에 반사 구현
				// 수치 오류 주의
				// 반사광이 반환해준 색을 더할 때의 비율은 hit.obj->reflection

				const vec3 reflectedDirection = glm::normalize(glm::dot(hit.normal, -ray.dir) * hit.normal*2.0f + ray.dir);
				Ray nextRay = { hit.point+reflectedDirection*1e-2f,reflectedDirection};
				color += traceRay(nextRay, recurseLevel - 1) * hit.obj->reflection;
			}
		}

		return color;
	}
	

	return vec3(0.0f);
}

 

여기서 유의할 점은 Specular에서 유의할 점과 같은데,  hit.point자리에서 Ray를 쏘면 안된다는 점입니다. 왜냐하면 빛 반사가 일어날 때 반사된 point에서 다시 Ray를 쏘는데 hit.point가 시작점이라 그 물체에 다시 한번 Ray가 맞는 현상이 일어나서 제대로 색이 반영이 안될 수 있기 때문입니다. 따라서 reflectedDirection*(1e-4f)이렇게  빛 방향으로 아주 조금 이동해서 똑같은 물체에 다시 Ray가 맞는 현상을 제거해야만 합니다.

 

강의 출처 :

https://honglab.co.kr/courses/graphicspt1

 

HongLab 홍정모 연구소

홍정모의 컴퓨터 그래픽스 새싹코스

honglab.co.kr