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 |
댓글