Esempio n. 1
0
void csm_calc_minsphere(struct sphere* bounds, const struct frustum* f,
    const struct mat3f* view, const struct mat3f* view_inv)
{
    /* reference:
     * http://www.gamedev.net/topic/604797-minimum-bounding-sphere-of-a-frustum/
     */
    struct vec3f a;
    struct vec3f b;
    struct vec3f p;
    struct vec3f tmp;

    vec3_transformsrt(&a, &f->points[1], view);
    vec3_transformsrt(&b, &f->points[5], view);

    float z = (vec3_dot(&b, &b) - vec3_dot(&a, &a))/(2.0f*(b.z - a.z));
    vec3_setf(&p, 0.0f, 0.0f, z);
    vec3_transformsrt(&p, &p, view_inv);

    sphere_setf(bounds, p.x, p.y, p.z, vec3_len(vec3_sub(&tmp, &f->points[5], &p)) + 0.01f);
}
Esempio n. 2
0
const struct vec4f* gfx_csm_get_cascades(const struct mat3f* view)
{
    static struct vec4f cascades[CSM_CASCADE_CNT];
    struct vec4f center;
    for (uint i = 0; i < CSM_CASCADE_CNT; i++)    {
        const struct sphere* s = &g_csm->cascades[i].bounds;
        vec3_setf(&center, s->x, s->y, s->z);
        vec3_transformsrt(&center, &center, view);
        vec4_setf(&cascades[i], center.x, center.y, center.z, s->r);
    }
    return cascades;
}
Esempio n. 3
0
struct sphere* sphere_xform(struct sphere* rs, const struct sphere* s, const struct mat3f* m)
{
    /* we have to transform radius by scale value of transform matrix
     * to determine scale value, we find the highest scale component of the matrix */
    float xlen = m->m11*m->m11 + m->m12*m->m12 + m->m13*m->m13;
    float ylen = m->m21*m->m21 + m->m22*m->m22 + m->m23*m->m23;
    float zlen = m->m31*m->m31 + m->m32*m->m32 + m->m33*m->m33;
    float isqr_scale = maxf(xlen, ylen);
    isqr_scale = maxf(isqr_scale, zlen);

