[Graphics] 개요
출처 : 홍정모의 컴퓨터 그래픽스 새싹코스
dx11, ImGUI 개요
- d3.compiler.h
- VS.hlsl, PS.hjsl 컴파일에 사용
- uv
- texture coordinates
- 2차원
- othographic projection
- perspective projection
Phong Model vs Phong Shading
Phong Reflection Model
- 조명 받았을 떄
- ambient + diffuse + specular 로 표현
ambient
- ambient color
- 조명이 없어도 나타남
diffuse
- 조명과 충돌 지점의 normal vector의 각도에 따라 diffuse 결정
- cos을 이용하는데, unit vector인 경우 dot product로 계산 가능하다.
- 90도가 넘어가면 0으로 고정해주어야함
specular
- 조명이 반사될 때, 반사벡터와 시점의 각도에 따라 specular 결정
- 반사 벡터를 구하고, 시점으로 향하는 벡터와 cos 이용하여 계산, 이 또한 unit vector를 이용해 dot product로 계산 가능하다.
- pow를 이용해 빛이 집중 되는 정도를 조절할 수 있다.
Phong Shading
- Phong Model 실제 구현 시 픽셀 단위의 normal vector를 이용해 쉐이딩 하는 것
winding order
- 삼각형의 vertex를 나열하는 순서.
- clockwise를 CW, counter clockwise를 CCW라 부른다.
- 특정 삼각형 안의 점은 삼각형의 세 vertex와 선을 이어 삼각형을 세개 그렸을 때, 세 삼각형의 외적도 같은 방향임.
- 삼각형 밖의 점은 위의 세 삼각형 중 하나를 뒤집은 느낌
원근 투영
- 왜곡이 생기는 이유
- interpolation 이 poject 된 screen 상에서 계산되므로 pixel 위치에서 계산한 것과 다르다.
- 해결 방법
- 제타(시점과 vertex의 z축 위에서의 거리)를 이용해 보정
블린-퐁 쉐이딩
- 쉐이딩이란 조명과 재질의 상호작용을 고려해 색을 결정하는 과정
- 쉐이딩은 vertex에서 할 수 도 있고 pixel에서도 할 수 있다.
- vertext의 수가 훨씬 적기 때문에 vertex shading이 더 빠르다.
- 하지만 상세도가 낮겠죠
- vertext의 수가 훨씬 적기 때문에 vertex shading이 더 빠르다.
- 반사 벡터는 계산이 오래 걸리므로 Halfway Vector와, normal vector를 이용해 퐁 쉐이딩을 개선한 쉐이딩
- halfway vector는 빛 벡터와 시야 벡터의 half vector
- halfway vector 와 normal vector를 dot product한 값을 이용한다.
light strength
- 빛의 각도와 normal 벡터를 이용해 빛의 각도 계산
diffuse Reflection
specular Reflection
- 특정 방향으로 빛을 강하게 반사.
- halfway 와 normal을 내적한 값을 shiness 만큼 pow한 결과 값
shiness
- 빛이 집중되는 정도
결과
- ambient + (diffuse + specular) * lightStr;
조명
- directional light, point light, spotlight 등이 있다.
point light
- 포인트로 부터 멀어질 수록 빛의 세기가 감소한다.
- linear 하게 falloffstart -> fallofend(여기선 빛의 세기가 0) 해주면 된다.
wire frame
- 삼각형의 변만 보여준다
- backface culling도 가능
normal vector 그리기
- DirectX 에는 normal vector 그려주는 메서드 없다.
- D3D11_PRIMITIVE_TOPOLOGY_LINELIST
- 선분을 그릴 때 사용
- 한 화면에 겹쳐 그릴때는 ClearRenderTargetView, ClearDepthStencilView, SetViewport, SetRenderTarget, SetDepthStencilState 등은 한번만 해주는 것이 맞다..
- BasicVertexConstantBuffer에 이미 행렬들이 들어가 있는 부분들은 제외하고 NormalVertexConstantBuffer를 만들어 넣어주면 된다.
- 그럼 Update에서도 행렬들을 이용한 계산을 중복해서 하지 않아도 된다.
- shader 에서도 맞춰서 수정해주어야함
- 변화가 있을 때만 업데이트 해주도록 최적화 할 수도 있겠죠
- flag를 이용해 update 부분은 Update에 몰아주는 것이 관리하기 좋다.
격자 평면
- 지형, 실린더, 구 모형 등 구현 시 유용한 모델링 기술
실린더
- 원형인 경우 텍스처의 좌표 0~1을 맞춰주기 위해 시작점의 vertex는 두개로 해주어야 한다.
subdivision
- 해상도가 낮은 물체를 높은 물체로 만드는 기능
- 삼각형을 여러 삼각형으로 쪼갬
- 새로 생긴 vertex들의 포지션을 조절해주어야 함
- GPU에서 할 수 있는 기능이므로, CPU에서는 해상도가 낮게 만들어 보내 GPU에서 높게 만드는 장점
Face vs Vertex Normals
- normal vector가 렌더링에 어떻게 영향을 미치는 지
- 같은 위치여도 vertex가 여러개이면, normal vector가 여러개 일 것이고,,
- 각져있게된다?
구 매핑
- subdivision 하다보면 텍스쳐 이음매가 깔끔하지 않음..
- 맞닿는 부분의 삼각형의 vertex 의 texture 좌표가 (0,0), (1,0) 이렇게 되는 경우 깨질 수 있다.
- pixel 쉐이더를 이용하면 해결 가능
3차원 모델 파일 읽기
- 언리얼에서는 FBX를 주로 사용
- assimp:x64-windows
vcpkg install assimp:x64-windows vcpkg install directxtk:x64-windows vcpkg install directxtex[openexr]:x64-windows vcpkg install directxmath:x64-windows vcpkg install fp16:x64-windows vcpkg install imgui[dx11-binding,win32-binding]:x64-windows vcpkg install glm:x64-windows vcpkg install directxmesh:x64-windows vcpkg install eigen3:x64-windows (파트4) vcpkg install physx:x64-windows <- PHYSX 물리 엔진 (파트4)
Rim 효과
- 물체의 테두리에 역광 효과
- 가장자리를 먼저 찾아야 겠죠.
- 시야와 normal vector의 각도가 90가 되는 점이 눈에 보이는 가장자리이다.
- dot product 이용.,.
큐브 매핑
피킹 광선 충돌
- BoundingSphere
자유도
- Degrees of Freedom (DOF)
- 3차원 공간의 회전의 자유도는 3자유도이다.
오일러 각도
- 3차원의 회전을 세개의 각도로 표현
- 3x3 회전행렬들의 곱으로 계산
짐벌락
- 두 축이 겹쳐지면 자유도를 하나 잃어버림
- 수식으로 찾아보자.
- 두 축이 겹쳐졌을 때 겹쳐진 두 벡터의 외적은 0벡터이다.
- 그래서 예전 게임의 경우 두 축이 겹칠때 막 회전하는 오류가 발생하기도 했다.
쿼터니언
- Quaternion(사원수)
- 3차원 회전을 4개의 수로 표현한다.
- 짐벌락 방지
- 숫자가 네개지만 합의 절댓값이 1이어야하는 제약이 있어 3자유도가 되어 3차원 회전을 표현하게된다.
- 회전 행렬과 호환되며, 회전의 보간(interpolation)에 유리하다.
쿼터니언 회전 방법
- 벡터 v를 n 축에 대해 theta 만큼 회전시킨다면,
- v를 쿼터니언으로 먼저 만들고
- p = Quaternion(v, 0)
- 회전을 위한 q = Quaternion(nsin(theta/2), cos(theta/2))과 이 Quaternion의 conjugate Quaternion인 q*를 만든다.
- qpq* 를 계산하면 된다.
쿼터니언의 구성
- q = xi + yj + zk + w
- i, j, k는 허수, w는 실수이다.
- 허수와 실수를 묶어 간단히 벡터처럼 (u, w) 로 표현하기도 한다.
- 가로축을 실수, 세로축을 허수로 두는 등 2차원에 표현 가능해짐
- q = 1 -> q = i 가 되면 즉, i를 곱하면 실수축에서 허수축으로 90도만큼 회전 효과가 일어난 것으로 볼 수 있다.
- 가로축을 실수, 세로축을 허수로 두는 등 2차원에 표현 가능해짐
- i, j, k는 각각 제곱하면 -1이다.
- 두 허수의 곱은 나머지 한 허수와 같고, 또한 두 허수를 뒤집어 곱한 값에 -를 곱한 값과 같다.
- ij = k = -ji
쿼터니언의 연산
- +, -는 각각의 원소끼리 +, -
- 곱하기는 다항식의 곱으로 보면 된다.
- q1(u1, w1) * q2(u2, w2) 를 잘 정리해보면,
- (w1u2 + w2u1 + u1Xu2, w1w2 - u1*u2) 로 외적과 내적으로 표현 가능하다.
절댓값
- $x^2 + y^2 + z^2 + w^2$ 를 루트씌워준 값.
Conjugate
- q(u, w) 의 conjugate Quaternion 은 q*(-u, w)
Inverse
- q(u, w) 의 Inverse Quaternion 은..
- 먼저 q와 q*의 곱은 q나 q*의 절댓값과 같다.
- 이를 이용하면 $q^{-1}$ = q* / (q의절댓값) 이라 볼 수 있다.
- q의 절댓값이 1이라면 Inverse Quaternion은 Conjugate Quaternion 이 되겠죠
MVP
- model , view, projection?
- model coordinates를 model matrix(혹은 world matrix)를 통해 world coordinates로 변환
- world coordinates를 view matrix를 통해 camera coordinates로 변환
- camera coordinates를 projection matrix를 통해 Homogeneous coordinates로 변환
가상 트랙볼
- 물체의 bounding sphere를 회전시킨다고 보면 된다.
- 한 지점에서 다른 지점으로 회전시킨다고 할때 회전 축은 두 지점 벡터의 cross product 결과겠죠
- 각도는 두 벡터를 normalize하고 dot product를 통해 구하면 된다.
드래그로 이동시키기
기하 쉐이더
- 점 하나만 넘겼을 떄 여러 점으로 바꾸는 작업을 해보자.
- 점 여러개를 그리기 위해 topology를 D3D11_PRIMITIVE_TOPOLOGY_POINTLIST 로 해뒀다
- Geometry shader 만 바꿔서 점을 사각형으로 만들어 보자.
Graphics Pipeline
- vertex shader
- 3차원 모델을 변화시키는 작업
- pixel shader
- 최근엔 쉐이딩은 여기서 한다.
Geometry Pipeline
- 기하 정보를 처리해 주는 Pipeline
- Graphics Pipeline의 일부
- subdivision 처럼 CPU에서는 GPU로 낮은 해상도의 정보를 보내고
- GPU에서 고해상도로 변환하는 작업을 요즘 많이한다.
- 이가 여기서 구현된다.
Geometry shader
- vertex 하나씩 Geometry shader로 들어온다
- 세개씩 묶어 pixel shader로 보낸다.
- [maxvertexcount(숫자)]
- Geometry shader 가 한번 실행 될 때 괄호안의 숫자를 최대로 하는 vertex 생성 가능
- inout PointStream
outputStream - 을 통해 vertex들을 출력한다.
- point GeometryShaderInput input[1] 를 통해 Geometry shader로 들어옴
- point 하나 단위로 들어 온다는 의미.
- outstream에 point를 4개 넣는 방법과 6개 넣는 방법이 있다.
- triangle strip
- Geometry shader가 vertex를 출력할 때, 내부적으로 triangle strip을 사용한다.
- vertex 4개만 넣으면 사각형을 그릴 수 있다. 대신, 순서를 잘 해야함.
- 즉, 4개가 들어오면 내부적으로 사각형으로 인식해 사각형을 그려버린다.
- triangle List
- 사각형을 그리기 위해 삼각형이 두개 필요하고, vertex 6개가 필요했음.
- 이렇게 사각형을 그리려면 먼저 vertex 세개를 보내고, outputStream.RestartStrip() 해준 뒤 다시 보내주어야 한다.
- triangle strip
빌보드(Billboards)
- 멀리있는 배경 구현시 자주 사용된다.
-
시점을 향해 회전한다.
- 텍스쳐가 여럿 있을 때 각각을 다루는 것은 불편한 일이다..
- 텍스쳐 array를 이용하자.
- 단, 텍스쳐들의 이미지 해상도가 동일해야 한다.
- ID3D11Texture2D를 그대로 이용하면 됨
- ID3D11ShaderResourceView 도 같이 초기화 해주어야 한다.
- D3D11_SUBRESOURCE_DATA 도 array로 해주어야한다.
- 텍스쳐 array를 이용하자.
텍스처
- 텍스처를 실제로 쉐이더에 넣어 주려면 D3D11_SHADER_RESOURCE_VIEW_DESC 를 이용하면 된다.
- shader resource view가 필요하므로.
- PSSetShaderResources 를 통해 pixel shader에게 지정해 주면 된다.
- 또 텍스처를 사용하려면 텍스쳐 좌표도 있어야 겠죠(texcoord)
- Geometry shader 에서 텍스처 좌표를 만들어 보내도 된다.
픽셀 쉐이더
- texture array 사용 시 샘플러를 사용할 때 3차원의 좌표를 사용해 준다.(uvw)
- 텍스쳐의 빈 부분을 표현하기 위해 hlsl의 clip 함수를 이용해 주자
노말 벡터 그리기
- 기존에 그렸던 방식 말고 Geometry shader를 이용해 그려보자
- vector<shared_ptr
> m_meshes 에 vertex 정보가 다 저장되어 있는 상태이다.
파이어 볼
- 빌보드를 이용해 만들어 보자
- ray tracing 이용하기
기하 분할(Tessellation)
- 해상도를 높여주는 단계 중 하나
- 어떤 면을 여러 개의 조각으로 쪼개주는 역할을 한다.
- subdivision 등과 연계한다.
- 사용하는 이유는,
- 해상도를 조절하기 위해서다.
- 멀리있는 물체는 해상도를 낮추고, 가까이 있는 물체는 해상도를 높이는데 사용한다.
- LOD(level of detail) 이라고 부름
- Tessellation stage 를 이용하기 위해서는,
- Graphics Pipeline 을 보면 알 수 있듯이,
- Hull-Shader 와 Domain-Shader 를 구현해 주어야 한다.
- Hull : 껍데기
- Hull-Shader 와 Domain-Shader 를 구현해 주어야 한다.
- Graphics Pipeline 을 보면 알 수 있듯이,
- 여기서 처음 입력되는 vertex들을 control points 라고도 한다.
- 기하학적 모양을 정의할 때 이 형상을 제어할 수 있는 포인트 들을 말한다.
- topology를 D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST 로 해준다.
hull shader
- VertexOut 으로부터 받아온 position 정보를 Hullout 구조체를 통해 내보낸다.
- 그리고 어떻게 쪼개줄지 함수도 출력한다.
- MyPatchConstantFunc
- InputPatch<VertexOut, 4> patch
- vertexout 4개짜리 배열
- 이를 이용해 구현해보자
- vertex 하나 당 한번 실행된다고 보면 된다.
- 배열을 넣어주고 ID를 통해 구분.
- partitioning
- integer
- fractional_even
- fractional_odd
- pow2
- outputtopology
- triangle_cw
- 시계방향 삼각형으로 만든다
- triangle_cw
- outputcontrolpoints
- 스레드 하나당 출력할 control points 숫자
- patchconstantfunc
- 파라미터로 사용할 함수의 이름을 문자열로 넣어주면 된다
- maxtessfactor
- Tessellation 할 최대 수
- 실습에선 MyPatchConstantFunc 만 수정해주면 된다.
- Tessellation stage 는 DirectX 가 내부적으로 알아서 처리하므로 구현하지 않아도 된다.
과정
- Patch control points 들이 hull shader 로 들어온다.
- hull shader 는 Patch control points 와 Patch constant data 를 내보낸다.
Domain Shader stage
- Tessellation 된 vertex 들의 좌표를 구해 보내주는 역할이다.
과정
- hull shader의 output control points와 Tessellation stage 의 output texture coordinates 를 받는다.
- vertex position 을 출력한다.
참고
- Introduction to 3D Game programming with DX12 - Luna
주의
- 회전 시킬 때 normal vector도 회전시켜주어야 한다.
Leave a comment