44cae1f00 Fix RGBA color painting bug. Fix screen position calculation to allow image projection when in perspective view
This commit is contained in:
@@ -4307,6 +4307,78 @@ static void color_facets_append_sampled_triangle(TriangleColorSplittingData
|
||||
data.colors_rgba.emplace_back(cc);
|
||||
}
|
||||
|
||||
static bool color_facets_append_existing_or_sampled_triangle(
|
||||
const TriangleColorSplittingData &old_data,
|
||||
TriangleColorSplittingData &new_data,
|
||||
const TextureMappingColorSampler &sampler,
|
||||
const TextureMappingColorLeafResamplePredicate &resample_leaf,
|
||||
size_t source_triangle,
|
||||
int bitstream_end,
|
||||
size_t color_end,
|
||||
int &bit_idx,
|
||||
size_t &color_idx,
|
||||
const std::array<Vec3f, 3> &vertices,
|
||||
const std::array<Vec3f, 3> &barycentrics,
|
||||
int depth,
|
||||
int min_depth,
|
||||
int max_depth,
|
||||
float split_color_threshold)
|
||||
{
|
||||
if (bit_idx + 3 >= bitstream_end)
|
||||
return false;
|
||||
|
||||
int code = 0;
|
||||
for (int bit = 0; bit < 4; ++bit)
|
||||
code |= int(old_data.bitstream[size_t(bit_idx++)]) << bit;
|
||||
|
||||
const int split_sides = code & 0b11;
|
||||
if (split_sides == 0) {
|
||||
if (color_idx >= color_end || color_idx >= old_data.colors_rgba.size())
|
||||
return false;
|
||||
|
||||
const uint32_t rgba = old_data.colors_rgba[color_idx++];
|
||||
if (resample_leaf && resample_leaf(source_triangle, vertices, barycentrics, rgba)) {
|
||||
color_facets_append_sampled_triangle(new_data,
|
||||
sampler,
|
||||
source_triangle,
|
||||
vertices,
|
||||
barycentrics,
|
||||
depth,
|
||||
min_depth,
|
||||
max_depth,
|
||||
split_color_threshold);
|
||||
} else {
|
||||
color_facets_append_nibble(new_data.bitstream, 0u);
|
||||
new_data.colors_rgba.emplace_back(rgba);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const int special_side = (code >> 2) & 0b11;
|
||||
color_facets_append_nibble(new_data.bitstream, unsigned(code));
|
||||
const std::array<std::array<Vec3f, 3>, 4> child_vertices = color_facets_split_triangle(vertices, split_sides, special_side);
|
||||
const std::array<std::array<Vec3f, 3>, 4> child_barycentrics = color_facets_split_triangle(barycentrics, split_sides, special_side);
|
||||
for (int child_idx = split_sides; child_idx >= 0; --child_idx) {
|
||||
if (!color_facets_append_existing_or_sampled_triangle(old_data,
|
||||
new_data,
|
||||
sampler,
|
||||
resample_leaf,
|
||||
source_triangle,
|
||||
bitstream_end,
|
||||
color_end,
|
||||
bit_idx,
|
||||
color_idx,
|
||||
child_vertices[size_t(child_idx)],
|
||||
child_barycentrics[size_t(child_idx)],
|
||||
depth + 1,
|
||||
min_depth,
|
||||
max_depth,
|
||||
split_color_threshold))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void color_facets_extract_triangle(const TriangleColorSplittingData &data,
|
||||
int bitstream_end,
|
||||
size_t color_end,
|
||||
@@ -4445,12 +4517,18 @@ bool ColorFacetsAnnotation::set_from_triangle_sampler(const ModelVolume
|
||||
const TextureMappingColorSampler &sampler,
|
||||
int max_depth,
|
||||
float split_color_threshold,
|
||||
const TextureMappingColorSubdivisionDepths &subdivision_depths)
|
||||
const TextureMappingColorSubdivisionDepths &subdivision_depths,
|
||||
const std::vector<bool> *resample_triangles,
|
||||
const TextureMappingColorLeafResamplePredicate &resample_leaf)
|
||||
{
|
||||
TriangleColorSplittingData new_data;
|
||||
new_data.metadata_json = m_data.metadata_json;
|
||||
const indexed_triangle_set &its = mv.mesh().its;
|
||||
new_data.triangles_to_split.reserve(its.indices.size());
|
||||
if (resample_triangles != nullptr) {
|
||||
new_data.bitstream.reserve(m_data.bitstream.size());
|
||||
new_data.colors_rgba.reserve(m_data.colors_rgba.size());
|
||||
}
|
||||
|
||||
const std::array<Vec3f, 3> root_barycentrics = {
|
||||
Vec3f(1.f, 0.f, 0.f),
|
||||
@@ -4461,6 +4539,60 @@ bool ColorFacetsAnnotation::set_from_triangle_sampler(const ModelVolume
|
||||
max_depth = std::clamp(max_depth, 0, 7);
|
||||
split_color_threshold = std::max(split_color_threshold, 0.f);
|
||||
|
||||
size_t preserved_mapping_idx = 0;
|
||||
auto existing_triangle_range = [this, &preserved_mapping_idx](size_t tri_idx,
|
||||
int &bitstream_start,
|
||||
int &bitstream_end,
|
||||
int &color_start,
|
||||
size_t &color_end) {
|
||||
while (preserved_mapping_idx < m_data.triangles_to_split.size() &&
|
||||
m_data.triangles_to_split[preserved_mapping_idx].triangle_idx < int(tri_idx))
|
||||
++preserved_mapping_idx;
|
||||
|
||||
if (preserved_mapping_idx >= m_data.triangles_to_split.size() ||
|
||||
m_data.triangles_to_split[preserved_mapping_idx].triangle_idx != int(tri_idx))
|
||||
return false;
|
||||
|
||||
const auto mapping_it = m_data.triangles_to_split.begin() + preserved_mapping_idx;
|
||||
const auto next_it = std::next(mapping_it);
|
||||
bitstream_start = mapping_it->bitstream_start_idx;
|
||||
bitstream_end = next_it == m_data.triangles_to_split.end() ?
|
||||
int(m_data.bitstream.size()) :
|
||||
next_it->bitstream_start_idx;
|
||||
color_start = mapping_it->color_start_idx;
|
||||
color_end = next_it == m_data.triangles_to_split.end() ?
|
||||
m_data.colors_rgba.size() :
|
||||
size_t(next_it->color_start_idx);
|
||||
|
||||
if (bitstream_start < 0 ||
|
||||
bitstream_start >= bitstream_end ||
|
||||
size_t(bitstream_end) > m_data.bitstream.size() ||
|
||||
color_start < 0 ||
|
||||
size_t(color_start) >= color_end ||
|
||||
color_end > m_data.colors_rgba.size())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto append_preserved_triangle = [this, &new_data, &existing_triangle_range](size_t tri_idx) {
|
||||
int bitstream_start = 0;
|
||||
int bitstream_end = 0;
|
||||
int color_start = 0;
|
||||
size_t color_end = 0;
|
||||
if (!existing_triangle_range(tri_idx, bitstream_start, bitstream_end, color_start, color_end))
|
||||
return false;
|
||||
|
||||
new_data.triangles_to_split.emplace_back(int(tri_idx), int(new_data.bitstream.size()), int(new_data.colors_rgba.size()));
|
||||
new_data.bitstream.insert(new_data.bitstream.end(),
|
||||
m_data.bitstream.begin() + bitstream_start,
|
||||
m_data.bitstream.begin() + bitstream_end);
|
||||
new_data.colors_rgba.insert(new_data.colors_rgba.end(),
|
||||
m_data.colors_rgba.begin() + color_start,
|
||||
m_data.colors_rgba.begin() + color_end);
|
||||
return true;
|
||||
};
|
||||
|
||||
for (size_t tri_idx = 0; tri_idx < its.indices.size(); ++tri_idx) {
|
||||
const auto &tri = its.indices[tri_idx];
|
||||
if (tri[0] < 0 || tri[1] < 0 || tri[2] < 0)
|
||||
@@ -4476,6 +4608,16 @@ bool ColorFacetsAnnotation::set_from_triangle_sampler(const ModelVolume
|
||||
its.vertices[size_t(tri[2])].cast<float>()
|
||||
};
|
||||
|
||||
const bool should_resample_triangle =
|
||||
resample_triangles == nullptr ||
|
||||
tri_idx >= resample_triangles->size() ||
|
||||
(*resample_triangles)[tri_idx];
|
||||
if (resample_triangles != nullptr &&
|
||||
tri_idx < resample_triangles->size() &&
|
||||
!(*resample_triangles)[tri_idx] &&
|
||||
append_preserved_triangle(tri_idx))
|
||||
continue;
|
||||
|
||||
int triangle_min_depth = 0;
|
||||
int triangle_max_depth = max_depth;
|
||||
if (subdivision_depths) {
|
||||
@@ -4487,6 +4629,36 @@ bool ColorFacetsAnnotation::set_from_triangle_sampler(const ModelVolume
|
||||
}
|
||||
|
||||
new_data.triangles_to_split.emplace_back(int(tri_idx), int(new_data.bitstream.size()), int(new_data.colors_rgba.size()));
|
||||
if (resample_leaf && should_resample_triangle) {
|
||||
int bitstream_start = 0;
|
||||
int bitstream_end = 0;
|
||||
int color_start = 0;
|
||||
size_t color_end = 0;
|
||||
if (existing_triangle_range(tri_idx, bitstream_start, bitstream_end, color_start, color_end)) {
|
||||
int bit_idx = bitstream_start;
|
||||
size_t color_idx = size_t(color_start);
|
||||
const size_t new_bitstream_start = new_data.bitstream.size();
|
||||
const size_t new_color_start = new_data.colors_rgba.size();
|
||||
if (color_facets_append_existing_or_sampled_triangle(m_data,
|
||||
new_data,
|
||||
sampler,
|
||||
resample_leaf,
|
||||
tri_idx,
|
||||
bitstream_end,
|
||||
color_end,
|
||||
bit_idx,
|
||||
color_idx,
|
||||
vertices,
|
||||
root_barycentrics,
|
||||
0,
|
||||
triangle_min_depth,
|
||||
triangle_max_depth,
|
||||
split_color_threshold))
|
||||
continue;
|
||||
new_data.bitstream.resize(new_bitstream_start);
|
||||
new_data.colors_rgba.resize(new_color_start);
|
||||
}
|
||||
}
|
||||
color_facets_append_sampled_triangle(new_data,
|
||||
sampler,
|
||||
tri_idx,
|
||||
@@ -4666,12 +4838,29 @@ bool model_mmu_segmentation_data_changed(const ModelObject& mo, const ModelObjec
|
||||
});
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static bool model_volume_imported_vector_matches(const ModelVolumeImportedVector<T> &lhs, const ModelVolumeImportedVector<T> &rhs)
|
||||
{
|
||||
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
|
||||
}
|
||||
|
||||
static bool model_volume_texture_mapping_data_matches(const ModelVolume &mv_old, const ModelVolume &mv_new)
|
||||
{
|
||||
return mv_old.texture_mapping_color_facets.timestamp_matches(mv_new.texture_mapping_color_facets) &&
|
||||
model_volume_imported_vector_matches(mv_old.imported_vertex_colors_rgba, mv_new.imported_vertex_colors_rgba) &&
|
||||
model_volume_imported_vector_matches(mv_old.imported_texture_uvs_per_face, mv_new.imported_texture_uvs_per_face) &&
|
||||
model_volume_imported_vector_matches(mv_old.imported_texture_uv_valid, mv_new.imported_texture_uv_valid) &&
|
||||
model_volume_imported_vector_matches(mv_old.imported_texture_rgba, mv_new.imported_texture_rgba) &&
|
||||
mv_old.imported_texture_width == mv_new.imported_texture_width &&
|
||||
mv_old.imported_texture_height == mv_new.imported_texture_height;
|
||||
}
|
||||
|
||||
bool model_texture_mapping_color_data_changed(const ModelObject& mo, const ModelObject& mo_new)
|
||||
{
|
||||
return model_property_changed(mo, mo_new,
|
||||
[](const ModelVolumeType t) { return t == ModelVolumeType::MODEL_PART; },
|
||||
[](const ModelVolume &mv_old, const ModelVolume &mv_new) {
|
||||
return mv_old.texture_mapping_color_facets.timestamp_matches(mv_new.texture_mapping_color_facets);
|
||||
return model_volume_texture_mapping_data_matches(mv_old, mv_new);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -846,6 +846,8 @@ struct ColorFacetTriangle
|
||||
|
||||
using TextureMappingColorSampler = std::function<uint32_t(size_t, const Vec3f &, const Vec3f &)>;
|
||||
using TextureMappingColorSubdivisionDepths = std::function<std::pair<int, int>(size_t, const std::array<Vec3f, 3> &)>;
|
||||
using TextureMappingColorLeafResamplePredicate =
|
||||
std::function<bool(size_t, const std::array<Vec3f, 3> &, const std::array<Vec3f, 3> &, uint32_t)>;
|
||||
|
||||
class ColorFacetsAnnotation final : public ObjectWithTimestamp {
|
||||
public:
|
||||
@@ -886,7 +888,9 @@ public:
|
||||
const TextureMappingColorSampler &sampler,
|
||||
int max_depth = 2,
|
||||
float split_color_threshold = 0.045f,
|
||||
const TextureMappingColorSubdivisionDepths &subdivision_depths = {});
|
||||
const TextureMappingColorSubdivisionDepths &subdivision_depths = {},
|
||||
const std::vector<bool> *resample_triangles = nullptr,
|
||||
const TextureMappingColorLeafResamplePredicate &resample_leaf = {});
|
||||
void get_facet_triangles(const ModelVolume &mv, std::vector<ColorFacetTriangle> &facets) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -80,6 +80,12 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
|
||||
mv_dst.mmu_segmentation_facets.assign(mv_src.mmu_segmentation_facets);
|
||||
assert(mv_dst.texture_mapping_color_facets.id() == mv_src.texture_mapping_color_facets.id());
|
||||
mv_dst.texture_mapping_color_facets.assign(mv_src.texture_mapping_color_facets);
|
||||
mv_dst.imported_vertex_colors_rgba = mv_src.imported_vertex_colors_rgba;
|
||||
mv_dst.imported_texture_uvs_per_face = mv_src.imported_texture_uvs_per_face;
|
||||
mv_dst.imported_texture_uv_valid = mv_src.imported_texture_uv_valid;
|
||||
mv_dst.imported_texture_rgba = mv_src.imported_texture_rgba;
|
||||
mv_dst.imported_texture_width = mv_src.imported_texture_width;
|
||||
mv_dst.imported_texture_height = mv_src.imported_texture_height;
|
||||
assert(mv_dst.fuzzy_skin_facets.id() == mv_src.fuzzy_skin_facets.id());
|
||||
mv_dst.fuzzy_skin_facets.assign(mv_src.fuzzy_skin_facets);
|
||||
//FIXME what to do with the materials?
|
||||
|
||||
@@ -706,6 +706,36 @@ static float distance_between_segments(const Vec3f &p1, const Vec3f &q1, const V
|
||||
return (p1 + d1 * s - (p2 + d2 * t)).norm();
|
||||
}
|
||||
|
||||
static bool rgb_point_in_triangle(const Vec3f &point, const std::array<Vec3f, 3> &triangle)
|
||||
{
|
||||
Vec3f weights = Vec3f::Zero();
|
||||
const float tolerance = -1e-4f;
|
||||
return barycentric_weights_for_region_vertex_colors(point, triangle[0], triangle[1], triangle[2], weights) &&
|
||||
weights.x() >= tolerance &&
|
||||
weights.y() >= tolerance &&
|
||||
weights.z() >= tolerance;
|
||||
}
|
||||
|
||||
static bool rgb_triangles_overlap(const std::array<Vec3f, 3> &lhs, const std::array<Vec3f, 3> &rhs)
|
||||
{
|
||||
for (const Vec3f &point : lhs)
|
||||
if (rgb_point_in_triangle(point, rhs))
|
||||
return true;
|
||||
for (const Vec3f &point : rhs)
|
||||
if (rgb_point_in_triangle(point, lhs))
|
||||
return true;
|
||||
|
||||
const float edge_tolerance = 1e-4f;
|
||||
for (size_t lhs_idx = 0; lhs_idx < 3; ++lhs_idx)
|
||||
for (size_t rhs_idx = 0; rhs_idx < 3; ++rhs_idx)
|
||||
if (distance_between_segments(lhs[lhs_idx],
|
||||
lhs[(lhs_idx + 1) % 3],
|
||||
rhs[rhs_idx],
|
||||
rhs[(rhs_idx + 1) % 3]) <= edge_tolerance)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static Vec3f transform_point(const Transform3d &matrix, const Vec3f &point)
|
||||
{
|
||||
return (matrix * point.cast<double>()).cast<float>();
|
||||
@@ -963,27 +993,43 @@ static std::vector<bool> rgb_brush_candidate_source_triangles(
|
||||
return candidates;
|
||||
}
|
||||
|
||||
static int rgb_leaf_count_depth(size_t leaf_count)
|
||||
static int rgb_color_tree_max_depth(const TriangleColorSplittingData &data, int bitstream_end, int &bit_idx, int depth)
|
||||
{
|
||||
int depth = 0;
|
||||
size_t depth_leaf_count = 1;
|
||||
while (depth_leaf_count < leaf_count && depth < 7) {
|
||||
depth_leaf_count *= 4;
|
||||
++depth;
|
||||
}
|
||||
return depth;
|
||||
if (bit_idx + 3 >= bitstream_end)
|
||||
return std::clamp(depth, 0, 7);
|
||||
|
||||
int code = 0;
|
||||
for (int bit = 0; bit < 4; ++bit)
|
||||
code |= int(data.bitstream[size_t(bit_idx++)]) << bit;
|
||||
|
||||
const int split_sides = code & 0b11;
|
||||
if (split_sides == 0)
|
||||
return std::clamp(depth, 0, 7);
|
||||
|
||||
int max_depth = std::clamp(depth + 1, 0, 7);
|
||||
for (int child_idx = split_sides; child_idx >= 0; --child_idx)
|
||||
max_depth = std::max(max_depth, rgb_color_tree_max_depth(data, bitstream_end, bit_idx, depth + 1));
|
||||
return std::clamp(max_depth, 0, 7);
|
||||
}
|
||||
|
||||
static std::vector<int> rgb_existing_source_triangle_depths(const std::vector<ColorFacetTriangle> &facets, size_t triangle_count)
|
||||
static std::vector<int> rgb_existing_source_triangle_depths(const TriangleColorSplittingData &data, size_t triangle_count)
|
||||
{
|
||||
std::vector<size_t> leaf_counts(triangle_count, 0);
|
||||
for (const ColorFacetTriangle &facet : facets)
|
||||
if (facet.source_triangle >= 0 && size_t(facet.source_triangle) < leaf_counts.size())
|
||||
++leaf_counts[size_t(facet.source_triangle)];
|
||||
|
||||
std::vector<int> depths(triangle_count, 0);
|
||||
for (size_t tri_idx = 0; tri_idx < leaf_counts.size(); ++tri_idx)
|
||||
depths[tri_idx] = rgb_leaf_count_depth(leaf_counts[tri_idx]);
|
||||
for (auto mapping_it = data.triangles_to_split.begin(); mapping_it != data.triangles_to_split.end(); ++mapping_it) {
|
||||
if (mapping_it->triangle_idx < 0 || size_t(mapping_it->triangle_idx) >= depths.size())
|
||||
continue;
|
||||
|
||||
const auto next_it = std::next(mapping_it);
|
||||
const int bitstream_start = mapping_it->bitstream_start_idx;
|
||||
const int bitstream_end = next_it == data.triangles_to_split.end() ?
|
||||
int(data.bitstream.size()) :
|
||||
next_it->bitstream_start_idx;
|
||||
if (bitstream_start < 0 || bitstream_start >= bitstream_end || size_t(bitstream_end) > data.bitstream.size())
|
||||
continue;
|
||||
|
||||
int bit_idx = bitstream_start;
|
||||
depths[size_t(mapping_it->triangle_idx)] = rgb_color_tree_max_depth(data, bitstream_end, bit_idx, 0);
|
||||
}
|
||||
return depths;
|
||||
}
|
||||
|
||||
@@ -1076,7 +1122,7 @@ static bool apply_rgb_stroke_to_volume(ModelVolume
|
||||
const int safe_max_depth = texture_mapping_depth_for_budget(volume.mesh().its.indices.size(), 7, 1800000);
|
||||
const float brush_subdivision_target = true_color_brush_subdivision_target(brush_radius);
|
||||
const std::vector<int> existing_source_triangle_depths =
|
||||
rgb_existing_source_triangle_depths(existing_facets, volume.mesh().its.indices.size());
|
||||
rgb_existing_source_triangle_depths(volume.texture_mapping_color_facets.get_data(), volume.mesh().its.indices.size());
|
||||
TextureMappingColorSubdivisionDepths subdivision_depths =
|
||||
[mesh_span,
|
||||
safe_max_depth,
|
||||
@@ -1103,7 +1149,49 @@ static bool apply_rgb_stroke_to_volume(ModelVolume
|
||||
return std::make_pair(min_depth, max_depth);
|
||||
};
|
||||
|
||||
return volume.texture_mapping_color_facets.set_from_triangle_sampler(volume, sampler, safe_max_depth, 0.012f, subdivision_depths);
|
||||
TextureMappingColorLeafResamplePredicate resample_leaf =
|
||||
[opacity,
|
||||
brush_radius,
|
||||
use_brush_path,
|
||||
&brush_stroke_points_world,
|
||||
&world_matrix,
|
||||
&stroke_by_source_triangle,
|
||||
&stroke_facets](size_t tri_idx, const std::array<Vec3f, 3> &vertices, const std::array<Vec3f, 3> &, uint32_t) {
|
||||
if (opacity <= 0.f || brush_radius <= EPSILON)
|
||||
return false;
|
||||
|
||||
if (use_brush_path) {
|
||||
const std::array<Vec3f, 3> world_vertices = transform_triangle(world_matrix, vertices);
|
||||
for (size_t point_idx = 0; point_idx < brush_stroke_points_world.size(); ++point_idx) {
|
||||
const Vec3f segment_a = brush_stroke_points_world[point_idx];
|
||||
const Vec3f segment_b = point_idx + 1 < brush_stroke_points_world.size() ?
|
||||
brush_stroke_points_world[point_idx + 1] :
|
||||
brush_stroke_points_world[point_idx];
|
||||
if (triangle_intersects_brush_segment(world_vertices, segment_a, segment_b, brush_radius))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto found = stroke_by_source_triangle.find(int(tri_idx));
|
||||
if (found == stroke_by_source_triangle.end())
|
||||
return false;
|
||||
for (const size_t facet_idx : found->second) {
|
||||
if (facet_idx >= stroke_facets.size())
|
||||
continue;
|
||||
if (rgb_triangles_overlap(vertices, stroke_facets[facet_idx].vertices))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return volume.texture_mapping_color_facets.set_from_triangle_sampler(volume,
|
||||
sampler,
|
||||
safe_max_depth,
|
||||
0.012f,
|
||||
subdivision_depths,
|
||||
&brush_candidate_triangles,
|
||||
resample_leaf);
|
||||
}
|
||||
|
||||
static bool build_volume_rgb_data(const ModelVolume &volume, const ColorRGBA &background, ColorFacetsAnnotation &out)
|
||||
@@ -6228,7 +6316,7 @@ bool GLGizmoImageProjection::project_to_vertex_colors(ModelObject *object)
|
||||
const OverlayRect rect = overlay_rect();
|
||||
|
||||
ProjectionContext context;
|
||||
context.view_projection = (camera.get_projection_matrix() * camera.get_view_matrix()).matrix();
|
||||
context.view_projection = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix();
|
||||
context.canvas_width = std::max(1, viewport[2]);
|
||||
context.canvas_height = std::max(1, viewport[3]);
|
||||
context.overlay_left = rect.left;
|
||||
@@ -6355,7 +6443,7 @@ bool GLGizmoImageProjection::project_to_image_texture(ModelObject *object)
|
||||
const OverlayRect rect = overlay_rect();
|
||||
|
||||
ProjectionContext context;
|
||||
context.view_projection = (camera.get_projection_matrix() * camera.get_view_matrix()).matrix();
|
||||
context.view_projection = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix();
|
||||
context.canvas_width = std::max(1, viewport[2]);
|
||||
context.canvas_height = std::max(1, viewport[3]);
|
||||
context.overlay_left = rect.left;
|
||||
@@ -6522,7 +6610,7 @@ bool GLGizmoImageProjection::project_to_rgb_data(ModelObject *object)
|
||||
const OverlayRect rect = overlay_rect();
|
||||
|
||||
ProjectionContext context;
|
||||
context.view_projection = (camera.get_projection_matrix() * camera.get_view_matrix()).matrix();
|
||||
context.view_projection = camera.get_projection_matrix().matrix() * camera.get_view_matrix().matrix();
|
||||
context.canvas_width = std::max(1, viewport[2]);
|
||||
context.canvas_height = std::max(1, viewport[3]);
|
||||
context.overlay_left = rect.left;
|
||||
|
||||
Reference in New Issue
Block a user