새소식

인기 검색어

게임 개발/그래픽스

텍스처링, 무게 중심 좌표계 (Barycentric coordinates), 선형 보간 (Linear Interpolation)

  • -

텍스처링(texturing)이란?

사진을 3차원으로 렌더링된 물체에 입혀주는 기술

직접 색깔을 일일히 지정해주는게 아니라 사진, 이미지등을 입혀주면 편하다.

 

무게 중심 좌표계 (Barycentric coordinates)

https://en.wikipedia.org/wiki/Barycentric_coordinate_system

 

Barycentric coordinate system - Wikipedia

From Wikipedia, the free encyclopedia Coordinate system that is defined by points instead of vectors A 3-simplex, with barycentric subdivisions of 1-faces (edges) 2-faces (triangles) and 3-faces (body). In geometry, a barycentric coordinate system is a coo

en.wikipedia.org

Barycentric coordinates are used for blending three colors over a triangular region evenly in computer graphics.

Linear Interpolation (선형 보간)

만약 3과 5사이 중간의 값을 물어본다면?

-> 4라고 답할것임.

그렇다면 그 4에서 3쪽으로 조금 이동하면 숫자는 어떻게 될까?

-> 3쪽으로 더 가까운 값이 될 것임.

즉, v0와 v1사이의 값 v는

interpolation의 개념

v = (v가 v1와 얼마나 떨어졌는가) * (v0) + (v가 v0와 얼마나 떨어졌는가) * (v1)

으로 표현할 수 있다.

이를 그래프로 그려보면 다음과 같이 선형(linear) 그래프가 나오는 것을 알 수 있다.

선형 보간 (Linear Interpolation)

다시 무게 중심 좌표계로 돌아와서...

이제 두 점이 아닌 세 개의 점 사이의 어떤 값에 대해 이야기 해 보자.

세 점 중간 어딘가에 있는 한 점의 위치는 다음 그림처럼 주어진 세 점을 이어 삼각형을 그리고 그 삼각형을 세개로 쪼개서 각 삼각형의 넓이를 이용해서 구할 수 있다.

예를들어 v0 와 얼마나 가까운가? v0와 가까울수록 v0에 가까운 값이 나올 것이다. 어떤 점 건너편에 있는 삼각형(a0)의 넓이에 비례해서 v0와 가까울 것이다. 즉, a0의 넓이가 클수록 v0에 가깝다.

각 삼각형의 넓이는 cross product 를 이용해 구한다.

팁이 있다면, 마지막 weight는 이미 구한 2개의 weight를 이용해서 구하면 계산량이 줄어든다.

 

무게 중심 좌표계

v0, v1, v2의 색이 정해져 있고, 그 사이의 색깔도 같은 방식으로 구할 수 있다.

// 참고: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/ray-triangle-intersection-geometric-solution
bool IntersectRayTriangle(const vec3 &orig, const vec3 &dir,
                          const vec3 &v0, const vec3 &v1,
                          const vec3 &v2, vec3 &point, vec3 &faceNormal,
                          float &t, float &w0, float &w1)
{
    /*
     * 기본 전략
     * - 삼각형이 놓여있는 평면과 광선의 교점을 찾고,
     * - 그 교점이 삼각형 안에 있는지 밖에 있는지를 판단한다.
     */

    /* 1. 삼각형이 놓여 있는 평면의 수직 벡터 계산 */
    faceNormal = glm::normalize(glm::cross(v1 - v0, v2 - v0));
    //주의: 삼각형의 넓이가 0일 경우에는 계산할 수 없음

    // 삼각형 뒷면을 그리고 싶지 않은 경우 (Backface culling)
    if (dot(-dir, faceNormal) < 0.0f)
        return false;

    // 평면과 광선이 수평에 매우 가깝다면 충돌하지 못하는 것으로 판단
    if (glm::abs(dot(dir, faceNormal)) < 1e-2f)
        return false; // t 계산시 0으로 나누기 방지

    /* 2. 광선과 평면의 충돌 위치 계산 */
    t = (dot(v0, faceNormal) - dot(orig, faceNormal)) /
        (dot(dir, faceNormal));

    // 광선의 시작점 이전에 충돌한다면 렌더링할 필요 없음
    if (t < 0.0f)
        return false;

    point = orig + t * dir; // 충돌점

    /* 3. 그 충돌 위치가 삼각형 안에 들어 있는 지 확인 */

    // 작은 삼각형들 3개의 normal 계산
    // 방향만 확인하면 되기 때문에 normalize() 생략 가능
    const vec3 cross0 = glm::cross(point - v2, v1 - v2);
    const vec3 cross1 = glm::cross(point - v0, v2 - v0);
    const vec3 cross2 = glm::cross(v1 - v0, point - v0);

    if (dot(cross0, faceNormal) < 0.0f)
        return false;
    if (dot(cross1, faceNormal) < 0.0f)
        return false;
    if (dot(cross2, faceNormal) < 0.0f)
        return false;

    // Barycentric coordinates 계산
    // 텍스춰링(texturing)에서 사용
    // 아래에서 cross product의 절대값으로 작은 삼각형들의 넓이 계산
    // 삼각형의 넓이 구하는데 *0.5는 생략가능. 어차피 비율만 따질거라서
    const float area0 = glm::length(cross0); 
    const float area1 = glm::length(cross1);
    const float area2 = glm::length(cross2);

    const float areaSum = area0 + area1 + area2;
    // const float areaSum = glm::length(glm::cross(v1 - v0, v2 - v0)) * 0.5f; // 이렇게도 구할 수 있음

    // 기호에 alpha, beta, gamma 또는 u, v, w 등을 사용하기도 함
    w0 = area0 / areaSum;
    w1 = area1 / areaSum;
    // w2 = area2 / areaSum 또는 점이 삼각형 안에 있는것이 확실하다면 w2 = 1.0f - w0 - w1 도 가능

    return true;
}

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.