74ea9e21ecd418986abce8954785716a947424


C++ 구현


위 gif 가 작업물임


헬로월드 별찍기 printf 찍는 콘솔창 그거 맞음


내용 길고 수학 많이나오고 난해하니

짤만 보고 나가도 무방함


GPT 적극적으로 활용함 (써도 개빡셈)










위 영상은 앵간한 사람들은 다 한번쯤은 봤을 거임

막연히 나도 저런거 한번 만들어봐야겠다는 생각을 평소 가지고있었고,
이 작업물은 그 생각을 실행으로 옮긴 거임

그리고 디시는 그림 50개 제한있어서 본론 일부 사진으로 대체함




7cec8168f5dc3f8650bbd58b3685726fa6ca73bc



중간시연



일단 대략적인건 다 이야기 했고,


워낙 구현한게 많아 다 다룰 수는 없어서 생략된게 좀 있음

설명안한 것들은 어차피 그 정도는 아니라서 스킵해도 무방함


어차피 여기까지 하나하나 읽는 사람도 없을거 같고


아무튼 이야기한거 + 생략한거 모든걸 구현하고


그리고 발생하는 온갖 잡버그를 디버깅하고 수정하고 난 후의 첫 결과물은 다음과 같음




7ae59e21ecd418986abce8954281756e57d7



잘못 그려지긴 하지만

그래도 굴러는 간다는 점에서 의의가 있음









시행착오와 개선


씬 구성에는 directional light를 썼었음

태양광 같은거임




7ae49e36ebd518986abce8954086726c


이론도 그렇고 구현도 그렇고 light 벡터는 버텍스에서 광원 쪽으로 향해야함

이부분 실수했었고 수정했음


이거 찾는데 무수한 간격의 시간이 소요되었음







75ed9e21ecd418986abce89542817d6ae5de


많이 나아졌음

그런데 아직도 버그가 있음

일단 이건 차치하고









75ec9e21ecd418986abce8954583706f3592


정육면체 그리면 원래 이렇게 그려짐


위에 그렸던 건 사실 y scale 압축시킨 직육면체였음


이 문제가 발생하는 이유는 console창 char 한칸 cell의 크기가 세로가 더 길기 때문임





75ef9e36ebd518986abce8954487756e67


콘솔창 셀의 세로가 대충 2배 기니 0.5 곱했음








75ee9e21ecd418986abce8954380726449b3


일단 비율 문제는 해결했는데


아직도 뭔가 문제가 있음


수많은 노가다와 시간간격이 소요된 후,


이게 Z Fighting 문제임을 알아냈음


정육면체라서 버텍스의 Z 값이 같으니 Z buffer method가 제대로 작동을 안함


그래서...








Back Face Removal



75e99e36ebd518986abce8954286716979


일단 이론은

View Coordinate 에서, 

polygon의 법선벡터가 음수면 back face 이다 -> 컬링해라

인데


결론부터 말하면

잘 작동안함

아무튼 잘 안됨






Back Face Removal2


75e89e36ebd518986abce8954383736e13


back face culling 다른버전임


보니깐 폴리곤 배열된걸 CCW 돌려서

버텍스의 위치만으로 면의 법선벡터를 구할 수 있음


이게 어떻게 가능하냐면 

애초에 모델 만들 때, 

폴리곤의 법선벡터가 모델의 외부로 향하도록 버텍스 순서를 맞춰서 전처리함 





75eb9e36ebd518986abce89545827169


Z 위치만 다른 두 삼각형을 가정해보자,

일반적으론, 저 두삼각형 외적 돌리면 같은 법선이 나와야하는데,

메쉬에 삼각형 집어넣을 때, 하나는 ABC 순서로 집어넣고

다른건 ACB 순서로 집어넣어서 외적돌렸을 때, 다른방향이 나오게 하는거임


그 후 평면위의 아무 한 점 잡아서 (보통 vertex 의 p0)

카메라까지의 방향벡터를 구하고 (to eye)

