새소식

인기 검색어

게임 개발/그래픽스

[그래픽스] Line-sphere Intersection 을 이용해 3차원 구 그리기

  • -

참고자료:

https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection

  1. 구의 식과 직선의 식을 d에 대해서 풀면 구와 직선의 intersection에 대해 구할 수 있다.
  2. 두 식을 연립방정식의 해를 구하듯이 구할 수 있다.
  3. 식을 정리하면 2차 방정식같은 형태가 나오고, 이를 근의 공식으로 구한다.
  4. ∇나블라(nabla) 를 구한다음 이를 이용해, d를 구한다.
    • ∇>0: 만나는 점이 2개, +- 에 대해 모두 각각 따로 구해야 한다.
    • ∇==0: 만나는 점이 1개
    • ∇<0: 만나지 않는다
    • d 값이 음수면 충돌하지 않은 것

 

위 방식을 그래픽스의 3차원 구 그리기에 활용할 수 있다.

이때는

u : direction of line (a non-zero vector) 의 값을 유닛 벡터로 사용한다.

따라서 ||u||^2 의 값은 1로 단순화 할 수 있다.

 

이 방식으로 ray를 쏴서 구에 hit 하는 지점까지의 거리를 구할 수 있다.

-> d값이 2개라면 작은 값을 선택하면 된다(가까운 쪽에 먼저 닿을거고, 먼쪽은 가까운쪽을 뚫고 나올때 부딪히는 부분일테니까)

 

class Sphere { public: glm::vec3 center; float radius; glm::vec3 color; // 뒤에서 '재질(material)'로 확장 Sphere(const glm::vec3 &center, const float radius, const glm::vec3 &color) : center(center), color(color), radius(radius) { } // Wikipedia Line–sphere intersection // https://en.wikipedia.org/wiki/Line-sphere_intersection Hit IntersectRayCollision(Ray &ray) { Hit hit = Hit{-1.0f, vec3(0.0f), vec3(0.0f)}; // d가 음수이면 충돌을 안한 것으로 가정 /* * hit.d = ... // 광선의 시작점으로부터 충돌지점까지의 거리 (float) * hit.point = ... // 광선과 구가 충돌한 지점의 위치 (vec3) * hit.normal = .. // 충돌 지점에서 구의 단위 법선 벡터(unit normal vector) */ // Nabla = (origin - center)^2 - (||origin - center||^2 + radius^2) const float nabla = pow(glm::dot(ray.dir, ray.start - this->center),2) - (pow(glm::length(ray.start - this->center), 2) - pow(this->radius, 2)); // d = -direction * (origin - center) +- sqrt(nabla) if (nabla < 0.0f) { return hit; // 광선이 구와 충돌하지 않음 } else if (nabla == 0.0f) { hit.d = -glm::dot(ray.dir, ray.start - this->center); hit.point = ray.start + ray.dir * hit.d; hit.normal = glm::normalize(hit.point - center); } else { // 두 값중 작은 값이 더 가까운 충돌 지점 const float d1 = -glm::dot(ray.dir, ray.start - this->center) + sqrt(nabla); const float d2 = -glm::dot(ray.dir, ray.start - this->center) - sqrt(nabla); hit.d = glm::min(d1, d2); hit.point = ray.start + ray.dir * hit.d; hit.normal = glm::normalize(hit.point - this->center); } return hit; } };
Contents

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

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