7 minute read

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

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이 더 빠르다.
      • 하지만 상세도가 낮겠죠
  • 반사 벡터는 계산이 오래 걸리므로 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도만큼 회전 효과가 일어난 것으로 볼 수 있다.
    • 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 이 되겠죠

Image

MVP

  • model , view, projection?
    1. model coordinates를 model matrix(혹은 world matrix)를 통해 world coordinates로 변환
    2. world coordinates를 view matrix를 통해 camera coordinates로 변환
    3. 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() 해준 뒤 다시 보내주어야 한다.



빌보드(Billboards)

  • 멀리있는 배경 구현시 자주 사용된다.
  • 시점을 향해 회전한다.

  • 텍스쳐가 여럿 있을 때 각각을 다루는 것은 불편한 일이다..
    • 텍스쳐 array를 이용하자.
      • 단, 텍스쳐들의 이미지 해상도가 동일해야 한다.
    • ID3D11Texture2D를 그대로 이용하면 됨
    • ID3D11ShaderResourceView 도 같이 초기화 해주어야 한다.
    • D3D11_SUBRESOURCE_DATA 도 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 : 껍데기
  • 여기서 처음 입력되는 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
      • 시계방향 삼각형으로 만든다
  • outputcontrolpoints
    • 스레드 하나당 출력할 control points 숫자
  • patchconstantfunc
    • 파라미터로 사용할 함수의 이름을 문자열로 넣어주면 된다
  • maxtessfactor
    • Tessellation 할 최대 수
  • 실습에선 MyPatchConstantFunc 만 수정해주면 된다.
  • Tessellation stage 는 DirectX 가 내부적으로 알아서 처리하므로 구현하지 않아도 된다.

과정

  1. Patch control points 들이 hull shader 로 들어온다.
  2. hull shader 는 Patch control points 와 Patch constant data 를 내보낸다.

Domain Shader stage

  • Tessellation 된 vertex 들의 좌표를 구해 보내주는 역할이다.

과정

  1. hull shader의 output control points와 Tessellation stage 의 output texture coordinates 를 받는다.
  2. vertex position 을 출력한다.

참고

  • Introduction to 3D Game programming with DX12 - Luna

주의

  • 회전 시킬 때 normal vector도 회전시켜주어야 한다.

Leave a comment