获得锥形法线 - 光线追踪

时间:2017-03-10 14:41:36

标签: c debugging raytracing normals

我正在用C编写光线跟踪器,但我无法完善锥体上的阴影。我认为我遇到的问题是计算交叉点处锥体的法线。 Here是对我目前所拥有的内容的渲染。

场景描述如下:

resolution: 500, 500
scene:
{
    light:
    {
        position: 0, -10, -40
        intensity: 20000
        color: white
    }
    camera:
    {
        position: -5, -7, -40
        direction: 0, 0, 1
        fov: 50
    }
    plane: 
    {
        position: 0, 0, 0
        direction: 0, 0, 1
        color: white
    }
    cone:
    {
        position: 0, 0, -2.5
        direction: -5, -8, 0
        color: white
        radius: 5
        height: 20
    }
    cylinder:
    {
        position: 10, 0, 0
        direction: -5, -8, 0
        color: white
        radius: 5
        height: 20
    }
}

请注意,灯光位于物体和相机之间。 问题在于,我认为锥体应该更加照亮,至少在某些区域,就像右边的圆柱体一样。

我根据this post's answer计算了法线,如下所示:

static void get_cone_normal(t_raytracing_tools *r, t_ray *ray, t_object *obj)
{
    //nhit is the normal at hit point.
    ray->nhit.x = (ray->hit.x - obj->pos.x) * (obj->height / obj->rad);
    ray->nhit.y = obj->rad / obj->height;
    ray->nhit.z = (ray->hit.z - obj->pos.z) * (obj->height / obj->rad);
    ray->nhit = v_norm(ray->nhit);
}

我还想到了法线的方向,取决于光线被光线击中的哪一侧。在我求解二次方程并得到两个可能的答案之后,我测试每一个以确定它是否在我的有限锥内(参数方程是无限锥)并且根据光线如何击中圆锥,我有一个int变量n_dir这是1或-1,如果射线击中锥体的内部,我用它来反转法线。以下是该部分的代码:

 bool       get_finite_cone_intersection(t_raytracing_tools *r, t_ray *ray, t_object *obj, t_intersection_tools *i)
{
    bool    r1_too_low;
    bool    r1_too_high;
    bool    r2_too_low;
    bool    r2_too_high;

    //i->r1 and i->r2 are the two roots (solutions of quadratic eq.)
    r1_too_low = lower_than_min(i->r1, i, obj, ray);
    r1_too_high = higher_than_max(i->r1, i, obj, ray);
    r2_too_low = lower_than_min(i->r2, i, obj, ray);
    r2_too_high = higher_than_max(i->r2, i, obj, ray);
    if (r1_too_low)
    {
        i->r1 = NAN; //I set roots to NAN if they are not valid solutions
        if (r2_too_low || r2_too_high)
            i->r2 = NAN;
        else
            i->n_dir = 1;
    }
    else if (r1_too_high)
    {
        i->r1 = NAN;
        if (r2_too_low || r2_too_high)
            i->r2 = NAN;
        else
            i->n_dir = -1;
    }
    else if (!r1_too_low && !r1_too_high)
    {
        i->r2 = NAN;
        if (r2_too_low)
            i->n_dir = -1;
        else
            i->n_dir = 1;
    }
    return (true);
}

bool        lower_than_min(double r, t_intersection_tools *i, t_object *obj, t_ray *ray)
{
    if (r > 0)
    {
        if (v_dot(obj->dir, v_sub(v_add(ray->origin, v_scale(ray->dir, r)), obj->pos)) < 0.0)
            return (true);      
    }
    return (false);
}
bool        higher_than_max(double r, t_intersection_tools *i, t_object *obj, t_ray *ray)
{
    if (r > 0)
    {
        if (v_dot(obj->dir, v_sub(v_add(ray->origin, v_scale(ray->dir, r)),
            v_add(obj->pos, v_scale(obj->dir, obj->height)))) > 0.0)
            return (true);      
    }
    return (false);
}

另外,这是什么,这是我的锥形交叉点的代码:

    bool        get_cone_intersection(t_raytracing_tools *r, t_ray *ray, t_object *cone)
{
    t_intersection_tools i;
    t_vec3    ori_cen;
    double    k;
    int         n_dir;

    i.n_dir = 1;
    k = tan(cone->angle);
    ori_cen = v_sub(ray->origin, cone->pos);
    i.q.x = v_dot(ray->dir, ray->dir) - (1.0 + k * k) * powf(v_dot(ray->dir, cone->dir), 2.0);
    i.q.y = 2 * (v_dot(ray->dir, ori_cen) - (1.0 + k * k) * v_dot(ray->dir, cone->dir)
                * v_dot(ori_cen, cone->dir));
    i.q.z = v_dot(ori_cen, ori_cen) - (1.0 + k * k) * powf(v_dot(ori_cen,
                cone->dir), 2.0);
    if (!solve_quadratic(i.q, &i.r1, &i.r2))
        return (0);
    (i.r2 < i.r1) ? ft_swapd(&i.r1, &i.r2) : 0;
    get_finite_cone_intersection(r, ray, cone, &i);
    if (i.r1 < 0 || isnan(i.r1)) //the smallest one is negative, thus take the other one
    {
        i.r1 = i.r2;
    }
    if (i.r1 < 0 || isnan(i.r1))    
        return (false);
    if (r->t > i.r1)
    {
        ray->t = i.r1;
        if (ray->type == R_PRIMARY)
        {
            ray->hit_obj = cone;
            ray->hit_type = T_CONE;
            ray->n_dir = i.n_dir;
        }
    }
    return (true);
}

希望一下子不要太多信息!再一次,如果有人可以对这种情况有所了解(haha),那就太喜欢了。

0 个答案:

没有答案