[MirRT]#10平面実装[追加]
実際には平面を表す部分がないため,既存のコード,構造体に平面の関数を増やした.やっとインターンシップから抜け出した…!
追加されたコード
ベクトルO:光線起点、 ベクトルD:光線の方向ベクトル(単位ベクトル)、 ベクトルN:平面のベクトル(単位ベクトル)、 ベクトルP 0:平面のある点、 リファレンス
追加されたコード
structures.h
struct s_plane
{
t_point3 center; // 평면의 어느 한 지점.
t_vec3 dir; // 평면이 가리키는 방향, 어떻게 기울여져 있는지
};
平面情報を含む構造体を作成します.平面は、ある点であるベクトルに無限に延びる形状であるため、範囲は存在しない.
hit.c
#include "trace.h"
t_bool hit(t_object *world, t_ray *ray, t_hit_record *rec)
{
t_bool hit_anything;
t_hit_record *temp_rec;
temp_rec = rec;
hit_anything = FALSE;
while (world) // world->next로 훑어가며 등록된 구조체를 전부 체크함
{
if (hit_obj(world, ray, temp_rec))
{
hit_anything = TRUE;
temp_rec->tmax = temp_rec->t;
rec = temp_rec;
}
world = world->next;
}
return (hit_anything);
}
t_bool hit_obj(t_object *world, t_ray *ray, t_hit_record *rec)
{
t_bool hit_result;
hit_result = FALSE;
if (world->type == SP)
hit_result = hit_sphere(world, ray, rec);
else if (world->type == PL)
hit_result = hit_plane(world, ray, rec);
else if (world->type == CY)
hit_result = hit_cylinder(world, ray, rec);
return (hit_result);
}
グラフィックによっては衝突チェック式が異なるので、条件文で分岐します.
hit_plane.c
#include "structures.h"
#include "utils.h"
#include "trace.h"
t_bool hit_plane(t_object *pl_obj, t_ray *ray, t_hit_record *rec)
{
t_plane *pl;
float numrator;
float denominator;
float root;
pl = pl_obj->element;
denominator = vdot(ray->dir, pl->dir);
if (fabs(denominator) < EPSILON)
return (FALSE);
numrator = vdot(vminus(pl->center, ray->origin), pl->dir);
root = numrator / denominator;
if (root < rec->tmin || rec->tmax < root)
return (FALSE);
rec->t = root;
rec->p = ray_at(ray, root);
rec->normal = pl->dir;
set_face_normal(ray, rec);
rec->color = pl_obj->color;
return (TRUE);
}
数式
垂直ベクトル間の内積結果は0
ベクトルの内積がまた現れた.互いに垂直なベクトルを内積すると結果値は0になりますが、考えてみれば当然の結果です.内積とは、あるベクトルが別のベクトルの方向にどれだけ役立つかを意味し、垂直であれば何の役にも立たないが、干渉もないので、0の値を得ることができる.
ソース:https://ansohxxn.github.io/c++ games/chapter3-2-2/
判別式を使用した競合式
今もう一度写真を見ましょう.
ベクトルPは、カメラから発せられる任意の光線である.
ベクトルP 0は、パラメータとして与えられる平面上のある点である.平面の一部とも言える.
ベクトルNは、因子によって供給される平面の方向ベクトルである.この方向ベクトルの垂直方向には、平面が伸びています.
上述したように,互いに垂直な2つのベクトルを内積すると0が得られることを知っている.
ベクトルNに垂直なベクトルは、平面の一部P 0であり、平面を通過する点Pに接するベクトルであり、ベクトルP−ベクトルP 0である.
次のように数式で表します.
(P⃗−P⃗0)⋅N⃗=0(\vec P -\vec P_0)\cdot\vec N = 0(P−P0)⋅N=0
次のように式を展開します.
(O+D⃗∗t−P⃗0)⋅N⃗=0(O +\vec D * t -\vec P_0)\cdot\vec N = 0(O+D∗t−P0)⋅N=0
t(D⃗⋅N⃗)+(O−P⃗0)⋅N⃗=0t(\vec D\cdot\vec N) + (O -\vec P_0)\cdot\vec N = 0t(D⋅N)+(O−P0)⋅N=0
Oは原点、ベクトルDはベクトルPの単位ベクトル、tはPまでの距離(スカラー)!
この式を距離tの式に展開します.以下に示します.
t(D⃗⋅N⃗)=−(O−P⃗0)⋅N⃗t(\vec D\cdot\vec N)= -(O -\vec P_0)\cdot\vec Nt(D⋅N)=−(O−P0)⋅N
t=−(O−P⃗0)⋅N⃗D⃗⋅N⃗=(P⃗0−O)⋅N⃗D⃗⋅N⃗t = { -(O -\vec P_0)\cdot\vec N\over\vec D\cdot\vec N}= { (\vec P_0 - O)\cdot\vec N\over\vec D\cdot\vec N}t=D⋅N−(O−P0)⋅N=D⋅N(P0−O)⋅N
上記の式が判別式、tが負数であれば、その光線、ベクトルPは平面と交差しないベクトルとなる.
平面のベクトルがカメラのベクトルと逆であっても、衝突と判定します.絶対値で判別式の条件をチェックします.
コード実装を使用する場合
t_bool hit_plane(t_object *pl_obj, t_ray *ray, t_hit_record *rec)
{
t_plane *pl = pl_obj->element;
float numrator; // 판별식의 분자
float denominator; // 판별식의 분모
float root;
denominator = vdot(ray->dir, pl->normal);
if (denominator < EPSILON) // 분모의 값이 0보다 작거나 같을 경우 충돌하지 않는다.
return (FALSE);
numrator = vdot(vminus(pl->point, ray->orig), pl->normal);
root = numrator / denominator;
if (root < rec->tmin || rec->tmax < root)
return (FALSE);
rec->t = root;
rec->p = ray_at(ray, root);
// rec->normal = pl->normal;
rec->albedo = pl_obj->albedo;
// print_vec(normal);
return (TRUE);
}
t=−(O−P⃗0)⋅N⃗D⃗⋅N⃗=(P⃗0−O)⋅N⃗D⃗⋅N⃗t = { -(O -\vec P_0)\cdot\vec N\over\vec D\cdot\vec N}= { (\vec P_0 - O)\cdot\vec N\over\vec D\cdot\vec N}t=D⋅N−(O−P0)⋅N=D⋅N(P0−O)⋅N
struct s_plane
{
t_point3 center; // 평면의 어느 한 지점.
t_vec3 dir; // 평면이 가리키는 방향, 어떻게 기울여져 있는지
};
#include "trace.h"
t_bool hit(t_object *world, t_ray *ray, t_hit_record *rec)
{
t_bool hit_anything;
t_hit_record *temp_rec;
temp_rec = rec;
hit_anything = FALSE;
while (world) // world->next로 훑어가며 등록된 구조체를 전부 체크함
{
if (hit_obj(world, ray, temp_rec))
{
hit_anything = TRUE;
temp_rec->tmax = temp_rec->t;
rec = temp_rec;
}
world = world->next;
}
return (hit_anything);
}
t_bool hit_obj(t_object *world, t_ray *ray, t_hit_record *rec)
{
t_bool hit_result;
hit_result = FALSE;
if (world->type == SP)
hit_result = hit_sphere(world, ray, rec);
else if (world->type == PL)
hit_result = hit_plane(world, ray, rec);
else if (world->type == CY)
hit_result = hit_cylinder(world, ray, rec);
return (hit_result);
}
#include "structures.h"
#include "utils.h"
#include "trace.h"
t_bool hit_plane(t_object *pl_obj, t_ray *ray, t_hit_record *rec)
{
t_plane *pl;
float numrator;
float denominator;
float root;
pl = pl_obj->element;
denominator = vdot(ray->dir, pl->dir);
if (fabs(denominator) < EPSILON)
return (FALSE);
numrator = vdot(vminus(pl->center, ray->origin), pl->dir);
root = numrator / denominator;
if (root < rec->tmin || rec->tmax < root)
return (FALSE);
rec->t = root;
rec->p = ray_at(ray, root);
rec->normal = pl->dir;
set_face_normal(ray, rec);
rec->color = pl_obj->color;
return (TRUE);
}
垂直ベクトル間の内積結果は0
ベクトルの内積がまた現れた.互いに垂直なベクトルを内積すると結果値は0になりますが、考えてみれば当然の結果です.内積とは、あるベクトルが別のベクトルの方向にどれだけ役立つかを意味し、垂直であれば何の役にも立たないが、干渉もないので、0の値を得ることができる.
ソース:https://ansohxxn.github.io/c++ games/chapter3-2-2/
判別式を使用した競合式
今もう一度写真を見ましょう.
ベクトルPは、カメラから発せられる任意の光線である.
ベクトルP 0は、パラメータとして与えられる平面上のある点である.平面の一部とも言える.
ベクトルNは、因子によって供給される平面の方向ベクトルである.この方向ベクトルの垂直方向には、平面が伸びています.
上述したように,互いに垂直な2つのベクトルを内積すると0が得られることを知っている.
ベクトルNに垂直なベクトルは、平面の一部P 0であり、平面を通過する点Pに接するベクトルであり、ベクトルP−ベクトルP 0である.
次のように数式で表します.
(P⃗−P⃗0)⋅N⃗=0(\vec P -\vec P_0)\cdot\vec N = 0(P−P0)⋅N=0
次のように式を展開します.
(O+D⃗∗t−P⃗0)⋅N⃗=0(O +\vec D * t -\vec P_0)\cdot\vec N = 0(O+D∗t−P0)⋅N=0
t(D⃗⋅N⃗)+(O−P⃗0)⋅N⃗=0t(\vec D\cdot\vec N) + (O -\vec P_0)\cdot\vec N = 0t(D⋅N)+(O−P0)⋅N=0
Oは原点、ベクトルDはベクトルPの単位ベクトル、tはPまでの距離(スカラー)!
この式を距離tの式に展開します.以下に示します.
t(D⃗⋅N⃗)=−(O−P⃗0)⋅N⃗t(\vec D\cdot\vec N)= -(O -\vec P_0)\cdot\vec Nt(D⋅N)=−(O−P0)⋅N
t=−(O−P⃗0)⋅N⃗D⃗⋅N⃗=(P⃗0−O)⋅N⃗D⃗⋅N⃗t = { -(O -\vec P_0)\cdot\vec N\over\vec D\cdot\vec N}= { (\vec P_0 - O)\cdot\vec N\over\vec D\cdot\vec N}t=D⋅N−(O−P0)⋅N=D⋅N(P0−O)⋅N
上記の式が判別式、tが負数であれば、その光線、ベクトルPは平面と交差しないベクトルとなる.
平面のベクトルがカメラのベクトルと逆であっても、衝突と判定します.絶対値で判別式の条件をチェックします.
コード実装を使用する場合
t_bool hit_plane(t_object *pl_obj, t_ray *ray, t_hit_record *rec)
{
t_plane *pl = pl_obj->element;
float numrator; // 판별식의 분자
float denominator; // 판별식의 분모
float root;
denominator = vdot(ray->dir, pl->normal);
if (denominator < EPSILON) // 분모의 값이 0보다 작거나 같을 경우 충돌하지 않는다.
return (FALSE);
numrator = vdot(vminus(pl->point, ray->orig), pl->normal);
root = numrator / denominator;
if (root < rec->tmin || rec->tmax < root)
return (FALSE);
rec->t = root;
rec->p = ray_at(ray, root);
// rec->normal = pl->normal;
rec->albedo = pl_obj->albedo;
// print_vec(normal);
return (TRUE);
}
t=−(O−P⃗0)⋅N⃗D⃗⋅N⃗=(P⃗0−O)⋅N⃗D⃗⋅N⃗t = { -(O -\vec P_0)\cdot\vec N\over\vec D\cdot\vec N}= { (\vec P_0 - O)\cdot\vec N\over\vec D\cdot\vec N}t=D⋅N−(O−P0)⋅N=D⋅N(P0−O)⋅Nray->orig
ray→dir
pl→normal
pl→point
リファレンス
IllusionCatalyst
Ray-Plane Intersection
https://bigpel66.oopy.io/library/42/inner-circle/5
Reference
この問題について([MirRT]#10平面実装[追加]), 我々は、より多くの情報をここで見つけました
https://velog.io/@sham/miniRT-10-평면-구현-추가
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
Reference
この問題について([MirRT]#10平面実装[追加]), 我々は、より多くの情報をここで見つけました https://velog.io/@sham/miniRT-10-평면-구현-추가テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol