Grid 그리기
Grid
일반적인 ‘사각형’(Vertex 4개) 대신
격자 모양(Grid)을 사용하는 이유?
-
‘지형’ 같은 ‘굴곡’을 표현 가능
(높이맵,Wave,진동, 노멀 등의 응용) -
기하의 vertex를 늘림에 따라
‘윤곽’ 과 그림자 계산을 더욱 사실적으로 계산 가능 -
Sphere, Cylinder 등에 응용 가능
예제 Grid 만들기
Grid는 ‘넓이’와 ‘높이’를 기반으로
slice(가로 개수)와 numStack(세로 개수)를 통해 만든다
따라서 각각의 Slice와 Stack을 적용하여 풀면 된다
Slice(가로 방향만) 구현
MeshData GeometryGenerator::MakeGrid(const float width, const float height,
const int numSlices, const int numStacks) {
const float dx = width / numSlices;
MeshData meshData;
vector<Vertex> &vertices = meshData.vertices;
vector<uint16_t> &indices = meshData.indices;
// y = -0.5f * height 인 점들
Vector3 stackStartPoint = Vector3(-0.5f * width, -0.5f * height, 0.0f);
for (int i = 0; i <= numSlices; i++) {
Vertex v;
// x-y 평면에서 시작점을 x 방향으로 이동
v.position = stackStartPoint;
v.position.x += (width / numSlices) * i;
// 시점을 향하는 방향
v.normal = Vector3(0.0f, 0.0f, -1.0f);
v.texcoord = Vector2(0,1);
v.texcoord.x += (1 / numSlices) * i;
vertices.push_back(v);
}
// y = 0.5f * height 인 점들
stackStartPoint = Vector3(-0.5f * width, 0.5f * height, 0.0f);
for (int i = 0; i <= numSlices; i++) {
Vertex v;
// x-y 평면에서 시작점을 x 방향으로 이동
v.position = stackStartPoint;
v.position.x += (width / numSlices) * i;
// 시점을 향하는 방향
v.normal = Vector3(0.0f, 0.0f, -1.0f);
v.texcoord = Vector2(0, 1);
v.texcoord.x += (1 / numSlices) * i;
vertices.push_back(v);
}
// 인덱스 추가
for (int i = 0; i < numSlices; i++) {
// 첫번째 삼각형
indices.push_back(i);
indices.push_back(i + numSlices + 1);
indices.push_back(i + numSlices + 2);
// 두 번째 삼각형
indices.push_back(i);
indices.push_back(i + numSlices + 2);
indices.push_back(i + 1);
}
return meshData;
}
- x 에 관한 position과 texcoord의 각각의 최댓값인
Width 와 1.0을 numSlices로 ‘나눈’후 각각의 정점의 x값으로 사용
결과
세로 Stack 적용 방식
MeshData GeometryGenerator::MakeGrid(const float width, const float height,
const int numSlices, const int numStacks) {
const float dx = width / numSlices;
MeshData meshData;
vector<Vertex> &vertices = meshData.vertices;
vector<uint16_t> &indices = meshData.indices;
// y = -0.5f * height 인 점들
Vector3 stackStartPoint = Vector3(-0.5f * width, -0.5f * height, 0.0f);
for (int h = 0; h <= numStacks; h++)
{
for (int i = 0; i <= numSlices; i++)
{
Vertex v;
// x-y 평면에서 시작점을 x 방향으로 이동
v.position = stackStartPoint;
v.position.x += (width / numSlices) * i;
v.position.y += (height / numStacks) * h;
// 시점을 향하는 방향
v.normal = Vector3(0.0f, 0.0f, -1.0f);
v.texcoord = Vector2(0, 1);
v.texcoord.x += (1 / numSlices) * i;
v.texcoord.y -= (1 / numStacks) * h;
vertices.push_back(v);
}
}
// 인덱스 추가
for (int i = 0; i <= numSlices * numStacks + 1; i++)
{
if (i % (numSlices + 1) == numSlices )
continue;
// 첫번째 삼각형
indices.push_back(i);
indices.push_back(i + numSlices + 1);
indices.push_back(i + numSlices + 2);
// 두 번째 삼각형
indices.push_back(i);
indices.push_back(i + numSlices + 2);
indices.push_back(i + 1);
}
return meshData;
}
-
반복문을 통하여 y에 관한 부분도 나누어 줌
-
다만 Index를 통하여 ‘마지막’ 점에 해당하는 부분은
index를 건너띈다
결과
예제 구현 코드 (제공)
vertecies 생성
const float dx = width / numSlices;
const float dy = height / numStacks;
MeshData meshData;
vector<Vertex> &vertices = meshData.vertices;
vector<uint16_t> &indices = meshData.indices;
// y = -0.5f * height 인 점들
Vector3 stackStartPoint = Vector3(-0.5f * width, -0.5f * height, 0.0f);
for (int h = 0; h <= numStacks; h++)
{
for (int i = 0; i <= numSlices; i++)
{
Vertex v;
// x-y 평면에서 시작점을 x 방향으로 이동
v.position =
Vector3::Transform(stackStartPoint, Matrix::CreateTranslation(Vector3(dx* float(i),dy* float(h),0.0f));
// 시점을 향하는 방향
v.normal = Vector3(0.0f, 0.0f, -1.0f);
v.texcoord = Vector2(float(i) / numSlices,1 - float(h) / numStacks);
vertices.push_back(v);
}
}
-
dx,dy를 이용
-
- Vector3::Transform 를 사용
- 그냥 y,x에 더해도 되나,
Transform을 통해 Rotation 등의 적용 결과를 방해하지 않을 수 있음
(즉, 회전/스케일 등의 연산 코드가 추가될때, 수정점이 적어짐)
(차후, 실린더나 스피어 구현할때 고려)
- Vector3::Transform 를 사용
- dx의 UV 좌표는 좌측 상단이
(0,0) 이고 현재 grid는 좌측 하단에서 시작하므로
y좌표를 1 - float(h) / numStacks 로 구현
Indices 생성
for (int h = 0; h < numStacks; h++)
{
const int offset = (numSlices + 1) * h;
for (int i = 0; i < numSlices; i++)
{
indices.push_back(offset + i);
indices.push_back(offset + i + numSlices + 1);
indices.push_back(offset + i + 1 + numSlices + 1);
indices.push_back(offset + i);
indices.push_back(offset + i + 1 + numSlices + 1);
indices.push_back(offset + i + 1);
}
}
TMI : Grid 의 z값을 이용하여 지도 표현
grid의 가장 큰 특징인 ‘변형’을 이용하여
물결치는 듯한 표현을 할 수 있다
// stack과 slice 수를 대량으로 늘릴 수록 부드러운 표현 가능
Vector3 stackStartPoint = Vector3(-0.5f * width, -0.5f * height, 0.0f);
for (int h = 0; h <= numStacks; h++)
{
for (int i = 0; i <= numSlices; i++)
{
Vertex v;
// x-y 평면에서 시작점을 x 방향으로 이동
v.position =
Vector3::Transform(stackStartPoint, Matrix::CreateTranslation(Vector3(dx* float(i),dy* float(h),sin(i * dx * 10.0f) * 0.1)));
// 시점을 향하는 방향
v.normal = Vector3(0.0f, 0.0f, -1.0f);
v.texcoord = Vector2(float(i) / numSlices,1 - float(h) / numStacks);
vertices.push_back(v);
}
}
-
z 값 영역에 sin 을 넣어
반복되는 표현을 사용 -
다만 지금은 nomral 값을 수정하지 않기 때문에
표면 등이 다소 어색할 수 있다
댓글남기기