ENH:enhance render performance

jira: none
Change-Id: I23ba97d0a00752a131b719436bd062cd0b79e9d2
This commit is contained in:
zhou.xu 2024-06-03 15:35:07 +08:00 committed by Lane.Wei
parent 072f4ed43e
commit 4bf4e1bb91
12 changed files with 558 additions and 26 deletions

View File

@ -10970,7 +10970,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Basic info
Text("Dear ImGui %s", GetVersion());
Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
//Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows);
Text("%d active allocations", io.MetricsActiveAllocations);

View File

@ -172,6 +172,8 @@ void AppConfig::set_defaults()
if (get("zoom_to_mouse").empty())
set_bool("zoom_to_mouse", false);
if (get("enable_lod").empty())
set_bool("enable_lod", true);
if (get("user_bed_type").empty())
set_bool("user_bed_type", true);
if (get("grabber_size_factor").empty())
@ -306,7 +308,7 @@ void AppConfig::set_defaults()
if (get("mouse_wheel").empty()) {
set("mouse_wheel", "0");
}
if (get("max_recent_count").empty()) {
set("max_recent_count", "18");
}

View File

@ -108,6 +108,8 @@ set(lisbslic3r_sources
Fill/FillRectilinear.hpp
Flow.cpp
Flow.hpp
Frustum.cpp
Frustum.hpp
FlushVolCalc.cpp
FlushVolCalc.hpp
format.hpp

94
src/libslic3r/Frustum.cpp Normal file
View File

@ -0,0 +1,94 @@
#include "Frustum.hpp"
#include <cmath>
namespace Slic3r {
Frustum::Plane::PlaneIntersects Frustum::Plane::intersects(const BoundingBoxf3 &box) const
{
Vec3f center = ((box.min + box.max) * 0.5f).cast<float>();
Vec3f extent = ((box.max - box.min) * 0.5f).cast<float>();
float d = distance(center);
float r = fabsf(extent.x() * normal_.x()) + fabsf(extent.y() * normal_.y()) + fabsf(extent.z() * normal_.z());
if (d == r) {
return Plane::Intersects_Tangent;
} else if (std::abs(d) < r) {
return Plane::Intersects_Cross;
}
return (d > 0.0f) ? Plane::Intersects_Front : Plane::Intersects_Back;
}
Frustum::Plane::PlaneIntersects Frustum::Plane::intersects(const Vec3f &p0) const
{
float d = distance(p0);
if (d == 0) {
return Plane::Intersects_Tangent;
}
return (d > 0.0f) ? Plane::Intersects_Front : Plane::Intersects_Back;
}
Frustum::Plane::PlaneIntersects Frustum::Plane::intersects(const Vec3f &p0, const Vec3f &p1) const
{
Plane::PlaneIntersects state0 = intersects(p0);
Plane::PlaneIntersects state1 = intersects(p1);
if (state0 == state1) {
return state0;
}
if (state0 == Plane::Intersects_Tangent || state1 == Plane::Intersects_Tangent) {
return Plane::Intersects_Tangent;
}
return Plane::Intersects_Cross;
}
Frustum::Plane::PlaneIntersects Frustum::Plane::intersects(const Vec3f &p0, const Vec3f &p1, const Vec3f &p2) const
{
Plane::PlaneIntersects state0 = intersects(p0, p1);
Plane::PlaneIntersects state1 = intersects(p0, p2);
Plane::PlaneIntersects state2 = intersects(p1, p2);
if (state0 == state1 && state0 == state2) {
return state0; }
if (state0 == Plane::Intersects_Cross || state1 == Plane::Intersects_Cross || state2 == Plane::Intersects_Cross) {
return Plane::Intersects_Cross;
}
return Plane::Intersects_Tangent;
}
bool Frustum::intersects(const BoundingBoxf3 &box) const {
for (auto &plane : planes) {
if (plane.intersects(box) == Plane::Intersects_Back) {
return false;
}
}
// check box intersects
if (!bbox.intersects(box)) {
return false;
}
return true;
}
bool Frustum::intersects(const Vec3f &p0) const {
for (auto &plane : planes) {
if (plane.intersects(p0) == Plane::Intersects_Back) { return false; }
}
return true;
}
bool Frustum::intersects(const Vec3f &p0, const Vec3f &p1) const
{
for (auto &plane : planes) {
if (plane.intersects(p0, p1) == Plane::Intersects_Back) {
return false;
}
}
return true;
}
bool Frustum::intersects(const Vec3f &p0, const Vec3f &p1, const Vec3f &p2) const
{
for (auto &plane : planes) {
if (plane.intersects(p0, p1, p2) == Plane::Intersects_Back) {
return false;
}
}
return true;
}
} // namespace Slic3r

79
src/libslic3r/Frustum.hpp Normal file
View File

@ -0,0 +1,79 @@
#ifndef slic3r_Frustum_hpp_
#define slic3r_Frustum_hpp_
#include "Point.hpp"
#include "BoundingBox.hpp"
namespace Slic3r {
class Frustum
{
public:
Frustum()=default;
~Frustum() = default;
class Plane {
public:
enum PlaneIntersects { Intersects_Cross = 0, Intersects_Tangent = 1, Intersects_Front = 2, Intersects_Back = 3 };
void set(const Vec3f &n, const Vec3f &pt)
{
normal_ = n.normalized();
center_ = pt;
d_ = -normal_.dot(pt);
}
float distance(const Vec3f &pt) const { return normal_.dot(pt) + d_; }
inline const Vec3f &getNormal() const { return normal_; }
Plane::PlaneIntersects intersects(const BoundingBoxf3 &box) const;
//// check intersect with point (world space)
Plane::PlaneIntersects intersects(const Vec3f &p0) const;
// check intersect with line segment (world space)
Plane::PlaneIntersects intersects(const Vec3f &p0, const Vec3f &p1) const;
// check intersect with triangle (world space)
Plane::PlaneIntersects intersects(const Vec3f &p0, const Vec3f &p1, const Vec3f &p2) const;
private:
Vec3f normal_;
Vec3f center_;
float d_ = 0;
};
bool intersects(const BoundingBoxf3 &box) const;
// check intersect with point (world space)
bool intersects(const Vec3f &p0) const;
// check intersect with line segment (world space)
bool intersects(const Vec3f &p0, const Vec3f &p1) const;
// check intersect with triangle (world space)
bool intersects(const Vec3f &p0, const Vec3f &p1, const Vec3f &p2) const;
Plane planes[6];
/* corners[0]: nearTopLeft;
* corners[1]: nearTopRight;
* corners[2]: nearBottomLeft;
* corners[3]: nearBottomRight;
* corners[4]: farTopLeft;
* corners[5]: farTopRight;
* corners[6]: farBottomLeft;
* corners[7]: farBottomRight;
*/
Vec3f corners[8];
BoundingBoxf3 bbox;
};
enum FrustumClipMask {
POSITIVE_X = 1 << 0,
NEGATIVE_X = 1 << 1,
POSITIVE_Y = 1 << 2,
NEGATIVE_Y = 1 << 3,
POSITIVE_Z = 1 << 4,
NEGATIVE_Z = 1 << 5,
};
const int FrustumClipMaskArray[6] = {
FrustumClipMask::POSITIVE_X, FrustumClipMask::NEGATIVE_X, FrustumClipMask::POSITIVE_Y, FrustumClipMask::NEGATIVE_Y, FrustumClipMask::POSITIVE_Z, FrustumClipMask::NEGATIVE_Z,
};
const Vec4f FrustumClipPlane[6] = {{-1, 0, 0, 1}, {1, 0, 0, 1}, {0, -1, 0, 1}, {0, 1, 0, 1}, {0, 0, -1, 1}, {0, 0, 1, 1}};
}
#endif

View File

@ -10,6 +10,7 @@
#include "GLShader.hpp"
#include "GUI_App.hpp"
#include "GUI_Colors.hpp"
//#include "Camera.hpp"
#include "Plater.hpp"
#include "BitmapCache.hpp"
@ -27,6 +28,7 @@
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/Tesselate.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/QuadricEdgeCollapse.hpp"
#include <stdio.h>
#include <stdlib.h>
@ -415,6 +417,45 @@ std::array<std::array<float, 4>, 5> GLVolume::MODEL_COLOR = { {
{ 1.0f, 1.0f, 0.0f, 1.f }
} };
float GLVolume::LOD_HIGH_ZOOM = 3.5f;
float GLVolume::LOD_MIDDLE_ZOOM = 2.8f;
float GLVolume::LOD_SMALL_ZOOM = 1.4f;
float GLVolume::LAST_CAMERA_ZOOM_VALUE = 0.0f;
const float ZOOM_THRESHOLD = 0.3f;
const unsigned char LOD_UPDATE_FREQUENCY = 20;
const Vec2i LOD_SCREEN_MIN = Vec2i(45, 35);
const Vec2i LOD_SCREEN_MAX = Vec2i(70, 55);
Vec2f calc_pt_in_screen(const Vec3d &pt, const Transform3d &world_tran, const Matrix4d &view_proj_mat, int window_width, int window_height)
{
auto tran = (view_proj_mat * world_tran);
Vec4d temp_center(pt.x(), pt.y(), pt.z(), 1.0);
Vec4d temp_ndc = tran * temp_center;
Vec3d screen_box_center = Vec3d(temp_ndc.x(), temp_ndc.y(), temp_ndc.z()) / temp_ndc.w();
float x = 0.5f * (1 + screen_box_center(0)) * window_width;
float y = 0.5f * (1 - screen_box_center(1)) * window_height;
return Vec2f(x, y);
}
LOD_LEVEL calc_volume_box_in_screen_bigger_than_threshold(
const BoundingBoxf3 &v_box, const Transform3d &world_tran, const Matrix4d &view_proj_mat,
int window_width, int window_height)
{
auto s_min = calc_pt_in_screen(v_box.min, world_tran, view_proj_mat, window_width, window_height);
auto s_max = calc_pt_in_screen(v_box.max, world_tran, view_proj_mat, window_width, window_height);
auto size_x = abs(s_max.x() - s_min.x());
auto size_y = abs(s_max.y() - s_min.y());
if (size_x >= LOD_SCREEN_MAX.x() || size_y >= LOD_SCREEN_MAX.y()) {
return LOD_LEVEL::HIGH;
}
if (size_x <= LOD_SCREEN_MIN.x() && size_y <= LOD_SCREEN_MIN.y()) {
return LOD_LEVEL::SMALL;
} else {
return LOD_LEVEL::MIDDLE;
}
}
void GLVolume::update_render_colors()
{
GLVolume::DISABLED_COLOR = GLColor(RenderColor::colors[RenderCol_Model_Disable]);
@ -463,6 +504,8 @@ GLVolume::GLVolume(float r, float g, float b, float a, bool create_index_data)
, force_sinking_contours(false)
, tverts_range(0, size_t(-1))
, qverts_range(0, size_t(-1))
, tverts_range_lod(0, size_t(-1))
, qverts_range_lod(0, size_t(-1))
{
color = { r, g, b, a };
set_render_color(color);
@ -580,6 +623,91 @@ std::array<float, 4> color_from_model_volume(const ModelVolume& model_volume)
return color;
}
bool GLVolume::simplify_mesh(const TriangleMesh &mesh, GLIndexedVertexArray &va, LOD_LEVEL lod) const
{
return simplify_mesh(mesh.its,va,lod);
}
#define SUPER_LARGE_FACES 500000
#define LARGE_FACES 100000
bool GLVolume::simplify_mesh(const indexed_triangle_set &_its, GLIndexedVertexArray &va, LOD_LEVEL lod) const
{
if (_its.indices.size() == 0 || _its.vertices.size() == 0) { return false; }
bool enable_lod = GUI::wxGetApp().app_config->get("enable_lod") == "true";
if (!enable_lod) {
return false;
}
auto its = std::make_unique<indexed_triangle_set>(_its);
auto m_state = std::make_unique<State>();
if (lod == LOD_LEVEL::MIDDLE) {
m_state->config.max_error = 0.5f;
if (_its.indices.size() > SUPER_LARGE_FACES) {
m_state->config.max_error = 0.4f;
} else if (_its.indices.size() > LARGE_FACES) {
m_state->config.max_error = 0.3f;
}
}
if (lod == LOD_LEVEL::SMALL) {
m_state->config.max_error = 0.1f;
if (_its.indices.size() > SUPER_LARGE_FACES) {
m_state->config.max_error = 0.08f;
} else if (_its.indices.size() > LARGE_FACES) {
m_state->config.max_error = 0.05f;
}
}
//std::mutex m_state_mutex;
std::thread m_worker = std::thread(
[&va](std::unique_ptr<indexed_triangle_set> its, std::unique_ptr<State> state) {
// Checks that the UI thread did not request cancellation, throws if so.
std::function<void(void)> throw_on_cancel = []() {
};
std::function<void(int)> statusfn = [&state](int percent) {
state->progress = percent;
};
// Initialize.
uint32_t triangle_count = 0;
float max_error = std::numeric_limits<float>::max();
{
if (state->config.use_count)
triangle_count = state->config.wanted_count;
if (!state->config.use_count)
max_error = state->config.max_error;
state->progress = 0;
state->result.reset();
state->status = State::Status::running;
}
TriangleMesh origin_mesh(*its);
try { // Start the actual calculation.
its_quadric_edge_collapse(*its, triangle_count, &max_error, throw_on_cancel, statusfn);
} catch (std::exception&) {
state->status = State::idle;
}
if (state->status == State::Status::running) {
// We were not cancelled, the result is valid.
state->status = State::Status::idle;
state->result = std::move(its);
}
if (state->result) {
TriangleMesh mesh(*state->result);
float eps = 1.0f;
Vec3f origin_min = origin_mesh.stats().min - Vec3f(eps, eps, eps);
Vec3f origin_max = origin_mesh.stats().max + Vec3f(eps, eps, eps);
if (origin_min.x() < mesh.stats().min.x() && origin_min.y() < mesh.stats().min.y() && origin_min.z() < mesh.stats().min.z()&&
origin_max.x() > mesh.stats().max.x() && origin_max.y() > mesh.stats().max.y() && origin_max.z() > mesh.stats().max.z()) {
va.load_mesh(mesh);
}
else {
state->status = State::cancelling;
}
}
},
std::move(its),std::move(m_state));
if (m_worker.joinable()) {
m_worker.detach();
}
return true;
}
Transform3d GLVolume::world_matrix() const
{
Transform3d m = m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix();
@ -687,7 +815,11 @@ void GLVolume::render(bool with_outline, const std::array<float, 4>& body_color)
glFrontFace(GL_CW);
glsafe(::glCullFace(GL_BACK));
glsafe(::glPushMatrix());
auto camera = GUI::wxGetApp().plater()->get_camera();
auto zoom = camera.get_zoom();
Transform3d vier_mat = camera.get_view_matrix();
Matrix4d vier_proj_mat = camera.get_projection_matrix().matrix() * vier_mat.matrix();
const std::array<int, 4> &viewport = camera.get_viewport();
// BBS: add logic for mmu segmentation rendering
auto render_body = [&]() {
bool color_volume = false;
@ -716,7 +848,6 @@ void GLVolume::render(bool with_outline, const std::array<float, 4>& body_color)
mmuseg_ivas[idx].load_its_flat_shading(its_per_color[idx]);
mmuseg_ivas[idx].finalize_geometry(true);
}
mmuseg_ts = mv->mmu_segmentation_facets.timestamp();
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, new mmuseg_ts %3%, new color size %4%")
%this %this->name %mmuseg_ts %mmuseg_ivas.size();
@ -734,8 +865,8 @@ void GLVolume::render(bool with_outline, const std::array<float, 4>& body_color)
}
glsafe(::glMultMatrixd(world_matrix().data()));
for (int idx = 0; idx < mmuseg_ivas.size(); idx++) {
GLIndexedVertexArray& iva = mmuseg_ivas[idx];
if (iva.triangle_indices_size == 0 && iva.quad_indices_size == 0)
GLIndexedVertexArray* iva = &mmuseg_ivas[idx];
if (iva->triangle_indices_size == 0 && iva->quad_indices_size == 0)
continue;
if (shader) {
@ -763,7 +894,7 @@ void GLVolume::render(bool with_outline, const std::array<float, 4>& body_color)
}
}
}
iva.render(this->tverts_range, this->qverts_range);
iva->render(this->tverts_range, this->qverts_range);
/*if (force_native_color && (render_color[3] < 1.0)) {
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, tverts_range {%3,%4}, qverts_range{%5%, %6%}")
%this %this->name %this->tverts_range.first %this->tverts_range.second
@ -773,7 +904,32 @@ void GLVolume::render(bool with_outline, const std::array<float, 4>& body_color)
}
else {
glsafe(::glMultMatrixd(world_matrix().data()));
this->indexed_vertex_array->render(this->tverts_range, this->qverts_range);
auto render_which = [this](std::shared_ptr<GLIndexedVertexArray> cur) {
if (cur->vertices_and_normals_interleaved_VBO_id > 0) {
cur->render(tverts_range_lod, qverts_range_lod);
} else {// if (cur->vertices_and_normals_interleaved_VBO_id == 0)
if (cur->triangle_indices.size() > 0) {
cur->finalize_geometry(true);
cur->render(tverts_range_lod, qverts_range_lod);
} else {
indexed_vertex_array->render(this->tverts_range, this->qverts_range);
}
}
};
Transform3d world_tran = world_matrix();
m_lod_update_index++;
if (abs(zoom - LAST_CAMERA_ZOOM_VALUE) > ZOOM_THRESHOLD || m_lod_update_index >= LOD_UPDATE_FREQUENCY){
m_lod_update_index = 0;
LAST_CAMERA_ZOOM_VALUE = zoom;
m_cur_lod_level = calc_volume_box_in_screen_bigger_than_threshold(bounding_box(), world_tran, vier_proj_mat, viewport[2], viewport[3]);
}
if (m_cur_lod_level == LOD_LEVEL::SMALL && indexed_vertex_array_small) {
render_which(indexed_vertex_array_small);
} else if (m_cur_lod_level == LOD_LEVEL::MIDDLE && indexed_vertex_array_middle) {
render_which(indexed_vertex_array_middle);
} else {
this->indexed_vertex_array->render(this->tverts_range, this->qverts_range);
}
}
};
@ -887,9 +1043,22 @@ void GLVolume::render(bool with_outline, const std::array<float, 4>& body_color)
glsafe(::glPushMatrix());
Transform3d matrix = world_matrix();
Transform3d world_tran = matrix;
matrix.scale(scale);
glsafe(::glMultMatrixd(matrix.data()));
this->indexed_vertex_array->render(this->tverts_range, this->qverts_range);
m_lod_update_index++;
if (abs(zoom - LAST_CAMERA_ZOOM_VALUE) > ZOOM_THRESHOLD || m_lod_update_index >= LOD_UPDATE_FREQUENCY) {
m_lod_update_index = 0;
LAST_CAMERA_ZOOM_VALUE = zoom;
m_cur_lod_level = calc_volume_box_in_screen_bigger_than_threshold(bounding_box(), world_tran, vier_proj_mat, viewport[2], viewport[3]);
}
if (m_cur_lod_level == LOD_LEVEL::SMALL && indexed_vertex_array_small && indexed_vertex_array_small->vertices_and_normals_interleaved_VBO_id > 0) {
this->indexed_vertex_array_small->render(this->tverts_range_lod, this->qverts_range_lod);
} else if (m_cur_lod_level == LOD_LEVEL::MIDDLE && indexed_vertex_array_middle && indexed_vertex_array_middle->vertices_and_normals_interleaved_VBO_id > 0) {
this->indexed_vertex_array_middle->render(this->tverts_range_lod, this->qverts_range_lod);
} else {
this->indexed_vertex_array->render(this->tverts_range, this->qverts_range);
}
//BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, outline render for body, shader name %2%")%__LINE__ %shader->get_name();
shader->set_uniform("is_outline", false);
@ -998,6 +1167,14 @@ void GLVolume::simple_render(GLShaderProgram *shader, ModelObjectPtrs &model_obj
glFrontFace(GL_CCW);
}
void GLVolume::set_bounding_boxes_as_dirty()
{
m_lod_update_index = LOD_UPDATE_FREQUENCY;
m_transformed_bounding_box.reset();
m_transformed_convex_hull_bounding_box.reset();
m_transformed_non_sinking_bounding_box.reset();
}
bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -int(slaposSupportTree); }
bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposPad); }
@ -1112,6 +1289,8 @@ int GLVolumeCollection::load_object_volume(
else {
GLVolume* first_volume = *(volume_set.begin());
new_volume->indexed_vertex_array = first_volume->indexed_vertex_array;
new_volume->indexed_vertex_array_middle = first_volume->indexed_vertex_array_middle;
new_volume->indexed_vertex_array_small = first_volume->indexed_vertex_array_small;
need_create_mesh = false;
}
volume_set.emplace(new_volume);
@ -1127,6 +1306,10 @@ int GLVolumeCollection::load_object_volume(
#if ENABLE_SMOOTH_NORMALS
v.indexed_vertex_array->load_mesh(mesh, true);
#else
if (v.indexed_vertex_array_middle == nullptr) { v.indexed_vertex_array_middle = std::make_shared<GLIndexedVertexArray>(); }
v.simplify_mesh(mesh, *v.indexed_vertex_array_middle, LOD_LEVEL::MIDDLE); // include finalize_geometry
if (v.indexed_vertex_array_small == nullptr) { v.indexed_vertex_array_small = std::make_shared<GLIndexedVertexArray>(); }
v.simplify_mesh(mesh, *v.indexed_vertex_array_small, LOD_LEVEL::SMALL);
v.indexed_vertex_array->load_mesh(mesh);
#endif // ENABLE_SMOOTH_NORMALS
v.indexed_vertex_array->finalize_geometry(opengl_initialized);
@ -1369,7 +1552,12 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
if (disable_cullface)
glsafe(::glDisable(GL_CULL_FACE));
auto camera = GUI::wxGetApp().plater()->get_camera();
for (GLVolumeWithIdAndZ& volume : to_render) {
auto world_box = volume.first->transformed_bounding_box();
if (!camera.getFrustum().intersects(world_box)) {
continue;
}
#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
if (type == ERenderType::Transparent) {
volume.first->force_transparent = true;

View File

@ -256,8 +256,20 @@ public:
private:
BoundingBox m_bounding_box;
};
enum LOD_LEVEL {
HIGH, // Origin data
MIDDLE,
SMALL,
};
class GLVolume {
static float LOD_HIGH_ZOOM;
static float LOD_MIDDLE_ZOOM;
static float LOD_SMALL_ZOOM;
static float LAST_CAMERA_ZOOM_VALUE;
mutable LOD_LEVEL m_cur_lod_level = LOD_LEVEL::HIGH;
mutable unsigned char m_lod_update_index = 0;
public:
std::string name;
bool is_text_shape{false};
@ -292,6 +304,9 @@ public:
virtual ~GLVolume() = default;
// BBS
bool simplify_mesh(const TriangleMesh &mesh, GLIndexedVertexArray &va, LOD_LEVEL lod) const;
bool simplify_mesh(const indexed_triangle_set &_its, GLIndexedVertexArray &va, LOD_LEVEL lod) const;
protected:
Geometry::Transformation m_instance_transformation;
Geometry::Transformation m_volume_transformation;
@ -327,6 +342,30 @@ protected:
SinkingContours m_sinking_contours;
// guards m_state
struct Configuration
{
bool use_count = false;//diff with glgizmoSimplify
float decimate_ratio = 50.f; // in percent
uint32_t wanted_count = 0; // initialize by percents
float max_error = 1.; // maximal quadric error
bool operator==(const Configuration &rhs)
{
return (use_count == rhs.use_count && decimate_ratio == rhs.decimate_ratio && wanted_count == rhs.wanted_count && max_error == rhs.max_error);
}
bool operator!=(const Configuration &rhs) { return !(*this == rhs); }
};
struct State
{
enum Status { idle, running, cancelling };
Status status = idle;
int progress = 0; // percent of done work
Configuration config; // Configuration we started with.
const ModelVolume * mv = nullptr;
std::unique_ptr<indexed_triangle_set> result;
};
public:
// Color of the triangles / quads held by this volume.
std::array<float, 4> color;
@ -400,7 +439,9 @@ public:
EHoverState hover;
// Interleaved triangles & normals with indexed triangles & quads.
std::shared_ptr<GLIndexedVertexArray> indexed_vertex_array;
std::shared_ptr<GLIndexedVertexArray> indexed_vertex_array;
std::shared_ptr<GLIndexedVertexArray> indexed_vertex_array_middle;
std::shared_ptr<GLIndexedVertexArray> indexed_vertex_array_small;
const TriangleMesh * ori_mesh{nullptr};
// BBS
mutable std::vector<GLIndexedVertexArray> mmuseg_ivas;
@ -409,7 +450,8 @@ public:
// Ranges of triangle and quad indices to be rendered.
std::pair<size_t, size_t> tverts_range;
std::pair<size_t, size_t> qverts_range;
std::pair<size_t, size_t> tverts_range_lod;
std::pair<size_t, size_t> qverts_range_lod;
// If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts
// of the extrusions per layer.
std::vector<coordf_t> print_zs;
@ -533,11 +575,7 @@ public:
void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array->finalize_geometry(opengl_initialized); }
void release_geometry() { this->indexed_vertex_array->release_geometry(); }
void set_bounding_boxes_as_dirty() {
m_transformed_bounding_box.reset();
m_transformed_convex_hull_bounding_box.reset();
m_transformed_non_sinking_bounding_box.reset();
}
void set_bounding_boxes_as_dirty();
bool is_sla_support() const;
bool is_sla_pad() const;
@ -573,6 +611,7 @@ typedef std::vector<GLVolume*> GLVolumePtrs;
typedef std::pair<GLVolume*, std::pair<unsigned int, double>> GLVolumeWithIdAndZ;
typedef std::vector<GLVolumeWithIdAndZ> GLVolumeWithIdAndZList;
class GLVolumeCollection
{
public:

View File

@ -56,7 +56,7 @@ void Camera::select_next_type()
void Camera::translate(const Vec3d& displacement) {
if (!displacement.isApprox(Vec3d::Zero())) {
m_view_matrix.translate(-displacement);
update_target();
update_target();
}
}
@ -106,6 +106,104 @@ void Camera::select_view(const std::string& direction)
look_at(m_target - 0.707 * m_distance * Vec3d::UnitY() + 0.707 * m_distance * Vec3d::UnitZ(), m_target, Vec3d::UnitY() + Vec3d::UnitZ());
}
}
//how to use
//BoundingBox bbox = mesh.aabb.transform(transform);
//return camera_->getFrustum().intersects(bbox);
void Camera::update_frustum()
{
auto eye_ = get_position().cast<float>();
auto center_ = get_target().cast<float>();
auto up_ = get_dir_up().cast<float>();
float near_ = m_frustrum_zs.first;
float far_ = m_frustrum_zs.second;
float aspect_ = m_viewport[2] / (double)m_viewport[3];
float fov_ = (float) Geometry::deg2rad(get_fov());
float eps = 0.01;
if (m_last_eye.isApprox(eye_) && m_last_center.isApprox(center_) && m_last_up.isApprox(up_) &&
abs(m_last_near - near_) > eps && abs(m_last_far - far_) > eps &&
abs(m_last_aspect - aspect_) > eps && abs(m_last_fov - fov_) > eps) {
return;
}
m_last_eye = eye_;
m_last_center = center_;
m_last_up = up_;
m_last_near = near_;
m_last_far = far_;
m_last_aspect = aspect_;
m_last_fov = fov_;
Vec3f forward((center_ - eye_).normalized());
Vec3f side((forward.cross(up_)).normalized());
Vec3f up((side.cross(forward)).normalized());
float nearHeightHalf = near_ * std::tan(fov_ / 2.f);
float farHeightHalf = far_ * std::tan(fov_ / 2.f);
float nearWidthHalf = nearHeightHalf * aspect_;
float farWidthHalf = farHeightHalf * aspect_;
// near plane
Vec3f nearCenter = eye_ + forward * near_;
Vec3f nearNormal = forward;
m_frustum.planes[0].set(nearNormal, nearCenter);
// far plane
Vec3f farCenter = eye_ + forward * far_;
Vec3f farNormal = -forward;
m_frustum.planes[1].set(farNormal, farCenter);
// top plane
Vec3f topCenter = nearCenter + up * nearHeightHalf;
Vec3f topNormal = (topCenter - eye_).normalized().cross(side);
m_frustum.planes[2].set(topNormal, topCenter);
// bottom plane
Vec3f bottomCenter = nearCenter - up * nearHeightHalf;
Vec3f bottomNormal = side.cross((bottomCenter - eye_).normalized());
m_frustum.planes[3].set(bottomNormal, bottomCenter);
// left plane
Vec3f leftCenter = nearCenter - side * nearWidthHalf;
Vec3f leftNormal = (leftCenter - eye_).normalized().cross(up);
m_frustum.planes[4].set(leftNormal, leftCenter);
// right plane
Vec3f rightCenter = nearCenter + side * nearWidthHalf;
Vec3f rightNormal = up.cross((rightCenter - eye_).normalized());
m_frustum.planes[5].set(rightNormal, rightCenter);
//// 8 corners
Vec3f nearTopLeft = nearCenter + up * nearHeightHalf - side * nearWidthHalf;
Vec3f nearTopRight = nearCenter + up * nearHeightHalf + side * nearWidthHalf;
Vec3f nearBottomLeft = nearCenter - up * nearHeightHalf - side * nearWidthHalf;
Vec3f nearBottomRight = nearCenter - up * nearHeightHalf + side * nearWidthHalf;
Vec3f farTopLeft = farCenter + up * farHeightHalf - side * farWidthHalf;
Vec3f farTopRight = farCenter + up * farHeightHalf + side * farWidthHalf;
Vec3f farBottomLeft = farCenter - up * farHeightHalf - side * farWidthHalf;
Vec3f farBottomRight = farCenter - up * farHeightHalf + side * farWidthHalf;
m_frustum.corners[0] = nearTopLeft;
m_frustum.corners[1] = nearTopRight;
m_frustum.corners[2] = nearBottomLeft;
m_frustum.corners[3] = nearBottomRight;
m_frustum.corners[4] = farTopLeft;
m_frustum.corners[5] = farTopRight;
m_frustum.corners[6] = farBottomLeft;
m_frustum.corners[7] = farBottomRight;
// bounding box
auto double_min = std::numeric_limits<double>::min();
auto double_max = std::numeric_limits<double>::max();
m_frustum.bbox.min = Vec3d(double_max, double_max, double_max);
m_frustum.bbox.max = Vec3d(double_min, double_min, double_min);
for (auto &corner : m_frustum.corners) {
m_frustum.bbox.min[0] = std::min((float)m_frustum.bbox.min.x(), corner.x());
m_frustum.bbox.min[1] = std::min((float)m_frustum.bbox.min.y(), corner.y());
m_frustum.bbox.min[2] = std::min((float)m_frustum.bbox.min.z(), corner.z());
m_frustum.bbox.max[0] = std::max((float)m_frustum.bbox.max.x(), corner.x());
m_frustum.bbox.max[1] = std::max((float)m_frustum.bbox.max.y(), corner.y());
m_frustum.bbox.max[2] = std::max((float)m_frustum.bbox.max.z(), corner.z());
}
}
double Camera::get_fov() const
{
@ -220,7 +318,7 @@ void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor)
}
#if ENABLE_CAMERA_STATISTICS
void Camera::debug_render() const
void Camera::debug_render()
{
ImGuiWrapper& imgui = *wxGetApp().imgui();
imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
@ -520,7 +618,7 @@ void Camera::set_distance(double distance)
if (m_distance != distance) {
m_view_matrix.translate((distance - m_distance) * get_dir_forward());
m_distance = distance;
update_target();
}
}
@ -626,7 +724,7 @@ void Camera::update_target() {
Vec3d temptarget = get_position() + m_distance * get_dir_forward();
if (!(temptarget-m_target).isApprox(Vec3d::Zero())){
m_target = temptarget;
}
}
}
} // GUI

View File

@ -2,6 +2,7 @@
#define slic3r_Camera_hpp_
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/Frustum.hpp"
#include "3DScene.hpp"
#include <array>
@ -55,6 +56,9 @@ private:
std::pair<double, double> m_frustrum_zs;
BoundingBoxf3 m_scene_box;
Frustum m_frustum;
Vec3f m_last_eye, m_last_center, m_last_up;
float m_last_near, m_last_far, m_last_aspect, m_last_fov;
public:
Camera() { set_default_orientation(); }
@ -69,7 +73,7 @@ public:
void enable_update_config_on_type_change(bool enable) { m_update_config_on_type_change_enabled = enable; }
void translate(const Vec3d& displacement);
const Vec3d& get_target() {
const Vec3d& get_target() {
update_target();
return m_target; }
void set_target(const Vec3d& target);
@ -100,9 +104,9 @@ public:
Vec3d get_dir_up() const { return m_view_matrix.matrix().block(0, 0, 3, 3).row(1); }
Vec3d get_dir_forward() const { return -m_view_matrix.matrix().block(0, 0, 3, 3).row(2); }
Vec3d get_position() const { return m_view_matrix.matrix().inverse().block(0, 3, 3, 1); }
const Frustum & getFrustum() const { return m_frustum; }
void update_frustum();
double get_near_z() const { return m_frustrum_zs.first; }
double get_far_z() const { return m_frustrum_zs.second; }
const std::pair<double, double>& get_z_range() const { return m_frustrum_zs; }
@ -119,7 +123,7 @@ public:
void zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor = DefaultZoomToVolumesMarginFactor);
#if ENABLE_CAMERA_STATISTICS
void debug_render() const;
void debug_render();
#endif // ENABLE_CAMERA_STATISTICS
// translate the camera in world space

View File

@ -1991,7 +1991,7 @@ void GLCanvas3D::render(bool only_init)
#if ENABLE_SHOW_CAMERA_TARGET
_render_camera_target();
#endif // ENABLE_SHOW_CAMERA_TARGET
camera.update_frustum();
if (m_picking_enabled && m_rectangle_selection.is_dragging())
m_rectangle_selection.render(*this);

View File

@ -805,6 +805,28 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxWindow *pa
}
}
if (param == "enable_lod") {
if (wxGetApp().plater()->is_project_dirty()) {
auto result = MessageDialog(static_cast<wxWindow *>(this), _L("The current project has unsaved changes, save it before continuing?"),
wxString(SLIC3R_APP_FULL_NAME) + " - " + _L("Save"), wxYES_NO | wxYES_DEFAULT | wxCENTRE)
.ShowModal();
if (result == wxID_YES) {
wxGetApp().plater()->save_project();
}
}
MessageDialog msg_wingow(nullptr, _L("Please note that the model show will undergo certain changes at small pixels case.\nEnabled LOD requires application restart.") + "\n" + _L("Do you want to continue?"), _L("Enable LOD"),
wxYES| wxYES_DEFAULT | wxCANCEL | wxCENTRE);
if (msg_wingow.ShowModal() == wxID_YES) {
Close();
GetParent()->RemoveChild(this);
wxGetApp().recreate_GUI(_L("Enable LOD"));
} else {
checkbox->SetValue(!checkbox->GetValue());
app_config->set_bool(param, checkbox->GetValue());
app_config->save();
}
}
e.Skip();
});
@ -1107,6 +1129,9 @@ wxWindow* PreferencesDialog::create_general_page()
auto item_mouse_zoom_settings = create_item_checkbox(_L("Zoom to mouse position"), page,
_L("Zoom in towards the mouse pointer's position in the 3D view, rather than the 2D window center."), 50,
"zoom_to_mouse");
auto enable_lod_settings = create_item_checkbox(_L("Improve rendering performance by lod"), page,
_L("Improved rendering performance under the scene of multiple plates and many models."), 50,
"enable_lod");
float range_min = 1.0, range_max = 2.5;
auto item_grabber_size_settings = create_item_range_input(_L("Grabber scale"), page,
_L("Set grabber size for move,rotate,scale tool.") + _L("Value range") + ":[" + std::to_string(range_min) + "," +
@ -1188,6 +1213,7 @@ wxWindow* PreferencesDialog::create_general_page()
sizer_page->Add(item_multi_machine, 0, wxTOP, FromDIP(3));
sizer_page->Add(_3d_settings, 0, wxTOP | wxEXPAND, FromDIP(20));
sizer_page->Add(item_mouse_zoom_settings, 0, wxTOP, FromDIP(3));
sizer_page->Add(enable_lod_settings, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_grabber_size_settings, 0, wxTOP, FromDIP(3));
sizer_page->Add(title_presets, 0, wxTOP | wxEXPAND, FromDIP(20));
sizer_page->Add(item_user_sync, 0, wxTOP, FromDIP(3));

View File

@ -33,7 +33,7 @@ public:
void OnPaint(wxPaintEvent &evt);
virtual ~ProgressDialog();
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO)override;
bool Create(const wxString &title, const wxString &message, int maximum = 100, wxWindow *parent = NULL, int style = wxPD_APP_MODAL | wxPD_AUTO_HIDE);
virtual bool Update(int value, const wxString &newmsg = wxEmptyString, bool *skip = NULL);