GameChoi
Choi Programming
GameChoi
전체 방문자
오늘
어제
  • 분류 전체보기 (468)
    • C++ Algorithm & Study (184)
      • C++ & Algorithm Strategies (45)
      • Game Math & DirectX 11 (72)
      • Server + UE5 (29)
      • Lyra Clone Coding (37)
    • Create Game (284)
      • [Window API] Game Client & .. (55)
      • [DirectX] DirectX 2D & 3D (155)
      • [UE5] BLUEPRINT & C++ (74)
    • odds and ends (0)
      • English (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Game Room
  • Direct3D
  • Direct11
  • Algorithm Strategies
  • Destination Move Packet
  • server
  • Player State
  • protobuf
  • Other Character
  • job queue
  • GAME Client
  • UE5
  • core
  • session
  • client
  • c++
  • Network Worker
  • RPG Game
  • Game Server
  • Player Move Packet

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
GameChoi

Choi Programming

[Direct11] 40. 3D Direct Application - Terrian Rendering #2
C++ Algorithm & Study/Game Math & DirectX 11

[Direct11] 40. 3D Direct Application - Terrian Rendering #2

2023. 6. 30. 19:57

1. 3D Direct Application

1.1 Terrian Rendering

1.1.1 Terrian Rendering System

1.1.1.1 Frustum

 - 지형 패치들 중 대다수는 카메라에 보이지 않음, 절두체 선별을 적용하면 성능이 개선될 가능성이 큼

   - 한 패치의 테셀레이션 계수들이 모두 0이면 GPU는 그 패치를 더이상 처리하지 않고 폐기

     - 시야 절두체의 평면, 패치를 감싸는 경계입체가 필요

void ExtractFrustumPlanes(XMFLOAT4 planes[6], CXMMATRIX M);

 - 각 패치는 사각형이므로 축 정렬 경계상자를 경계입체로 사용

   - 패치들은 xz평면에 규칙적으로 배치, 패치 제어점들의 x, z성분의 경계는 아주 간단히 구할 수 있음

     - y 성분의 경계를 구하기 위해 전처리 단계를 밟을 필요가 있음

       - 하나의 패치는 높이맵의 여러 원소들을 덮음, 각 패치마다 그 패치가 포괄하는 높이맵 원소들을 훑으면서 y 성분의 최댓 값과 최솟 값을 구해 그 최대, 최솟값을 패치의 상단 왼쪽 제어점에 저장

 - 2차원 배열을 생성하여 x 성분에 y의 최소, y성분의 y의 쵀댓값을 저장

void Terrain::CalcAllPatchBoundsY()
{
    _patchBoundsY.resize(_numPatchQuadFaces);
    for (uint32 i = 0; i < _numPatchVertRows - 1; ++i)
        for (uint32 j = 0; j < _numPatchVertCols - 1; ++j) CalcPatchBoundsY(i, j);
}

   - 이 패치가 포괄하는 높이맵 원소들을 훑으면서 최대, 최소 높이를 구함

void Terrain::CalcPatchBoundsY(uint32 i, uint32 j)
{
    uint32 x0 = j * CellsPerPatch; uint32 x1 = (j + 1) * CellsPerPatch;
    uint32 y0 = i * CellsPerPatch; uint32 y1 = (i + 1) * CellsPerPatch;

    float minY = +MathHelper::Infinity; float maxY = -MathHelper::Infinity;
    for (uint32 y = y0; y <= y1; ++y)
	{
        for (uint32 x = x0; x <= x1; ++x)
        {
            uint32 k = y * _info.heightmapWidth + x;
            minY = MathHelper::Min(minY, _heightmap[k]);
            maxY = MathHelper::Max(maxY, _heightmap[k]);
        }
    }
    uint32 patchID = i * (_numPatchVertCols - 1) + j;
    _patchBoundsY[patchID] = XMFLOAT2(minY, maxY);
}

1.1.1.2 Hull Shader

 - 상수 덮개 셰이더에서 패치마다 해당하는 최대, 최솟값을 이용하여 경계상자를 만듦

   - 상자 대 절두체 교차 판정을 통해 현재 패치의 경계상자가 절두체 바깥에 있는 지 판정

     - OBB 대 평면 판정의 특별한 경우이므로 경계상자가 축에 정렬되어 있으므로 반지름 r에 대한 공식을 사용

1.1.1.2.1 AABB Behind Plane

bool AabbBehindPlaneTest(float3 center, float3 extents, float4 plane);

 - 상자 전체가 평면의 뒤쪽에 있으면 True 반환

   - 상자의 중점이 평면 뒤쪽으로 거리 e 이상 떨어져 있으면 상자 전체가 평면의 음의 빈공간에 있음

float3 n = abs(plane.xyz); float r = dot(extents, n);
float s = dot(float4(center, 1.0f), plane);
return (s + r) < 0.0f;

1.1.1.2.2 AABB Outside Frustum

bool AabbOutsideFrustumTest(float3 center, float3 extents, float4 frustumPlanes[6]);

 - 상자 전체가 절두체 바깥이면 True 반환

   - 상자 전체가 절두체의 적어도 한 평면의 뒤쪽에 있다면 상자는 절두체 바깥에 있음

for (int i = 0; i < 6; ++i)
    if (AabbBehindPlaneTest(center, extents, frustumPlanes[i])) return true;
return false;

1.1.2.2 Constant Hull Shader

PatchTess ConstantHS(InputPatch<VertexOut, 4> patch, uint patchID : SV_PrimitiveID);

 - 절두체를 선별하기 위해 패치의 BoundsY의 첫 번째 제어점에 저장 (이전에 생성한 최대, 최소 저장 위치)

float minY = patch[0].BoundsY.x; float maxY = patch[0].BoundsY.y;

   - 축 정렬 경계상자를 생성 및 AABB 중점 및 한계 표현 생성

     - 패치의 2의 경우 왼쪽 하단 모퉁이 제어점, 1의 경우 오른쪽 상단 모퉁이 제어점

float3 vMin = float3(patch[2].PosW.x, minY, patch[2].PosW.z);
float3 vMax = float3(patch[1].PosW.x, maxY, patch[1].PosW.z);
float3 boxCenter = 0.5f * (vMin + vMax); float3 boxExtents = 0.5f * (vMax - vMin);

   - 경계 상자가 안에 있는 지 확인하고 바깥에 있는 경우 모두 0으로 처리

if (AabbOutsideFrustumTest(boxCenter, boxExtents, gWorldFrustumPlanes))
{
    pt.EdgeTess[0] = 0.0f; pt.EdgeTess[1] = 0.0f;
    pt.EdgeTess[2] = 0.0f; pt.EdgeTess[3] = 0.0f;

    pt.InsideTess[0] = 0.0f; pt.InsideTess[1] = 0.0f;
    return pt;
}

1.1.2.3 Get Height

float Terrain::GetHeight(float x, float z) const

 - 지형을 렌더링하는 응용 프로그램에 주어진 x, z 좌표성분에 해당하는 지형표면의 높이를 구해야하는 경우가 많음

   - 그 높이는 지형 표면에 물체를 배치하거나, 카메라를 지형 표면보다 약간 위쪽에 배치하고자 할 때 유용

    - 높이맵은 격자점들에서의 지형 정점의 높이를 제공, 필요한 것은 그 정점들 사이에 있는 지형의 한 위치의 높이

 - 주어진 이산적인 높이맵 표본들을 적절히 보간함으로써 지형을 나타내는 연속적인 표면을 형성

   - 지형을 하나의 삼각형 메시로 근사하므로 선형 보간을 사용하는 것이 바람직함

 - 주어진 x, z 좌표가 속한 격자 낱칸이 무엇인지를 파악

   - 지형 국소 공간을 낱칸 공간으로 변환 및 주어진 위치가 속한 행과 열을 구함

float c = (x + 0.5f * GetWidth()) / _info.cellSpacing;
float d = (z - 0.5f * GetDepth()) / -_info.cellSpacing;
int row = (int)floorf(d); int col = (int)floorf(c);

   - 주어진 위치가 속한 낱칸을 알아낸 다음 그 낱칸의 네 정점의 높이를 높이맵에서 알아냄

// A -- B
// |  / |
// | /  |
// C -- D
float A = _heightmap[row * _info.heightmapWidth + col];
float B = _heightmap[row * _info.heightmapWidth + col + 1];
float C = _heightmap[(row + 1) * _info.heightmapWidth + col];
float D = _heightmap[(row + 1) * _info.heightmapWidth + col + 1];

   - 이제 주어진 위치가 속한 낱칸과 네 정점의 높이들을 알게 됨

     - 필요한 것은 표면의 그 위치에서의 높이를 구하는 것, 하나의 낱칸이 두가지 방향으로 기울수 있기에 까다로움

 - 높이를 구하려면 그 위치가 낱칸의 두 삼각형 중 어떤 것에 있는지를 알아야 함

   - 이를 위해 좌표를 한 낱칸 안의 공간을 규정하는 또 다른 좌표계로 변환, 이동으로만 구성된 간단한 변환

float s = c - (float)col; float t = d - (float)row;

 - s와 t를 더해 1보다 작은 경우 위쪽 삼각형에 있는 것이고, 그렇지 않으면 아래쪽 삼각형에 있는 것

   - 종점 A에서 시작하는 삼각형 두변의 벡터를 구해 u에 따라 s만큼 선형 보간하고 v를 따라 t만큼 선형 보간해서 삼각형 내부의 한점을 구함

     - 그 점의 y 성분이 바로 주어진 x, z위치의 높이, 높이만 구하는 것이기 때문에 y 성분만 보간 후 다른 성분 무시

if (s + t <= 1.0f) { float uy = B - A;  float vy = C - A;  return A + s * uy + t * vy; }
else { float uy = C - D;  float vy = B - D; return D + (1.0f - s) * uy + (1.0f - t) * vy; }

 - 높이를 이용해 카메라를 지형 표면 조금 위쪽에 배치함으로써 지형 위를 걸어 다니는 듯한 상황을 연출할 수 있음

if (_walkCamMode)
{
    XMFLOAT3 camPos = _camera.GetPosition();
    float y = _terrain.GetHeight(camPos.x, camPos.z);
    _camera.SetPosition(camPos.x, y + 2.0f, camPos.z);
}
_camera.UpdateViewMatrix();
저작자표시 (새창열림)

'C++ Algorithm & Study > Game Math & DirectX 11' 카테고리의 다른 글

[Direct11] 42. 3D Direct Application - Particle System #2  (0) 2023.07.03
[Direct11] 41. 3D Direct Application - Particle System #1  (0) 2023.07.03
[Direct11] 39. 3D Direct Application - Terrian Rendering #1  (0) 2023.06.30
[Direct11] 38. 3D Direct Application - Displacement Mapping  (0) 2023.06.30
[Direct11] 37. 3D Direct Application - Normal Mapping  (0) 2023.06.30
    'C++ Algorithm & Study/Game Math & DirectX 11' 카테고리의 다른 글
    • [Direct11] 42. 3D Direct Application - Particle System #2
    • [Direct11] 41. 3D Direct Application - Particle System #1
    • [Direct11] 39. 3D Direct Application - Terrian Rendering #1
    • [Direct11] 38. 3D Direct Application - Displacement Mapping
    GameChoi
    GameChoi

    티스토리툴바