/* calculate sphere that goes through 4 points */ struct sphere* sphere_circum(struct sphere* rs, const struct vec4f* v0, const struct vec4f* v1, const struct vec4f* v2, const struct vec4f* v3) { struct vec4f a; vec3_sub(&a, v1, v0); struct vec4f b; vec3_sub(&b, v2, v0); struct vec4f c; vec3_sub(&c, v3, v0); struct vec4f o; struct vec4f tmp; struct mat3f m; mat3_setf(&m, a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z, 0.0f, 0.0f, 0.0f); float denom = 2.0f * mat3_det(&m); vec3_muls(&o, vec3_cross(&tmp, &a, &b), vec3_dot(&c, &c)); vec3_add(&o, &o, vec3_muls(&tmp, vec3_cross(&tmp, &c, &a), vec3_dot(&b, &b))); vec3_add(&o, &o, vec3_muls(&tmp, vec3_cross(&tmp, &b, &c), vec3_dot(&a, &a))); vec3_muls(&o, &o, 1.0f/denom); return sphere_setf(rs, v0->x + o.x, v0->y + o.y, v0->z + o.z, vec3_len(&o) + EPSILON); }
struct sphere* sphere_merge(struct sphere* rs, const struct sphere* s1, const struct sphere* s2) { struct vec4f cdiff; vec3_setf(&cdiff, s2->x - s1->x, s2->y - s1->y, s2->z - s1->z); float rd = s2->r - s1->r; float rd_sqr = rd * rd; float ld_sqr = cdiff.x*cdiff.x + cdiff.y*cdiff.y + cdiff.z*cdiff.z; if (rd_sqr < ld_sqr) { float ld = sqrtf(ld_sqr); struct vec4f c; vec3_setf(&c, s1->x, s1->y, s1->z); float k = (ld + s2->r - s1->r)/(2.0f*ld); vec3_add(&c, &c, vec3_muls(&cdiff, &cdiff, k)); rs->x = c.x; rs->y = c.y; rs->z = c.z; rs->r = (ld + s1->r + s2->r)*0.5f; return rs; } else { if (rd >= 0.0f) return sphere_sets(rs, s2); else return sphere_sets(rs, s1); } }
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, ¶ms->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); }
Vector Vector::__mul__(float k) { Vector r; vec3_muls(&r.v_, &this->v_, k); return r; }
Vector Vector::__div__(float k) { Vector r; vec3_muls(&r.v_, &this->v_, 1.0f/k); return r; }
t_vec3 vec3_mix(t_vec3 a, t_vec3 b, float t) { return (vec3_add(vec3_muls(a, (1.0f - t)), vec3_muls(b, t))); }