    /* transform center */
    struct vec4f c;
    vec3_setf(&c, s->x, s->y, s->z);
    vec3_transformsrt(&c, &c, m);
    return sphere_setf(rs, c.x, c.y, c.z, s->r*sqrtf(isqr_scale));
}
Esempio n. 4
0
void gfx_csm_prepare(const struct gfx_view_params* params, const struct vec3f* light_dir,
    const struct aabb* world_bounds)
{
    static const float tolerance = 10.0f;

    struct vec3f dir;
    vec3_setv(&dir, light_dir);

    float texoffset_x = 0.5f + (0.5f/g_csm->shadowmap_size);
    float texoffset_y = 0.5f + (0.5f/g_csm->shadowmap_size);

    struct mat3f view_inv;
    struct mat4f tex_mat;
    struct mat4f tmp_mat;
    float splits[CSM_CASCADE_CNT+1];

    mat3_setf(&view_inv,
        params->view.m11, params->view.m21, params->view.m31,
        params->view.m12, params->view.m22, params->view.m32,
        params->view.m13, params->view.m23, params->view.m33,
        params->cam_pos.x, params->cam_pos.y, params->cam_pos.z);
    mat4_setf(&tex_mat,
        0.5f, 0.0f, 0.0f, 0.0f,
        0.0f, -0.5f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f,
        texoffset_x, texoffset_y, 0.0f, 1.0f);

    float csm_far = minf(CSM_FAR_MAX, params->cam->ffar);
    csm_split_range(params->cam->fnear, csm_far, splits);

    /* calculate cascades */
    struct frustum f;   /* frustum points for cascades */
    struct plane vp_planes[6];

    for (uint i = 0; i < CSM_CASCADE_CNT; i++)    {
        cam_calc_frustumcorners(params->cam, (struct vec3f*)f.points, &splits[i], &splits[i+1]);
        csm_calc_minsphere(&g_csm->cascades[i].bounds, &f, &params->view, &view_inv);
        memcpy(&g_csm->cascade_frusts[i], &f, sizeof(f));

        /* cascade matrixes: first we find two extreme points of the world, related to cascade */
        struct vec3f scenter;
        struct ray r;
        struct plane upper_plane;
        struct plane lower_plane;
        struct vec3f upper_pt;
        struct vec3f lower_pt;
        struct vec3f xaxis;
        struct vec3f yaxis;
        struct vec3f viewpos;
        struct vec3f tmp;
        struct vec3f lowerpt_vs;

        float sr = g_csm->cascades[i].bounds.r;
        vec3_setf(&scenter, g_csm->cascades[i].bounds.x, g_csm->cascades[i].bounds.y,
            g_csm->cascades[i].bounds.z);
        ray_setv(&r, &scenter, &dir);
        plane_setv(&upper_plane, &g_vec3_unity_neg, fabs(world_bounds->maxpt.y));
        plane_setv(&lower_plane, &g_vec3_unity, fabs(world_bounds->minpt.y));
        vec3_sub(&upper_pt, &r.pt,
            vec3_muls(&tmp, &dir, fabs(ray_intersect_plane(&r, &upper_plane)) + tolerance));
        vec3_add(&lower_pt, &r.pt,
            vec3_muls(&tmp, &dir, fabs(ray_intersect_plane(&r, &lower_plane)) + tolerance));

        /* view matrix of light view for the cascade :
         * dir = light_dir
         * up = (1, 0, 0)
         * pos = sphere center
         */
        vec3_norm(&xaxis, vec3_cross(&tmp, &g_vec3_unitx, &dir));
        vec3_cross(&yaxis, &dir, &xaxis);
        vec3_sub(&viewpos, &upper_pt, vec3_muls(&tmp, &dir, tolerance));
        mat3_setf(&g_csm->cascades[i].view,
            xaxis.x, yaxis.x, dir.x,
            xaxis.y, yaxis.y, dir.y,
            xaxis.z, yaxis.z, dir.z,
            -vec3_dot(&xaxis, &viewpos), -vec3_dot(&yaxis, &viewpos), -vec3_dot(&dir, &viewpos));

        /* orthographic projection matrix for cascade */
        vec3_transformsrt(&lowerpt_vs, &lower_pt, &g_csm->cascades[i].view);
        float nnear = tolerance*0.5f;
        float nfar = lowerpt_vs.z + sr;
        csm_calc_orthoproj(&g_csm->cascades[i].proj,
            sr*2.0f + 1.0f/g_csm->shadowmap_size,
            sr*2.0f + 1.0f/g_csm->shadowmap_size,
            nnear, nfar);
        g_csm->cascades[i].nnear = nnear;
        g_csm->cascades[i].nfar = nfar;

        /* calculate final matrix */
        mat3_mul4(&g_csm->cascade_vps[i], &g_csm->cascades[i].view, &g_csm->cascades[i].proj);

        cam_calc_frustumplanes(vp_planes, &g_csm->cascade_vps[i]);
        csm_calc_cascadeplanes(&g_csm->cascade_planes[i*4], vp_planes, &g_csm->cascade_vps[i]);

        csm_round_mat(&g_csm->cascade_vps[i], &g_csm->cascade_vps[i], g_csm->shadowmap_size);

        mat4_mul(&g_csm->shadow_mats[i],
            mat3_mul4(&tmp_mat, &view_inv, &g_csm->cascade_vps[i]), &tex_mat);
    }

    /* caculate shadow area bounds (aabb) */
    struct aabb cascade_near;
    struct aabb cascade_far;
    aabb_setzero(&g_csm->frustum_bounds);

    aabb_from_sphere(&cascade_near, &g_csm->cascades[0].bounds);
    aabb_from_sphere(&cascade_far, &g_csm->cascades[CSM_CASCADE_CNT-1].bounds);
    aabb_merge(&g_csm->frustum_bounds, &cascade_near, &cascade_far);

    vec3_setv(&g_csm->light_dir, &dir);
}