본문 바로가기
Metal

무게 중심 좌표계, Barycentric coordinates

by ARpple 2024. 4. 30.

 

 

Barycentric coordinate system - Wikipedia

From Wikipedia, the free encyclopedia Coordinate system that is defined by points instead of vectors Barycentric coordinates ( λ 1 , λ 2 , λ 3 ) {\displaystyle (\lambda _{1},\lambda _{2},\lambda _{3})} on an equilateral triangle and on a right triangle.

en.wikipedia.org

삼각형 색상 보간

삼각형의 각 꼭짓점에 3원색을 선언하고 삼각형 내부의 색상은 내삽을 이용해서 처리하기

Interpolation

하나의 직선 위에 Interpolation

 

삼각형 Interpolation

용어 정리

  • V ⇒ 삼각형 꼭짓점의 좌표
  • C ⇒ 색상 좌표 (R,G,B), 0(검정) ~ 1(흰) 값을 가진다
  • P ⇒ 삼각형 위에 한 점의 좌표
  • W ⇒ 삼각형 꼭짓점 중 한 점의 가중되는 정도
  • a ⇒ P를 중심으로 삼각형 꼭짓점을 이용해 만든 세개의 작은 삼각형의 면

Metal로 구현하기

필요 및 추가 된 데이터 구조

  • Hit → 광선, 물체간 충돌 시 유의미한 데이터
    • 충돌한 곳에서의 삼각형 꼭짓점의 가중치
      ⇒ 2 꼭짓점 가중치만 갖는다. 나머지 하나는 (1 - 2꼭짓점 가중치)로 구할 수 있다.
  • Triangle → 삼각형 객체
  • ObjProtocol → 객체들을 정의하는 프로토콜
    • 객체의 고유성을 만족하기 위한 Identifiable 프로토콜 채택
    • protocol ObjProtocol:Identifiable{ var id:UUID { get set } ... }

Triangle method 확장

✅ Interpolation할 세 점 사이의 가중치를 구하기
struct Triangle:ObjProtocol{
...
    func intersectRayTriangle(_ rayStart:vf3,_ rayDir: vf3,point:inout vf3,fN faceNormalize:inout vf3,
                              t:inout Float32,w0:inout Float32, w1:inout Float32) -> Bool{

        // 평면의 법선 벡터
        faceNormalize = simd_cross(v1 - v0, v2 - v0)
        if simd_dot(-rayDir, faceNormalize) < 0 { return false }
        if abs(simd_dot(rayDir, faceNormalize)) < 1e-2 { return false }
        t = (dot(v0,faceNormalize) - dot(rayStart,faceNormalize)) / dot(rayDir, faceNormalize)
        if t < 0.0 {return false} // 광선의 진행이 원하는 것과 반대로 진행됨

        // 광선이 평면에 만나는 점의 위치 벡터
        point = rayStart + rayDir * t

        // 작은 삼각형들의 법선 벡터
        // 방향만 확인하면 되기 때문에 normalize 생략 후 무게중심 좌표에 사용
//        let normal0 = simd_normalize(simd_cross(point - v2, v1 - v2))
//        let normal1 = simd_normalize(simd_cross(point - v0, v2 - v0))
//        let normal2 = simd_normalize(simd_cross(v1 - v0, point - v0))
        let cross0 = simd_cross(point - v2, v1 - v2)
        let cross1 = simd_cross(point - v0, v2 - v0)
        let cross2 = simd_cross(v1 - v0, point - v0)

        // 광선이 삼각형 내부에 없으면 false
        if simd_dot(cross0, faceNormalize) < 0 {return false}
        if simd_dot(cross1, faceNormalize) < 0 {return false}
        if simd_dot(cross2, faceNormalize) < 0 {return false}

        let area0 = length(cross0) * 0.5
        let area1 = length(cross1) * 0.5
        let area2 = length(cross2) * 0.5

        let areaSum = area0 + area1 + area2
        w0 = area0 / areaSum // 0번 꼭짓점에 대한 가중치 반환
        w1 = area1 / areaSum // 1번 꼭짓점에 대한 가중치 반환
        return true
        }
...
}

RayTracer에서 보간 색상 적용하기

fileprivate extension RayTracer{
func traceRay(ray: inout Ray)->vector_float3{
        let hit:Hit = findClosestCollision(ray: &ray)
        if hit.d < 0{
            return .init(0, 0, 0)
        }else{
            var pointColor:vector_float3 = hit.obj?.phongMat.amb ?? .zero
            // 충돌한 객체의 ID가 일시적으로 저장한 객체 ID와 같다면
            if hit.obj?.id == self.tempID?.id{ 
                let color0 = vector_float3(1, 0, 0)
                let color1 = vector_float3(0,1,0)
                let color2 = vector_float3(0,0,1)
                let w0 = hit.w.x
                let w1 = hit.w.y
                let w2 = 1 - w0 - w1
                pointColor = color0 * w0 + color1 * w1 + color2 * w2
            }
            var phongColor = phongColor(ray: ray, hit: hit)
            phongColor = phongColor + pointColor
            ...
        }
    }
    }
}

 

'Metal' 카테고리의 다른 글

Perspective Projection & Phong Shading  (0) 2024.04.22
RayTracing으로 삼각형 그리기  (0) 2024.04.08
Raytracing으로 구 그리기  (0) 2024.03.31
블룸 효과 만들기 with Metal  (0) 2024.03.11

댓글