to eye 벡터랑 내적 돌려서 이게 양수이면 카메라에서 보임, 음수면 back face라 컬링 가능임



75ea9e36ebd518986abce89544807d655a


위 수식은 간단한 증명임

s(x) 는 삼각형을 포함하는 평면의 방정식

카메라의 위치는 (0, 0, 0) 이 정석이므로 0을 집어넣음




75e59e36ebd518986abce8954487726a29


이건 평면위의 아무 점을 잡던간에 판별에 영향을 주지 않음을 보여주는 증명

e1 e2는 평면위의 평행하지 않은 두 벡터이고 이걸로 평면위의 어떠한 점이라도 표현 가능함

내적시켜보면 싹다 0으로 날라가서 부호가 항상 일정함을 보여줌


결론적으로, Back face culling 까지 적용하고 나면










75e49e21ecd418986abce8954287776a8400


꽤 잘 작동한다









Texture


이제 텍스쳐 만들어야함



74ed9e36ebd518986abce8954788736a3d


텍스쳐 자체는 뭐 별거 없음

이미지 정보가 rgb데이터로 width height 이렇게 존재할텐데

그거 가중치 기반으로 정보 추출해오는거임


width 100, height 100 짜리 이미지에

예를들어 Sample(0.5, 0.5) 한다 가정해보자

그러면 pixel[50][50] 인덱스의 rgb 가져오는거임 (인덱스 디테일은 살짝 다르겠지만 대충 이런느낌이라는 뜻임)


뭐 CLAMP REPEAT NEAREAST LINEAR는 딱히 다룰 주제는 아닌 것 같고





74ec9e36ebd518986abce89547877168a4


대충 이런느낌으로 색깔에 곱해서 썼음


텍스쳐 매니저 만들기

패턴베이크 이미지등록

렌더링 파이프라인에 끼워넣기

수많은 시간간격이 소요된 버그들 수정 

등등의 많은 일이 있었지만

딱히 할만한 이야깃거리는 아니라서 스킵함


골때리는건 보정보간임







perspective correct


일단 문제는 다음과 같음


Vertex에는


position,

normal, 

color,

uv,


가 존재함


근데 파이프라인은

PVM * vertex 하고, 

vextex의 각 x y z 를 w 로 나눠서 ndc로 맞추는데


color랑 uv는 이런과정을 안거친다는 것이고,

이를 바라센트릭 보간 가중치를 그대로 갖다쓰면 왜곡이 발생함


그래서,


보정 보간을 해야하는데

증명 빡셈




74ef9e36ebd518986abce89542827369c7


이를 NDC 로 투영시키면

위 수식과 같이 나옴



74ee9e36ebd518986abce89545857d6f61


color든 uv든, 

바라센트릭으로 레스터라이즈할때, 이 수식으로 구현해야함







74e99e36ebd518986abce8954488756a14


구현은 위와 같음

u_over_w, r_over_w .. 

등등은 u/w , r/w 랑 같음

연산감소용으로 미리 전처리해서 구해두는 값



아무튼 최종적으로





74e89e21ecd418986abce8954781726550f11d

체커텍스쳐 적용











74eb9e21ecd418986abce8954e847d6f9c23


벽돌 텍스쳐 적용









결론



이제 온갖 구현된걸 기반으로


대충 메인이랑 엔진 사이에 


인풋핸들러 카메라컨트롤러 월드메이커 같은 추상층 몇개 끼얹어서 공간 만들면 (난이도 : 쉬움)


아래 GIF 처럼 나옴



7ff3d72fe3f206a26d81f6e442837364b73e




Further Work



방향성은 매우 많은 듯함



1. 멀티쓰레드, GPU 등의 병렬화 및 analysis 


2. 스타1, 메월 같은 2D 플랫폼에 그대로 이식해서 3D게임 만들기


3. 레이트레이싱


4. 이대로 DOOM 제작작


5. 코드 최적화


6. 각종 기법들 적용해보고 성능 analysis



등등 있는데 일단 한동안은 그대로 냅둘듯