여기까지의 작업내용: https://github.com/hwi-middle/HimchanSoftwareRenderer/tree/1fec655e44bffcbd7eff43adea8ca4067748468f
(또) 오랜만입니다
한 달 정도 정신없이 졸업 작품과 관련된 일을 했다. 그러다 오늘 약~간 시간이 남길래 다시 이 프로젝트에 손을 댔다. 지금은 새벽 3시 반. 피곤하다.
텍스처링 버그
오늘 고쳐볼 버그는 요녀석. 삼각형이 화면 밖으로 나가면 텍스처가 일그러지는 현상을 발견했다. Wireframe을 덧대어보아도 (당연히) 삼각형은 멀쩡한데 텍스처가 일그러진 것이다.
자, 그렇다면 이유는 무엇이겠는가? 더 볼 것도 없이 UV다.
for (int Y = Y1; Y <= Y2; ++Y)
{
int32 XStart = X1 + A12 * (Y - Y1);
int32 XEnd = X1 + A13 * (Y - Y1);
bool bIsSwapped = false;
if (XStart > XEnd)
{
std::swap(XStart, XEnd);
std::swap(UvStart, UvEnd);
bIsSwapped = true;
}
XStart = Math::Clamp(XStart, 0, Width - 1);
XEnd = Math::Clamp(XEnd, 0, Width - 1);
for (int X = XStart; X <= XEnd; ++X)
{
Vector2 UV = Math::Lerp(UvStart, UvEnd, (X - XStart) / static_cast<float>(XEnd - XStart));
SetPixel(X, Y, SampleTexture(UV));
}
if (bIsSwapped)
{
std::swap(UvStart, UvEnd);
}
UvStart += DeltaUvStart;
UvEnd += DeltaUvEnd;
}
스캔라인 방식에서 위쪽 삼각형을 그리는 부분을 발췌해왔다. 여기서 XStart와 XEnd를 클리핑해주는데, UV정보는 수정하지 않는다는게 문제다. 결과적으로 UV 좌표가 일그러지는 것이다.
예를 들어, 다시 이 화면을 살펴보자. XStart는 클리핑된 부분부터 그려지기 시작하는데, 이게 UV를 보간할 때에도 영향을 주는 것이다. XStart와 XEnd 사이를 보간해야하는데, XStart가 클리핑되면서 값이 손상(?)된 것이다.
하지만 원인을 아는 것과 해결법을 생각해내는 것은 거리가 멀다. 공책에 죄 없는 삼각형들을 난도질 해가면서 계속 방법을 생각해냈다. 제자리에 앉아서 끙끙 앓다가 2시간 정도 걸려서 해결했다. 바보 같은 녀석... -_-;;
for (int Y = Y1; Y < Y2; ++Y)
{
int32 XStart = X1 + A12 * (Y - Y1);
int32 XEnd = X1 + A13 * (Y - Y1);
bool bIsSwapped = false;
if (XStart > XEnd)
{
std::swap(XStart, XEnd);
std::swap(UvStart, UvEnd);
bIsSwapped = true;
}
const int32 ClipXStart = Math::Clamp(XStart, 0, Width - 1);
const int32 ClipXEnd = Math::Clamp(XEnd, 0, Width - 1);
for (int X = ClipXStart; X <= ClipXEnd; ++X)
{
Vector2 UV = Math::Lerp(UvStart, UvEnd, (X - XStart) / static_cast<float>(XEnd - XStart));
SetPixel(X, Y, SampleTexture(UV));
}
if (bIsSwapped)
{
std::swap(UvStart, UvEnd);
}
UvStart += DeltaUvStart;
UvEnd += DeltaUvEnd;
}
해결된 코드. 생각보다 매우 간단한데, 클리핑된 좌표는 따로 저장하면 된다. 그러면 자연스럽게 UV 좌표를 보간할 때에는 클리핑 되기 전 좌표를 기준으로 되면서 문제가 해결된다.
짜잔, 문제가 해결된 버전.
또 다른 문제
또 한가지 문제, 삼각형이 화면 밖으로 아예 나가도 1픽셀 정도 그려진다.
// Degenerate triangle
if ((X2 - X1) * (Y3 - Y1) == (X3 - X1) * (Y2 - Y1))
{
return;
}
// 화면 밖으로 나간 경우 클리핑
bool IsTriangleOutsideViewport = true;
for (int i = 0; i < 3; ++i)
{
if (ClipLine(Vertices[i].Position, Vertices[(i + 1) % 3].Position, Vector2(0, 0), Vector2(Width - 1, Height - 1)))
{
IsTriangleOutsideViewport = false;
break;
}
}
if (IsTriangleOutsideViewport)
{
return;
}
그리하여 삼각형이 뷰포트 밖으로 나가면 클리핑하도록 했다. 삼각형을 이루는 Line 3개에 대해서 ClipLine을 해보고 모두 뷰포트 밖에 있다면 삼각형도 화면 밖에 있는 것이므로 그리지 않고 생략한다.
이렇게, 2가지 문제 해결!
바쁜 일 끝나면 진짜 3D 렌더러... 제발...
'개발일지 > 소프트 렌더러' 카테고리의 다른 글
소프트웨어 렌더러 만들기 - 17 (3D 렌더링) (0) | 2024.12.23 |
---|---|
소프트웨어 렌더러 만들기 - 15 (키보드 입력) (0) | 2024.07.27 |
소프트웨어 렌더러 만들기 - 14 (텍스처링) (1) | 2024.07.25 |
소프트웨어 렌더러 만들기 - 13 (삼각형 채우기, 보간) (1) | 2024.07.22 |
소프트웨어 렌더러 만들기 - 12 (삼각형 그리기 + 버그 수정) (0) | 2024.07.19 |