mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 04:31:35 -10:00
The new design is centered around the Event Trace JSON format but it should still be possible to adapt it for other profiling tools. The old profiling system has been removed.
496 lines
15 KiB
C++
496 lines
15 KiB
C++
/*
|
|
* Copyright (C) Freespace Open 2013. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Freespace Open. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
#include "asteroid/asteroid.h"
|
|
#include "cmdline/cmdline.h"
|
|
#include "debris/debris.h"
|
|
#include "graphics/opengl/gropengldraw.h"
|
|
#include "graphics/opengl/gropengltnl.h"
|
|
#include "graphics/shadows.h"
|
|
#include "lighting/lighting.h"
|
|
#include "math/vecmat.h"
|
|
#include "model/model.h"
|
|
#include "model/modelrender.h"
|
|
#include "render/3d.h"
|
|
#include "tracing/tracing.h"
|
|
|
|
extern vec3d check_offsets[8];
|
|
|
|
matrix4 Shadow_view_matrix;
|
|
matrix4 Shadow_proj_matrix[MAX_SHADOW_CASCADES];
|
|
float Shadow_cascade_distances[MAX_SHADOW_CASCADES];
|
|
|
|
light_frustum_info Shadow_frustums[MAX_SHADOW_CASCADES];
|
|
|
|
bool shadows_obj_in_frustum(object *objp, matrix *light_orient, vec3d *min, vec3d *max)
|
|
{
|
|
vec3d pos, pos_rot;
|
|
|
|
vm_vec_sub(&pos, &objp->pos, &Eye_position);
|
|
vm_vec_rotate(&pos_rot, &pos, light_orient);
|
|
|
|
if ( (pos_rot.xyz.x - objp->radius) > max->xyz.x
|
|
|| (pos_rot.xyz.x + objp->radius) < min->xyz.x
|
|
|| (pos_rot.xyz.y - objp->radius) > max->xyz.y
|
|
|| (pos_rot.xyz.y + objp->radius) < min->xyz.y
|
|
|| (pos_rot.xyz.z - objp->radius) > max->xyz.z ) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void shadows_construct_light_proj(light_frustum_info *shadow_data)
|
|
{
|
|
memset(&shadow_data->proj_matrix, 0, sizeof(matrix4));
|
|
|
|
shadow_data->proj_matrix.a1d[0] = 2.0f / ( shadow_data->max.xyz.x - shadow_data->min.xyz.x );
|
|
shadow_data->proj_matrix.a1d[5] = 2.0f / ( shadow_data->max.xyz.y - shadow_data->min.xyz.y );
|
|
shadow_data->proj_matrix.a1d[10] = -2.0f / ( shadow_data->max.xyz.z - shadow_data->min.xyz.z );
|
|
shadow_data->proj_matrix.a1d[12] = -(shadow_data->max.xyz.x + shadow_data->min.xyz.x) / ( shadow_data->max.xyz.x - shadow_data->min.xyz.x );
|
|
shadow_data->proj_matrix.a1d[13] = -(shadow_data->max.xyz.y + shadow_data->min.xyz.y) / ( shadow_data->max.xyz.y - shadow_data->min.xyz.y );
|
|
shadow_data->proj_matrix.a1d[14] = -(shadow_data->max.xyz.z + shadow_data->min.xyz.z) / ( shadow_data->max.xyz.z - shadow_data->min.xyz.z );
|
|
shadow_data->proj_matrix.a1d[15] = 1.0f;
|
|
}
|
|
|
|
void shadows_debug_show_frustum(matrix* orient, vec3d *pos, float fov, float aspect, float z_near, float z_far)
|
|
{
|
|
// find the widths and heights of the near plane and far plane to determine the points of this frustum
|
|
float near_height = tanf(fov * 0.5f) * z_near;
|
|
float near_width = near_height * aspect;
|
|
|
|
float far_height = tanf(fov * 0.5f) * z_far;
|
|
float far_width = far_height * aspect;
|
|
|
|
vec3d up_scale = ZERO_VECTOR;
|
|
vec3d right_scale = ZERO_VECTOR;
|
|
vec3d forward_scale_near = orient->vec.fvec;
|
|
vec3d forward_scale_far = orient->vec.fvec;
|
|
|
|
vm_vec_scale(&forward_scale_near, z_near);
|
|
vm_vec_scale(&forward_scale_far, z_far);
|
|
|
|
// find the eight points using eye orientation and position
|
|
vec3d near_top_left = ZERO_VECTOR;
|
|
vec3d near_top_right = ZERO_VECTOR;
|
|
vec3d near_bottom_left = ZERO_VECTOR;
|
|
vec3d near_bottom_right = ZERO_VECTOR;
|
|
|
|
// near top left
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, -near_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, -near_width);
|
|
|
|
vm_vec_add(&near_top_left, &up_scale, &right_scale);
|
|
vm_vec_add2(&near_top_left, &forward_scale_near);
|
|
|
|
// near top right
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, -near_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, near_width);
|
|
|
|
vm_vec_add(&near_top_right, &up_scale, &right_scale);
|
|
vm_vec_add2(&near_top_right, &forward_scale_near);
|
|
|
|
// near bottom left
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, near_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, -near_width);
|
|
|
|
vm_vec_add(&near_bottom_left, &up_scale, &right_scale);
|
|
vm_vec_add2(&near_bottom_left, &forward_scale_near);
|
|
|
|
// near bottom right
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, near_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, near_width);
|
|
|
|
vm_vec_add(&near_bottom_right, &up_scale, &right_scale);
|
|
vm_vec_add2(&near_bottom_right, &forward_scale_near);
|
|
|
|
vec3d far_top_left = ZERO_VECTOR;
|
|
vec3d far_top_right = ZERO_VECTOR;
|
|
vec3d far_bottom_left = ZERO_VECTOR;
|
|
vec3d far_bottom_right = ZERO_VECTOR;
|
|
|
|
// far top left
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, -far_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, -far_width);
|
|
|
|
vm_vec_add(&far_top_left, &up_scale, &right_scale);
|
|
vm_vec_add2(&far_top_left, &forward_scale_far);
|
|
|
|
// far top right
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, -far_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, far_width);
|
|
|
|
vm_vec_add(&far_top_right, &up_scale, &right_scale);
|
|
vm_vec_add2(&far_top_right, &forward_scale_far);
|
|
|
|
// far bottom left
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, far_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, -far_width);
|
|
|
|
vm_vec_add(&far_bottom_left, &up_scale, &right_scale);
|
|
vm_vec_add2(&far_bottom_left, &forward_scale_far);
|
|
|
|
// far bottom right
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, far_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, far_width);
|
|
|
|
vm_vec_add(&far_bottom_right, &up_scale, &right_scale);
|
|
vm_vec_add2(&far_bottom_right, &forward_scale_far);
|
|
|
|
// translate frustum
|
|
vm_vec_add2(&near_bottom_left, pos);
|
|
vm_vec_add2(&near_bottom_right, pos);
|
|
vm_vec_add2(&near_top_right, pos);
|
|
vm_vec_add2(&near_top_left, pos);
|
|
vm_vec_add2(&far_top_left, pos);
|
|
vm_vec_add2(&far_top_right, pos);
|
|
vm_vec_add2(&far_bottom_right, pos);
|
|
vm_vec_add2(&far_bottom_left, pos);
|
|
|
|
gr_set_color(0, 255, 255);
|
|
// g3_draw_htl_line(&near_bottom_left, &near_bottom_right);
|
|
// g3_draw_htl_line(&near_bottom_right, &near_top_right);
|
|
// g3_draw_htl_line(&near_bottom_right, &near_top_left);
|
|
// g3_draw_htl_line(&near_top_right, &near_top_left);
|
|
// g3_draw_htl_line(&far_top_left, &far_top_right);
|
|
// g3_draw_htl_line(&far_top_right, &far_bottom_right);
|
|
// g3_draw_htl_line(&far_bottom_right, &far_bottom_left);
|
|
// g3_draw_htl_line(&far_bottom_left, &far_top_left);
|
|
|
|
g3_render_line_3d(true, &near_bottom_left, &near_bottom_right);
|
|
g3_render_line_3d(true, &near_bottom_right, &near_top_right);
|
|
g3_render_line_3d(true, &near_bottom_right, &near_top_left);
|
|
g3_render_line_3d(true, &near_top_right, &near_top_left);
|
|
g3_render_line_3d(true, &far_top_left, &far_top_right);
|
|
g3_render_line_3d(true, &far_top_right, &far_bottom_right);
|
|
g3_render_line_3d(true, &far_bottom_right, &far_bottom_left);
|
|
g3_render_line_3d(true, &far_bottom_left, &far_top_left);
|
|
}
|
|
|
|
void shadows_construct_light_frustum(light_frustum_info *shadow_data, matrix *light_matrix, matrix *orient, vec3d *pos, float fov, float aspect, float z_near, float z_far)
|
|
{
|
|
// find the widths and heights of the near plane and far plane to determine the points of this frustum
|
|
float near_height = tanf(fov * 0.5f) * z_near;
|
|
float near_width = near_height * aspect;
|
|
|
|
float far_height = tanf(fov * 0.5f) * z_far;
|
|
float far_width = far_height * aspect;
|
|
|
|
vec3d up_scale = ZERO_VECTOR;
|
|
vec3d right_scale = ZERO_VECTOR;
|
|
vec3d forward_scale_near = orient->vec.fvec;
|
|
vec3d forward_scale_far = orient->vec.fvec;
|
|
|
|
vm_vec_scale(&forward_scale_near, z_near);
|
|
vm_vec_scale(&forward_scale_far, z_far);
|
|
|
|
// find the eight points using eye orientation and position
|
|
vec3d near_top_left = ZERO_VECTOR;
|
|
vec3d near_top_right = ZERO_VECTOR;
|
|
vec3d near_bottom_left = ZERO_VECTOR;
|
|
vec3d near_bottom_right = ZERO_VECTOR;
|
|
|
|
// near top left
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, -near_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, -near_width);
|
|
|
|
vm_vec_add(&near_top_left, &up_scale, &right_scale);
|
|
vm_vec_add2(&near_top_left, &forward_scale_near);
|
|
|
|
// near top right
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, -near_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, near_width);
|
|
|
|
vm_vec_add(&near_top_right, &up_scale, &right_scale);
|
|
vm_vec_add2(&near_top_right, &forward_scale_near);
|
|
|
|
// near bottom left
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, near_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, -near_width);
|
|
|
|
vm_vec_add(&near_bottom_left, &up_scale, &right_scale);
|
|
vm_vec_add2(&near_bottom_left, &forward_scale_near);
|
|
|
|
// near bottom right
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, near_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, near_width);
|
|
|
|
vm_vec_add(&near_bottom_right, &up_scale, &right_scale);
|
|
vm_vec_add2(&near_bottom_right, &forward_scale_near);
|
|
|
|
vec3d far_top_left = ZERO_VECTOR;
|
|
vec3d far_top_right = ZERO_VECTOR;
|
|
vec3d far_bottom_left = ZERO_VECTOR;
|
|
vec3d far_bottom_right = ZERO_VECTOR;
|
|
|
|
// far top left
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, -far_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, -far_width);
|
|
|
|
vm_vec_add(&far_top_left, &up_scale, &right_scale);
|
|
vm_vec_add2(&far_top_left, &forward_scale_far);
|
|
|
|
// far top right
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, -far_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, far_width);
|
|
|
|
vm_vec_add(&far_top_right, &up_scale, &right_scale);
|
|
vm_vec_add2(&far_top_right, &forward_scale_far);
|
|
|
|
// far bottom left
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, far_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, -far_width);
|
|
|
|
vm_vec_add(&far_bottom_left, &up_scale, &right_scale);
|
|
vm_vec_add2(&far_bottom_left, &forward_scale_far);
|
|
|
|
// far bottom right
|
|
up_scale = orient->vec.uvec;
|
|
vm_vec_scale(&up_scale, far_height);
|
|
|
|
right_scale = orient->vec.rvec;
|
|
vm_vec_scale(&right_scale, far_width);
|
|
|
|
vm_vec_add(&far_bottom_right, &up_scale, &right_scale);
|
|
vm_vec_add2(&far_bottom_right, &forward_scale_far);
|
|
|
|
vec3d frustum_pts[8];
|
|
|
|
// bring frustum points into light space
|
|
vm_vec_rotate(&frustum_pts[0], &near_bottom_left, light_matrix);
|
|
vm_vec_rotate(&frustum_pts[1], &near_bottom_right, light_matrix);
|
|
vm_vec_rotate(&frustum_pts[2], &near_top_right, light_matrix);
|
|
vm_vec_rotate(&frustum_pts[3], &near_top_left, light_matrix);
|
|
vm_vec_rotate(&frustum_pts[4], &far_top_left, light_matrix);
|
|
vm_vec_rotate(&frustum_pts[5], &far_top_right, light_matrix);
|
|
vm_vec_rotate(&frustum_pts[6], &far_bottom_right, light_matrix);
|
|
vm_vec_rotate(&frustum_pts[7], &far_bottom_left, light_matrix);
|
|
|
|
vec3d min = ZERO_VECTOR;
|
|
vec3d max = ZERO_VECTOR;
|
|
|
|
min = frustum_pts[0];
|
|
max = frustum_pts[0];
|
|
|
|
// find min and max of frustum points
|
|
for (int i = 0; i < 8; ++i) {
|
|
if ( frustum_pts[i].xyz.x < min.xyz.x ) {
|
|
min.xyz.x = frustum_pts[i].xyz.x;
|
|
}
|
|
|
|
if ( frustum_pts[i].xyz.x > max.xyz.x ) {
|
|
max.xyz.x = frustum_pts[i].xyz.x;
|
|
}
|
|
|
|
if ( frustum_pts[i].xyz.y < min.xyz.y ) {
|
|
min.xyz.y = frustum_pts[i].xyz.y;
|
|
}
|
|
|
|
if ( frustum_pts[i].xyz.y > max.xyz.y ) {
|
|
max.xyz.y = frustum_pts[i].xyz.y;
|
|
}
|
|
|
|
if ( frustum_pts[i].xyz.z < min.xyz.z ) {
|
|
min.xyz.z = frustum_pts[i].xyz.z;
|
|
}
|
|
|
|
if ( frustum_pts[i].xyz.z > max.xyz.z ) {
|
|
max.xyz.z = frustum_pts[i].xyz.z;
|
|
}
|
|
}
|
|
|
|
shadow_data->min = min;
|
|
shadow_data->max = max;
|
|
|
|
shadows_construct_light_proj(shadow_data);
|
|
}
|
|
|
|
matrix shadows_start_render(matrix *eye_orient, vec3d *eye_pos, float fov, float aspect, float veryneardist, float neardist, float middist, float fardist)
|
|
{
|
|
if(Static_light.empty())
|
|
return vmd_identity_matrix;
|
|
|
|
light *lp = *(Static_light.begin());
|
|
|
|
if ( lp == NULL ) {
|
|
return vmd_identity_matrix;
|
|
}
|
|
|
|
vec3d light_dir;
|
|
matrix light_matrix;
|
|
|
|
vm_vec_copy_normalize(&light_dir, &lp->vec);
|
|
vm_vector_2_matrix(&light_matrix, &light_dir, &eye_orient->vec.uvec, NULL);
|
|
|
|
shadows_construct_light_frustum(&Shadow_frustums[0], &light_matrix, eye_orient, eye_pos, fov, aspect, 0.0f, veryneardist);
|
|
shadows_construct_light_frustum(&Shadow_frustums[1], &light_matrix, eye_orient, eye_pos, fov, aspect, veryneardist - (veryneardist - 0.0f)* 0.2f, neardist);
|
|
shadows_construct_light_frustum(&Shadow_frustums[2], &light_matrix, eye_orient, eye_pos, fov, aspect, neardist - (neardist - veryneardist) * 0.2f, middist);
|
|
shadows_construct_light_frustum(&Shadow_frustums[3], &light_matrix, eye_orient, eye_pos, fov, aspect, middist - (middist - neardist) * 0.2f, fardist);
|
|
|
|
Shadow_cascade_distances[0] = veryneardist;
|
|
Shadow_cascade_distances[1] = neardist;
|
|
Shadow_cascade_distances[2] = middist;
|
|
Shadow_cascade_distances[3] = fardist;
|
|
|
|
Shadow_proj_matrix[0] = Shadow_frustums[0].proj_matrix;
|
|
Shadow_proj_matrix[1] = Shadow_frustums[1].proj_matrix;
|
|
Shadow_proj_matrix[2] = Shadow_frustums[2].proj_matrix;
|
|
Shadow_proj_matrix[3] = Shadow_frustums[3].proj_matrix;
|
|
|
|
gr_shadow_map_start(&Shadow_view_matrix, &light_matrix);
|
|
|
|
return light_matrix;
|
|
}
|
|
|
|
void shadows_end_render()
|
|
{
|
|
gr_shadow_map_end();
|
|
}
|
|
|
|
void shadows_render_all(float fov, matrix *eye_orient, vec3d *eye_pos)
|
|
{
|
|
GR_DEBUG_SCOPE("Render shadows");
|
|
TRACE_SCOPE(tracing::BuildShadowMap);
|
|
|
|
if ( Static_light.empty() ) {
|
|
return;
|
|
}
|
|
|
|
light *lp = *(Static_light.begin());
|
|
|
|
if( !Cmdline_shadow_quality || !lp ) {
|
|
return;
|
|
}
|
|
|
|
//shadows_debug_show_frustum(&Player_obj->orient, &Player_obj->pos, fov, gr_screen.clip_aspect, Min_draw_distance, 3000.0f);
|
|
|
|
gr_end_proj_matrix();
|
|
gr_end_view_matrix();
|
|
|
|
// these cascade distances are a result of some arbitrary tuning to give a good balance of quality and banding.
|
|
// maybe we could use a more programmatic algorithim?
|
|
matrix light_matrix = shadows_start_render(eye_orient, eye_pos, fov, gr_screen.clip_aspect, 200.0f, 600.0f, 2500.0f, 8000.0f);
|
|
|
|
draw_list scene;
|
|
object *objp = Objects;
|
|
|
|
for ( int i = 0; i <= Highest_object_index; i++, objp++ ) {
|
|
bool cull = true;
|
|
|
|
for ( int j = 0; j < MAX_SHADOW_CASCADES; ++j ) {
|
|
if ( shadows_obj_in_frustum(objp, &light_matrix, &Shadow_frustums[j].min, &Shadow_frustums[j].max) ) {
|
|
cull = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( cull ) {
|
|
continue;
|
|
}
|
|
|
|
switch(objp->type)
|
|
{
|
|
case OBJ_SHIP:
|
|
{
|
|
obj_queue_render(objp, &scene);
|
|
}
|
|
break;
|
|
case OBJ_ASTEROID:
|
|
{
|
|
model_render_params render_info;
|
|
|
|
render_info.set_object_number(OBJ_INDEX(objp));
|
|
render_info.set_flags(MR_IS_ASTEROID | MR_NO_TEXTURING | MR_NO_LIGHTING);
|
|
|
|
model_clear_instance( Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype]);
|
|
model_render_queue(&render_info, &scene, Asteroid_info[Asteroids[objp->instance].asteroid_type].model_num[Asteroids[objp->instance].asteroid_subtype], &objp->orient, &objp->pos);
|
|
}
|
|
break;
|
|
|
|
case OBJ_DEBRIS:
|
|
{
|
|
debris *db;
|
|
db = &Debris[objp->instance];
|
|
|
|
if ( !(db->flags & DEBRIS_USED)){
|
|
continue;
|
|
}
|
|
|
|
objp = &Objects[db->objnum];
|
|
|
|
model_render_params render_info;
|
|
|
|
render_info.set_flags(MR_NO_TEXTURING | MR_NO_LIGHTING);
|
|
|
|
submodel_render_queue(&render_info, &scene, db->model_num, db->submodel_num, &objp->orient, &objp->pos);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
scene.init_render();
|
|
scene.render_all(ZBUFFER_TYPE_FULL);
|
|
|
|
shadows_end_render();
|
|
|
|
gr_zbias(0);
|
|
gr_zbuffer_set(ZBUFFER_TYPE_READ);
|
|
gr_set_cull(0);
|
|
|
|
gr_clear_states();
|
|
|
|
gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance);
|
|
gr_set_view_matrix(&Eye_position, &Eye_matrix);
|
|
}
|