void Model::computeRuntimeData(const uint8* vertices) { int index = 0; float bounding_radius_squared = 0; Vec3 min_vertex(0, 0, 0); Vec3 max_vertex(0, 0, 0); for (int i = 0; i < m_meshes.size(); ++i) { int mesh_vertex_count = m_meshes[i].getAttributeArraySize() / m_meshes[i].getVertexDefinition().getStride(); int mesh_attributes_array_offset = m_meshes[i].getAttributeArrayOffset(); int mesh_vertex_size = m_meshes[i].getVertexDefinition().getStride(); int mesh_position_attribute_offset = m_meshes[i].getVertexDefinition().getOffset(bgfx::Attrib::Position); for (int j = 0; j < mesh_vertex_count; ++j) { m_vertices[index] = *(const Vec3*)&vertices[mesh_attributes_array_offset + j * mesh_vertex_size + mesh_position_attribute_offset]; bounding_radius_squared = Math::maxValue( bounding_radius_squared, dotProduct(m_vertices[index], m_vertices[index]) > 0 ? m_vertices[index].squaredLength() : 0); min_vertex.x = Math::minValue(min_vertex.x, m_vertices[index].x); min_vertex.y = Math::minValue(min_vertex.y, m_vertices[index].y); min_vertex.z = Math::minValue(min_vertex.z, m_vertices[index].z); max_vertex.x = Math::maxValue(max_vertex.x, m_vertices[index].x); max_vertex.y = Math::maxValue(max_vertex.y, m_vertices[index].y); max_vertex.z = Math::maxValue(max_vertex.z, m_vertices[index].z); ++index; } } m_bounding_radius = sqrt(bounding_radius_squared); m_aabb = AABB(min_vertex, max_vertex); }
void management_base:: check_for_nodes_within_cells(const std::vector<std::vector<size_t>>& total_depths, const std::vector<std::vector<size_t>>& total_nums) { lamure::ren::model_database* database = lamure::ren::model_database::get_instance(); for(model_t model_index = 0; model_index < database->num_models(); ++model_index) { for(size_t cell_index = 0; cell_index < visibility_grid_->get_cell_count(); ++cell_index) { // Create bounding box of view cell. const view_cell* current_cell = visibility_grid_->get_cell_at_index(cell_index); vec3r min_vertex(current_cell->get_position_center() - (current_cell->get_size() * 0.5f)); vec3r max_vertex(current_cell->get_position_center() + (current_cell->get_size() * 0.5f)); bounding_box cell_bounds(min_vertex, max_vertex); // We can get the first and last index of the nodes on a certain depth inside the bvh. unsigned int average_depth = total_depth_rendered_nodes_[model_index][cell_index] / total_num_rendered_nodes_[model_index][cell_index]; node_t start_index = database->get_model(model_index)->get_bvh()->get_first_node_id_of_depth(average_depth); node_t end_index = start_index + database->get_model(model_index)->get_bvh()->get_length_of_depth(average_depth); for(node_t node_index = start_index; node_index < end_index; ++node_index) { // Create bounding box of node. scm::gl::boxf node_bounding_box = database->get_model(model_index)->get_bvh()->get_bounding_boxes()[node_index]; vec3r min_vertex = vec3r(node_bounding_box.min_vertex()) + database->get_model(model_index)->get_bvh()->get_translation(); vec3r max_vertex = vec3r(node_bounding_box.max_vertex()) + database->get_model(model_index)->get_bvh()->get_translation(); bounding_box node_bounds(min_vertex, max_vertex); // check if the bounding boxes collide. if(cell_bounds.intersects(node_bounds)) { visibility_grid_->set_cell_visibility(cell_index, model_index, node_index, true); } } } } }
int visibility_test_id_histogram_renderer:: initialize(int& argc, char** argv) { namespace po = boost::program_options; namespace fs = boost::filesystem; const std::string exec_name = (argc > 0) ? fs::basename(argv[0]) : ""; scm::shared_ptr<scm::core> scm_core(new scm::core(1, argv)); putenv((char *)"__GL_SYNC_TO_VBLANK=0"); std::string resource_file_path = ""; // These value are read, but not used. Yet ignoring them in the terminal parameters would lead to misinterpretation. std::string pvs_output_file_path = ""; std::string visibility_test_type = ""; std::string grid_type = ""; unsigned int grid_size = 1; unsigned int num_steps = 11; double oversize_factor = 1.5; float optimization_threshold = 1.0f; po::options_description desc("Usage: " + exec_name + " [OPTION]... INPUT\n\n" "Allowed Options"); desc.add_options() ("help", "print help message") ("width,w", po::value<int>(&resolution_x_)->default_value(1024), "specify window width (default=1024)") ("height,h", po::value<int>(&resolution_y_)->default_value(1024), "specify window height (default=1024)") ("resource-file,f", po::value<std::string>(&resource_file_path), "specify resource input-file") ("vram,v", po::value<unsigned>(&video_memory_budget_)->default_value(2048), "specify graphics memory budget in MB (default=2048)") ("mem,m", po::value<unsigned>(&main_memory_budget_)->default_value(4096), "specify main memory budget in MB (default=4096)") ("upload,u", po::value<unsigned>(&max_upload_budget_)->default_value(64), "specify maximum video memory upload budget per frame in MB (default=64)") // The following parameters are used by the main app only, yet must be identified nonetheless since otherwise they are dealt with as file paths. ("pvs-file,p", po::value<std::string>(&pvs_output_file_path), "specify output file of calculated pvs data") ("vistest", po::value<std::string>(&visibility_test_type)->default_value("histogramrenderer"), "specify type of visibility test to be used. ('histogramrenderer', 'randomhistogramrenderer')") ("gridtype", po::value<std::string>(&grid_type)->default_value("octree"), "specify type of grid to store visibility data ('regular', 'octree', 'hierarchical')") ("gridsize", po::value<unsigned int>(&grid_size)->default_value(1), "specify size/depth of the grid used for the visibility test (depends on chosen grid type)") ("oversize", po::value<double>(&oversize_factor)->default_value(1.5), "factor the grid bounds will be scaled by, default is 1.5 (grid bounds will exceed scene bounds by factor of 1.5)") ("optithresh", po::value<float>(&optimization_threshold)->default_value(1.0f), "specify the threshold at which common data are converged. Default is 1.0, which means data must be 100 percent equal.") ("numsteps,n", po::value<unsigned int>(&num_steps)->default_value(11), "specify the number of intervals the occlusion values will be split into (visibility analysis only)"); ; po::variables_map vm; try { auto parsed_options = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); po::store(parsed_options, vm); po::notify(vm); std::vector<std::string> to_pass_further = po::collect_unrecognized(parsed_options.options, po::include_positional); bool no_input = !vm.count("input") && to_pass_further.empty(); if (resource_file_path == "") { if (vm.count("help") || no_input) { std::cout << desc; return 0; } } // no explicit input -> use unknown options if (!vm.count("input") && resource_file_path == "") { resource_file_path = "auto_generated.rsc"; std::fstream ofstr(resource_file_path, std::ios::out); if (ofstr.good()) { for (auto argument : to_pass_further) { ofstr << argument << std::endl; } } else { throw std::runtime_error("Cannot open file"); } ofstr.close(); } } catch (std::exception& e) { std::cout << "Warning: No input file specified. \n" << desc; return 0; } lamure::pvs::glut_wrapper::initialize(argc, argv, resolution_x_, resolution_y_, nullptr); std::pair< std::vector<std::string>, std::vector<scm::math::mat4f> > model_attributes; std::set<lamure::model_t> visible_set; std::set<lamure::model_t> invisible_set; model_attributes = read_model_string(resource_file_path, &visible_set, &invisible_set); std::vector<scm::math::mat4f> & model_transformations = model_attributes.second; std::vector<std::string> const& model_filenames = model_attributes.first; lamure::ren::policy* policy = lamure::ren::policy::get_instance(); policy->set_max_upload_budget_in_mb(max_upload_budget_); policy->set_render_budget_in_mb(video_memory_budget_); policy->set_out_of_core_budget_in_mb(main_memory_budget_); policy->set_window_width(resolution_x_); policy->set_window_height(resolution_y_); lamure::ren::model_database* database = lamure::ren::model_database::get_instance(); management_ = new management_id_histogram_renderer(model_filenames, model_transformations, visible_set, invisible_set); glut_wrapper::set_management(management_); management_->set_pvs_file_path(pvs_output_file_path); // Calculate bounding box of whole scene. for(lamure::model_t model_id = 0; model_id < database->num_models(); ++model_id) { // Cast required from boxf to bounding_box. const scm::gl::boxf& box_model_root = database->get_model(model_id)->get_bvh()->get_bounding_boxes()[0]; vec3r min_vertex(box_model_root.min_vertex() + database->get_model(model_id)->get_bvh()->get_translation()); vec3r max_vertex(box_model_root.max_vertex() + database->get_model(model_id)->get_bvh()->get_translation()); bounding_box model_root_box(min_vertex, max_vertex); if(model_id == 0) { scene_bounds_ = bounding_box(model_root_box); } else { scene_bounds_.expand(model_root_box); } } return 0; }
bool Model::parseMeshesOld(bgfx::VertexDecl global_vertex_decl, FS::IFile& file, FileVersion version, u32 global_flags) { int object_count = 0; file.read(&object_count, sizeof(object_count)); if (object_count <= 0) return false; m_meshes.reserve(object_count); char model_dir[MAX_PATH_LENGTH]; PathUtils::getDir(model_dir, MAX_PATH_LENGTH, getPath().c_str()); struct Offsets { i32 attribute_array_offset; i32 attribute_array_size; i32 indices_offset; i32 mesh_tri_count; }; Array<Offsets> mesh_offsets(m_allocator); for (int i = 0; i < object_count; ++i) { i32 str_size; file.read(&str_size, sizeof(str_size)); char material_name[MAX_PATH_LENGTH]; file.read(material_name, str_size); if (str_size >= MAX_PATH_LENGTH) return false; material_name[str_size] = 0; char material_path[MAX_PATH_LENGTH]; copyString(material_path, model_dir); catString(material_path, material_name); catString(material_path, ".mat"); auto* material_manager = m_resource_manager.getOwner().get(Material::TYPE); Material* material = static_cast<Material*>(material_manager->load(Path(material_path))); Offsets& offsets = mesh_offsets.emplace(); file.read(&offsets.attribute_array_offset, sizeof(offsets.attribute_array_offset)); file.read(&offsets.attribute_array_size, sizeof(offsets.attribute_array_size)); file.read(&offsets.indices_offset, sizeof(offsets.indices_offset)); file.read(&offsets.mesh_tri_count, sizeof(offsets.mesh_tri_count)); file.read(&str_size, sizeof(str_size)); if (str_size >= MAX_PATH_LENGTH) { material_manager->unload(*material); return false; } char mesh_name[MAX_PATH_LENGTH]; mesh_name[str_size] = 0; file.read(mesh_name, str_size); bgfx::VertexDecl vertex_decl = global_vertex_decl; if (version <= FileVersion::SINGLE_VERTEX_DECL) { parseVertexDecl(file, &vertex_decl); if (i != 0 && global_vertex_decl.m_hash != vertex_decl.m_hash) { g_log_error.log("Renderer") << "Model " << getPath().c_str() << " contains meshes with different vertex declarations."; } if(i == 0) global_vertex_decl = vertex_decl; } m_meshes.emplace(material, vertex_decl, mesh_name, m_allocator); addDependency(*material); } i32 indices_count = 0; file.read(&indices_count, sizeof(indices_count)); if (indices_count <= 0) return false; u32 INDICES_16BIT_FLAG = 1; int index_size = global_flags & INDICES_16BIT_FLAG ? 2 : 4; Array<u8> indices(m_allocator); indices.resize(indices_count * index_size); file.read(&indices[0], indices.size()); i32 vertices_size = 0; file.read(&vertices_size, sizeof(vertices_size)); if (vertices_size <= 0) return false; Array<u8> vertices(m_allocator); vertices.resize(vertices_size); file.read(&vertices[0], vertices.size()); int vertex_count = 0; for (const Offsets& offsets : mesh_offsets) { vertex_count += offsets.attribute_array_size / global_vertex_decl.getStride(); } if (version > FileVersion::BOUNDING_SHAPES_PRECOMPUTED) { file.read(&m_bounding_radius, sizeof(m_bounding_radius)); file.read(&m_aabb, sizeof(m_aabb)); } float bounding_radius_squared = 0; Vec3 min_vertex(0, 0, 0); Vec3 max_vertex(0, 0, 0); int vertex_size = global_vertex_decl.getStride(); int position_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Position); int uv_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::TexCoord0); int weights_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Weight); int bone_indices_attribute_offset = global_vertex_decl.getOffset(bgfx::Attrib::Indices); bool keep_skin = global_vertex_decl.has(bgfx::Attrib::Weight) && global_vertex_decl.has(bgfx::Attrib::Indices); for (int i = 0; i < m_meshes.size(); ++i) { Offsets& offsets = mesh_offsets[i]; Mesh& mesh = m_meshes[i]; mesh.indices_count = offsets.mesh_tri_count * 3; mesh.indices.resize(mesh.indices_count * index_size); copyMemory(&mesh.indices[0], &indices[offsets.indices_offset * index_size], mesh.indices_count * index_size); int mesh_vertex_count = offsets.attribute_array_size / global_vertex_decl.getStride(); int mesh_attributes_array_offset = offsets.attribute_array_offset; mesh.vertices.resize(mesh_vertex_count); mesh.uvs.resize(mesh_vertex_count); if (keep_skin) mesh.skin.resize(mesh_vertex_count); for (int j = 0; j < mesh_vertex_count; ++j) { int offset = mesh_attributes_array_offset + j * vertex_size; if (keep_skin) { mesh.skin[j].weights = *(const Vec4*)&vertices[offset + weights_attribute_offset]; copyMemory(mesh.skin[j].indices, &vertices[offset + bone_indices_attribute_offset], sizeof(mesh.skin[j].indices)); } mesh.vertices[j] = *(const Vec3*)&vertices[offset + position_attribute_offset]; mesh.uvs[j] = *(const Vec2*)&vertices[offset + uv_attribute_offset]; float sq_len = mesh.vertices[j].squaredLength(); bounding_radius_squared = Math::maximum(bounding_radius_squared, sq_len > 0 ? sq_len : 0); min_vertex.x = Math::minimum(min_vertex.x, mesh.vertices[j].x); min_vertex.y = Math::minimum(min_vertex.y, mesh.vertices[j].y); min_vertex.z = Math::minimum(min_vertex.z, mesh.vertices[j].z); max_vertex.x = Math::maximum(max_vertex.x, mesh.vertices[j].x); max_vertex.y = Math::maximum(max_vertex.y, mesh.vertices[j].y); max_vertex.z = Math::maximum(max_vertex.z, mesh.vertices[j].z); } } if (version <= FileVersion::BOUNDING_SHAPES_PRECOMPUTED) { m_bounding_radius = sqrt(bounding_radius_squared); m_aabb = AABB(min_vertex, max_vertex); } for (int i = 0; i < m_meshes.size(); ++i) { Mesh& mesh = m_meshes[i]; Offsets offsets = mesh_offsets[i]; ASSERT(!bgfx::isValid(mesh.index_buffer_handle)); if (global_flags & INDICES_16BIT_FLAG) { mesh.flags.set(Mesh::Flags::INDICES_16_BIT); } int indices_size = index_size * mesh.indices_count; const bgfx::Memory* mem = bgfx::copy(&indices[offsets.indices_offset * index_size], indices_size); mesh.index_buffer_handle = bgfx::createIndexBuffer(mem, index_size == 4 ? BGFX_BUFFER_INDEX32 : 0); if (!bgfx::isValid(mesh.index_buffer_handle)) return false; ASSERT(!bgfx::isValid(mesh.vertex_buffer_handle)); const bgfx::Memory* vertices_mem = bgfx::copy(&vertices[offsets.attribute_array_offset], offsets.attribute_array_size); mesh.vertex_buffer_handle = bgfx::createVertexBuffer(vertices_mem, mesh.vertex_decl); if (!bgfx::isValid(mesh.vertex_buffer_handle)) return false; } return true; }
management_base:: management_base(std::vector<std::string> const& model_filenames, std::vector<scm::math::mat4f> const& model_transformations, std::set<lamure::model_t> const& visible_set, std::set<lamure::model_t> const& invisible_set) : renderer_(nullptr), model_filenames_(model_filenames), model_transformations_(model_transformations), test_send_rendered_(true), active_camera_(nullptr), num_models_(0), dispatch_(true), error_threshold_(LAMURE_DEFAULT_THRESHOLD), near_plane_(0.001f), far_plane_(1000.f), importance_(1.f) { visibility_threshold_ = 0.0001f; first_frame_ = true; visibility_grid_ = nullptr; current_grid_index_ = 0; direction_counter_ = 0; update_position_for_pvs_ = true; #ifdef LAMURE_PVS_MEASURE_PERFORMANCE total_cut_update_time_ = 0.0; total_render_time_ = 0.0; total_histogram_evaluation_time_ = 0.0; #endif #ifndef LAMURE_PVS_USE_AS_RENDERER lamure::pvs::pvs_database::get_instance()->activate(false); #endif lamure::ren::model_database* database = lamure::ren::model_database::get_instance(); for (const auto& filename : model_filenames_) { database->add_model(filename, std::to_string(num_models_)); ++num_models_; } total_depth_rendered_nodes_.resize(num_models_); total_num_rendered_nodes_.resize(num_models_); float scene_diameter = far_plane_; for (lamure::model_t model_id = 0; model_id < database->num_models(); ++model_id) { const auto& bb = database->get_model(model_id)->get_bvh()->get_bounding_boxes()[0]; scene_diameter = std::max(scm::math::length(bb.max_vertex()-bb.min_vertex()), scene_diameter); model_transformations_[model_id] = model_transformations_[model_id] * scm::math::make_translation(database->get_model(model_id)->get_bvh()->get_translation()); } far_plane_ = 2.0f * scene_diameter; auto root_bb = database->get_model(0)->get_bvh()->get_bounding_boxes()[0]; scm::math::vec3 center = model_transformations_[0] * root_bb.center(); scm::math::mat4f reset_matrix = scm::math::make_look_at_matrix(center + scm::math::vec3f(0.0f, 0.0f, 0.1f), center, scm::math::vec3f(0.0f, 1.0f,0.0f)); float reset_diameter = scm::math::length(root_bb.max_vertex()-root_bb.min_vertex()); std::cout << "model center : " << center << std::endl; std::cout << "model size : " << reset_diameter << std::endl; active_camera_ = new lamure::ren::camera(0, reset_matrix, reset_diameter, false, false); // Increase camera movement speed for debugging purpose. active_camera_->set_dolly_sens_(20.5f); renderer_ = new Renderer(model_transformations_, visible_set, invisible_set); }