Skip to content
Snippets Groups Projects
Commit 5f30b75e authored by Suhyeon Han's avatar Suhyeon Han
Browse files

뒷북1

parent da24c4f5
No related branches found
No related tags found
No related merge requests found
...@@ -9,27 +9,33 @@ ...@@ -9,27 +9,33 @@
### 주제 ### 주제
제가 선정한 주제는 **Light shaft**라는 효과입니다. 제가 선정한 주제는 **Light shaft**라는 효과입니다.
Light shaft란 광원에서 뿜어져나오는 빛이 오브젝트에 의해서 부분적으로 막히는 경우, 막히지 않는 부위에서 어져 나오는 빛의 줄기입니다. Light shaft란 광원에서 뿜어져나오는 빛이 오브젝트에 의해서 부분적으로 막히는 경우, 막히지 않는 부위에서 빛의 줄기가 뻗어져 나오는 효과입니다.
초기엔 **Three.js** 예제 중 **Godrays**를 참고하여 수정하려 했으나, 전체적으로 코드 파일이 많이 나눠져 있고 없어도 되는 구현이 많아 완전히 새로 만들었습니다. 초기엔 **Three.js** 예제 중 **Godrays**를 참고하여 수정하려 했으나, 전체적으로 코드 파일이 많이 나눠져 있고 불필요한 구현이 많아 완전히 새로 만들었습니다.
베이스 코드와 셰이더 코드, 구현 원리 등 **Godrays** 예제에서 가져온 것은 아무것도 없으므로 결과만 비슷한 다른 프로그램이라고 생각해주시면 되겠습니다. 베이스 코드와 셰이더 코드, 구현 원리 등 **Godrays** 예제에서 가져온 것은 아무것도 없으므로 결과만 비슷한 다른 프로그램이라고 보시면 됩니다.
(구현 원리는 레퍼런스의 **HLSL Development Cookbook** 참고했습니다.) (구현 원리는 레퍼런스의 **HLSL Development Cookbook** 책을 참고했습니다.)
## 설명 요약 ## 설명 요약
### 작동 단계 ### 작동 단계
렌더링 단계를 보면 이해하기 쉽습니다. 렌더링 단계를 보면 전체적인 구현 흐름을 이해할 수 있습니다.
1. 기본 장면을 `originalRT` 렌더 타겟에 렌더 1. 기본 장면을 `originalRT` 렌더 타겟에 그립니다.
1. `originalRT`의 깊이 텍스처를 바탕으로 해당 픽셀에서의 오브젝트의 존재 유/무 가중치를 추출한 뒤 `weightRT` 렌더타겟에 렌더 1. `originalRT`의 깊이 텍스처를 바탕으로 해당 픽셀에서의 오브젝트의 존재 여부로 흑백 가중치를 추출한 뒤, `weightRT` 렌더 타겟에 그립니다.
1. `originalRT``weightRT`를 바탕으로 직접 작성한 `Light shaft` 셰이더를 이용하여 기본(윈도) 렌더 타겟에 렌더 1. `originalRT``weightRT`를 바탕으로 직접 작성한 `Light shaft` 셰이더를 이용하여 기본 렌더 타겟에 최종 결과물을 그립니다.
### 작동 원리 ### 작동 원리
기본적으로 **스크린 공간**(Screen-space)을 이용한 기법인 만큼 **후처리**(Post-processing) 방식을 주로 이용합니다. 기본적으로 **스크린 공간**(Screen-space)을 이용한 기법인 만큼 **후처리**(Post-processing) 방식을 주로 활용합니다.
`Light shaft` 셰이더 또한 2번의 후처리를 해야만 구현할 수 있습니다. `Light shaft` 셰이더 또한 2번의 후처리를 해야 구현할 수 있기 때문에 총 2번의 셰이더를 거쳐야 합니다.
즉, 2번의 셰이더를 거쳐야 합니다. 첫 번째로는 가중치 추출 셰이더이며 이는 해당 프래그먼트에 오브젝트가 있는지 없는지를 깊이 텍스처의 값을 통해 판별합니다.
첫 번째로는 가중치 추출 셰이더인데, 이 셰이더는 해당 픽셀에 오브젝트가 있는지 없는지를 깊이 텍스처를 통해 판별합니다. 두 번째는 라이트 셰프트 셰이더로, 픽셀과 광원 사이를 지나는 ray를 쏘고 그 경로에 있는 `weightRT`의 가중치를 일정 수만큼 추출합니다.
두 번째는 라이트 셰프트 셰이더로, 픽셀과 태양 사이에 ray를 쏴서 그 경로에 있는 가중치를 일정 수만큼 추출하여 감쇄 적용 후 누적시켜 해당 픽셀의 빛 줄기 강도 값을 구합니다. 그리고 해당 추출 값들에 각각 감쇄를 적용한 뒤 이를 모두 합하여 해당 픽셀의 빛 줄기 강도 값을 구합니다.
요약이라 많이 어려워 보일 수 있으나 튜토리얼을 보면 차근차근 이해할 수 있습니다. 요약이라 많이 어려워 보일 수 있으나 차근차근 튜토리얼을 보고 따라하면 쉽게 이해할 수 있습니다.
마지막으로 기본 장면을 그린 렌더 타겟과 라이트 셰프트 값을 합쳐주면 구현 완료입니다. 마지막으로 기본 장면을 그린 렌더 타겟과 라이트 셰프트 값을 합치면 구현이 완성됩니다.
## 튜토리얼
여러분이 따라서 개발할 수 있는 튜토리얼은 `index.html` 파일에 있습니다.
원래는 구글 크롬 서버 확장 프로그램을 사용하여 볼 수 있었으나, 해당 프로그램이 버려져 이제는 사용할 수 없습니다.
서버를 열지 않고 로컬에서 `index.html` 파일을 열면 튜토리얼은 볼 수 있지만 결과물 시연을 볼 수 없다는 점 유의하시기 바랍니다.
## 개발 과정 ## 개발 과정
...@@ -38,71 +44,60 @@ Light shaft란 광원에서 뿜어져나오는 빛이 오브젝트에 의해서 ...@@ -38,71 +44,60 @@ Light shaft란 광원에서 뿜어져나오는 빛이 오브젝트에 의해서
### 1일차 ### 1일차
**1일차**에는 주제를 정한 뒤 간단히 기본 장면을 만들었습니다. **1일차**에는 주제를 정한 뒤 간단히 기본 장면을 만들었습니다.
모두 수업에 나온 내용인지라 전혀 어렵지 않았습니다. 이는 모두 수업에 나온 내용이었기 때문에 별로 어렵지 않았습니다.
그런데 잠깐, 애초에 Three.js에서 HLSL 책에 나온 원리로 구현이 가능한지가 궁금했습니다. 그런데 문득 Three.js에서 GLSL을 사용해 HLSL과 똑같이 구현이 가능한 지를 아직 알아보지 않았다는 생각이 들었습니다.
저도 모르는 어떠한 제한사항으로 인해 만들지 못하는 구조일 경우 일찍 포기해야만 했기 때문입니다. 제가 아직 모르는 어떠한 제한사항으로 인해 구현하지 못하는 구조일 경우, 빠르게 포기하고 다른 주제를 정하는 것이 좋았기 때문입니다.
사실 라이트 셰프트 셰이더는 Direct3D에서 컴퓨트 셰이더로 계산하는 방식입니다. 사실 라이트 셰프트 셰이더는 DirectX 11에서 컴퓨트 셰이더로 구현하는 것이 정석입니다.
컴퓨트 셰이더란 GPU의 스레드 그룹을 직접 배치하고 사용하는 방식으로 후처리 또는 파티클 기법에 최적화된 방식이며, 계산 속도가 굉장히 빠릅니다. 컴퓨트 셰이더란 GPU의 스레드 그룹을 직접 배치하고 사용하는 방식으로, 후처리 또는 입자 효과에 최적화된 방식이며 계산 속도가 월등히 빠릅니다.
하지만 Three.js 컴퓨트 셰이더를 사용할 수 있없을지 몰랐기 때문에 그냥 없는 것으로 가정했습니다. 하지만 Three.js에서 컴퓨트 셰이더를 사용할 수 있여부를 몰랐기 때문에 일단 없는 것으로 가정했습니다.
그럼 이제 컴퓨트 셰이더 코드를 버텍스-프래그먼트 셰이더 코드로 변환할 수 있는지를 알아야 했습니다. 그럼 이제 컴퓨트 셰이더 코드를 버텍스-프래그먼트 셰이더 코드로 변환할 수 있는지를 알아야 했습니다.
그래서 저는 아주 오래된 프로그램인 렌더몽키를 꺼냈습니다(그리고 셰이더 프로그래밍 입문 책도). 그래서 저는 아주 오래된 프로그램인 렌더몽키를 사용해 테스트했습니다.
렌더몽키는 AMD에서 만든 DirectX 9 셰이더 작성 프로그램입니다. 렌더몽키는 AMD에서 (ATI 시절에) 만든 셰이더 작성 프로그램입니다.
DirectX의 버텍스-픽셀 셰이더가 WebGL의 버텍스-프래그먼트 셰이더에 대응되므로 여기서 잘 작동하면 별 탈 없이 작동될 터였습니다. DirectX의 버텍스-픽셀 셰이더가 WebGL의 버텍스-프래그먼트 셰이더에 대응되므로 여기서 잘 작동하면 별 탈 없이 작동될 것이라 생각했습니다.
그렇게 렌더몽키에 구현해봤더니 정상적으로 작동했습니다. 의외로 사양도 높지 않았습니다. 그렇게 렌더몽키에 HLSL을 사용해 구현해봤더니 정상적으로 작동했습니다. 의외로 사양도 높지 않았습니다.
![Render Monkey result](https://git.ajou.ac.kr/shh1473/cg-tutorial/-/raw/main/tutorial_data/pictures/references/render_monkey.png "Render Monkey result") ![Render Monkey result](https://git.ajou.ac.kr/shh1473/cg-tutorial/-/raw/main/tutorial_data/pictures/references/render_monkey.png "Render Monkey test result")
### 2일차 ### 2일차
**2일차**에는 렌더 타겟 사용법을 익혔습니다. **2일차**에는 렌더 타겟 사용법을 익혔습니다.
Direct3D면 몰라도 Three.js는 처음 사용하는 라이브러리이고 수업에서도 제대로 배우지 않았으니 많은 구글링을 요구했습니다. 저에게 있어 Three.js는 처음 사용하는 라이브러리이고, 수업에서도 완전히 다루지 않았기 때문에 더 알아볼 필요가 있었습니다.
렌더 타겟 다루는 법을 안 뒤에는 기본 장면을 `originalRT`에 렌더했습니다. 렌더 타겟 다루는 법을 어느 정도 알아낸 뒤에는 기본 장면을 `originalRT`에 그렸습니다.
그 다음에 할 일은 렌더 타겟에 깊이 텍스처를 넣는 것이었습니다. 그 다음에 할 일은 렌더 타겟에 깊이 텍스처를 추가하는 것이었습니다.
[Three.js webgl_depth_texture](https://github.com/mrdoob/three.js/blob/master/examples/webgl_depth_texture.html) 예제가 많은 도움이 됐습니다. 이는 [Three.js webgl_depth_texture](https://github.com/mrdoob/three.js/blob/master/examples/webgl_depth_texture.html) 예제가 많은 도움이 되었습니다.
추가 코드는 예상 외로 쉬웠습니다만, 실제로 잘 찍혔는지 봐야 하는데 전부 하얘서 손을 좀 봐야 했습니다. 깊이 텍스처까지 완성한 후, GLSL 셰이더 사용법을 공부했습니다.
깊이 텍스처까지 완성한 후에 GLSL 셰이더 사용법을 공부했습니다. [Three.js webgl_postprocessing](https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing.html) 예제를 참고해 후처리에 사용되는 셰이더는 기존 방식과 뭔가 다르다는 것을 알아챘습니다.
[Three.js webgl_postprocessing](https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing.html) 예제를 참고해 후처리에 사용되는 셰이더는 뭔가 다르다는 것을 알아챘습니다. 후처리 셰이더의 경우 `ShaderPass``EffectComposer`를 반드시 사용해야 했습니다.
후처리 셰이더의 경우 `ShaderPass``EffectComposer`를 무조건 사용해야만 했기에 그것들도 모두 공부해야 했습니다. `ShaderPass`의 경우, Screen-aligned quad (화면을 꽉 채우는) 도형을 자동으로 넣어주는 클래스였습니다.
그래도 사용법이 쉬워서 참 다행이었습니다. `EffectComposer`는 그러한 `ShaderPass`들을 차례대로 그려주는 대기열 클래스였습니다.
`ShaderPass`의 경우, Screen-aligned quad 도형을 자동으로 넣어주는 클래스였습니다. 이후 GLSL을 사용해 가중치 추출 셰이더를 만들고 화면에 렌더하여 결과를 확인하는 데 성공했습니다.
`EffectComposer`는 그러한 `ShaderPass`를 렌더링해주는 대기열 클래스였습니다.
이후 GLSL을 사용해 가중치 추출 셰이더를 만들고 화면에 렌더하여 확인하는 데 성공했습니다.
### 3일차 ### 3일차
**3일차**에는 라이트 셰프트 셰이더를 만들었습니다. **3일차**에는 라이트 셰프트 셰이더를 만들었습니다.
렌더몽키에서 사용했던 알고리즘 그대로 GLSL하여 만들었는데, 문제가 하나 있었습니다. 렌더몽키에서 사용했던 알고리즘 그대로 GLSL로 변환하여 만들었는데, 문제가 하나 있었습니다.
바로 태양의 위치를 월드 좌표계에서 UV 좌표계로 변환하는 일이었습니다. 바로 광원의 위치를 월드 좌표계에서 UV 좌표계로 변환하는 일이었습니다.
저는 카메라로부터 뷰 행렬과 프로젝션 행렬을 가져오는 방법을 몰랐기에 많이 방황했습니다. 저는 Three.js에서 카메라로부터 뷰 행렬과 투영 행렬을 가져오는 방법을 몰랐기에 많이 방황했습니다.
이후 3차원 벡터에 `project()` 함수가 있다는 것을 깨달았으나 그마저도 오류가 많이 나 시간을 많이 잡아먹었습니다. 이후 3차원 벡터에 `project()` 함수가 있다는 것을 깨달았으나 그마저도 제대로 사용하지 못해 시간을 많이 뺏겼습니다.
많은 노력 끝에 완전히 성공한 셰이더의 모습을 확인할 수 있었습니다. 그래도 결국 완전히 성공한 셰이더의 모습을 확인할 수 있었습니다.
하지만 아직 GUI 추가 및 카메라 움직임 등 할 것들이 많이 남아있었습니다. 물론 아직 GUI 셋업 및 카메라 움직임 등 할 것들이 많이 남아있었습니다.
### 4일차 ### 4일차
**4일차**에는 뒷정리 및 부가 기능을 개발했습니다. **4일차**에는 뒷정리 및 부가 기능을 개발했습니다.
튜토리얼의 7장에 해당하는 내용입니다. 튜토리얼의 7장에 해당하는 내용입니다.
프리셋 기능은 시간이 많이 걸렸지만 은근 쉬웠습니다. 프리셋 기능의 추가는 시간이 꽤 걸렸지만 그래도 난이도는 쉬웠습니다.
태양의 자동 움직임 기능은 `Clock``getDelta()` 함수를 사용했는데, 이 함수의 결과가 제가 알던 방식의 값과 조금 달라서 놀랐습니다. 광원의 자동 움직임 기능은 `Clock``getDelta()` 함수를 사용했습니다.
유니티 같은 게임 엔진을 보면 이전 프레임과 현재 프레임 사이의 값을 반환하는 것이 원칙인데 여기의 함수는 직전의 `getDelta()` 함수와의 시간차이를 반환했습니다. 삼각함수와 함께 부드러운 움직임을 구현한 후 광원 오브젝트 변경 기능을 만들었습니다.
삼각함수와 함께 부드러운 움직임을 구현한 후 태양 오브젝트 변경 기능을 만들었습니다. 그렇게 부가 기능도 끝나고 이제 튜토리얼 작성만 남았습니다.
처음엔 리사 수의 사진을 넣어볼까 했는데 프로젝트가 MIT 라이선스인지라 관뒀습니다~(리사 수는 MIT에서 박사 학위까지 땄지만 말입니다 하하)~.
이후 제가 직접 짱 귀여운 고양이를 그려서 넣었습니다.
그렇게 부가 기능도 끝나고 이제 튜토리얼만 남은 상황이었습니다.
### 5~7일차 ### 5~7일차
**5일차부터 7일차**에는 `readme.md` 파일에 마크다운으로 튜토리얼을 작성했습니다(이때는 `index.html`에 작성해야 한다는 사실을 몰랐습니다). **5일차부터 7일차**에는 `readme.md` 파일에 마크다운으로 튜토리얼을 작성했습니다.
코드 추출하고 설명 쓰고 많이 힘들었지만 다 하니 참 많이도 썼구나 생각했습니다.
### 8~10일차 ### 8~10일차
**8일차**, `index.html`에 모든 것을 집어넣어야 한다는 것을 깨달은 저는 다시 작업에 들어갔습니다. **8일차**에는 마크다운으로 작성한 튜토리얼을 마크업으로 바꿔 `index.html` 파일로 옮겼습니다.
중요한 점은 제가 HTML을 안 한지 대략 7년이 지나 아무것도 모른다는 것이었습니다.
결국 다시 공부해야만 했습니다.
아주 많은 시간 끝에 마크다운을 번쩍 들어 마크업으로 바꾸는 데 성공했습니다.
### 11일차 ### 11일차
**11일차**에는 마지막으로 `index.html`에 프로그램 시연까지 봉합하여 모든 작업을 마쳤습니다. **11일차**에는 마지막으로 `index.html`에 프로그램 시연까지 봉합하여 모든 작업을 마쳤습니다.
그리고 보고서까지 작성 완료한 후 제출했습니다. 그리고 보고서까지 작성을 완료한 후 제출했습니다.
**정말 놀라운 점은 아직도 교수님께서 OK를 해주지 않으셨습니다.**
</details> </details>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment