/* main */ int main () { /* initialize the corner info */ while (1) { /* loop is executed forever */ int range; /* range to target */ int hit; /* check for targets in range */ int dir, sc; /* scan direction */ int d; /* last damage check */ new_corner (); /* start at a random corner */ d = damage (); /* get current damage */ /* scan around sc. */ sc = plot_course (500, 500); dir = sc - 46; hit = 0; do { dir += 2; if (dir >= sc + 45) /* at end of 90 degrees range... */ { if (!hit) /* move if we hit */ break; dir = sc - 45; /* ... or restart */ } range = scan (dir, 1); /* look at a direction */ /* keep firing while in range, tolerating several hits */ while (range <= 700 && range > 0 && damage () <= d + 15) { hit = 1; cannon (dir, range); /* fire! */ range = scan (dir, 1); /* check target again */ } if (hit) { dir = MAX (dir - 10, sc - 45); /* back up scan after attack */ hit = 0; } } while (d == damage ()); } }
void ShadowMap::render_cascaded(RenderContext const& ctx, SceneGraph const& scene_graph, math::vec3 const& center_of_interest, Frustum const& scene_frustum, Camera const& scene_camera, math::mat4 const& transform, unsigned map_size, float split_0, float split_1, float split_2, float split_3, float split_4, float near_clipping_in_sun_direction) { update_members(ctx, map_size*2); projection_view_matrices_ = std::vector<math::mat4>(4); buffer_->bind(ctx); buffer_->clear_depth_stencil_buffer(ctx); ctx.render_context->set_depth_stencil_state(depth_stencil_state_); ctx.render_context->set_rasterizer_state(rasterizer_state_); std::vector<float> splits({ split_0, split_1, split_2, split_3, split_4 }); if (pipeline_->config.near_clip() > split_0 || pipeline_->config.far_clip() < split_4) { Logger::LOG_WARNING << "Splits of cascaded shadow maps are not inside clipping range! Fallback to equidistant splits used." << std::endl; float clipping_range(pipeline_->config.far_clip() - pipeline_->config.near_clip()); splits = { pipeline_->config.near_clip(), pipeline_->config.near_clip() + clipping_range * 0.25f, pipeline_->config.near_clip() + clipping_range * 0.5f, pipeline_->config.near_clip() + clipping_range * 0.75f, pipeline_->config.far_clip() }; } for (int y(0); y<2; ++y) { for (int x(0); x<2; ++x) { int cascade(y*2 + x); // render each cascade to a quarter of the shadow map ctx.render_context->set_viewport(scm::gl::viewport( math::vec2(x * map_size, y * map_size), math::vec2(map_size, map_size))); // set clipping of camera frustum according to current cascade Frustum cropped_frustum(Frustum::perspective( scene_frustum.get_camera_transform(), scene_frustum.get_screen_transform(), splits[cascade], splits[cascade+1] )); // transform cropped frustum tu sun space and calculate radius and bbox // of transformed frustum auto cropped_frustum_corners(cropped_frustum.get_corners()); math::BoundingBox<math::vec3> extends_in_sun_space; float radius_in_sun_space = 0; std::vector<math::vec3> corners_in_sun_space; math::vec3 center_in_sun_space(0, 0, 0); auto inverse_sun_transform(scm::math::inverse(transform)); for (auto const& corner: cropped_frustum_corners) { math::vec3 new_corner(inverse_sun_transform * corner); center_in_sun_space += new_corner/8; corners_in_sun_space.push_back(new_corner); extends_in_sun_space.expandBy(new_corner); } for (auto const& corner: corners_in_sun_space) { float radius = scm::math::length(corner-center_in_sun_space); if (radius > radius_in_sun_space) radius_in_sun_space = radius; } // center of front plane of frustum auto center(math::vec3((extends_in_sun_space.min[0] + extends_in_sun_space.max[0])/2, (extends_in_sun_space.min[1] + extends_in_sun_space.max[1])/2, extends_in_sun_space.max[2] + near_clipping_in_sun_direction)); // eliminate sub-pixel movement float tex_coord_x = center.x * map_size / radius_in_sun_space / 2; float tex_coord_y = center.y * map_size / radius_in_sun_space / 2; float tex_coord_rounded_x = round(tex_coord_x); float tex_coord_rounded_y = round(tex_coord_y); float dx = tex_coord_rounded_x - tex_coord_x; float dy = tex_coord_rounded_y - tex_coord_y; dx /= map_size / radius_in_sun_space / 2; dy /= map_size / radius_in_sun_space / 2; center.x += dx; center.y += dy; // calculate transformation of shadow screen auto screen_in_sun_space(scm::math::make_translation(center) * scm::math::make_scale(radius_in_sun_space*2, radius_in_sun_space*2, 1.0f)); auto sun_screen_transform(transform * screen_in_sun_space); // calculate transformation of shadow eye auto sun_eye_transform(scm::math::make_translation(sun_screen_transform.column(3)[0], sun_screen_transform.column(3)[1], sun_screen_transform.column(3)[2])); auto sun_eye_depth(transform * math::vec4(0, 0, extends_in_sun_space.max[2] - extends_in_sun_space.min[2] + near_clipping_in_sun_direction, 0.0f)); auto shadow_frustum( Frustum::orthographic( sun_eye_transform, sun_screen_transform, 0, scm::math::length(sun_eye_depth) ) ); // render geometries render_geometry(ctx, scene_graph, center_of_interest, shadow_frustum, scene_camera, cascade, map_size); } } ctx.render_context->reset_state_objects(); buffer_->unbind(ctx); }