More efficient 3D preview of slices

This commit is contained in:
Alessandro Ranellucci 2015-01-15 18:49:07 +01:00
parent 306bc02e29
commit 18e815d032
5 changed files with 130 additions and 83 deletions

View File

@ -22,7 +22,6 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init
on_right_click on_right_click
on_move on_move
volumes volumes
print
_sphi _stheta _sphi _stheta
cutting_plane_z cutting_plane_z
cut_lines_vertices cut_lines_vertices
@ -813,73 +812,6 @@ sub draw_volumes {
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (defined($self->print) && !$fakecolor) {
my $tess = gluNewTess();
gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_VERTEX, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT');
foreach my $object (@{$self->print->objects}) {
foreach my $layer (@{$object->layers}) {
my $gap = 0;
my $top_z = $layer->print_z;
my $bottom_z = $layer->print_z - $layer->height + $gap;
foreach my $copy (@{ $object->_shifted_copies }) {
glPushMatrix();
glTranslatef(map unscale($_), @$copy, 0);
foreach my $slice (@{$layer->slices}) {
glColor3f(@{&DEFAULT_COLOR});
gluTessBeginPolygon($tess);
glNormal3f(0,0,1);
foreach my $polygon (@$slice) {
gluTessBeginContour($tess);
gluTessVertex_p($tess, (map unscale($_), @$_), $layer->print_z) for @$polygon;
gluTessEndContour($tess);
}
gluTessEndPolygon($tess);
foreach my $polygon (@$slice) {
foreach my $line (@{$polygon->lines}) {
if (0) {
glLineWidth(1);
glColor3f(0,0,0);
glBegin(GL_LINES);
glVertex3f((map unscale($_), @{$line->a}), $bottom_z);
glVertex3f((map unscale($_), @{$line->b}), $bottom_z);
glEnd();
}
glLineWidth(0);
glColor3f(@{&DEFAULT_COLOR});
glBegin(GL_QUADS);
# We'll use this for the middle normal when using 4 quads:
#my $xy_normal = $line->normal;
#$_xynormal->scale(1/$line->length);
glNormal3f(0,0,-1);
glVertex3f((map unscale($_), @{$line->a}), $bottom_z);
glVertex3f((map unscale($_), @{$line->b}), $bottom_z);
glNormal3f(0,0,1);
glVertex3f((map unscale($_), @{$line->b}), $top_z);
glVertex3f((map unscale($_), @{$line->a}), $top_z);
glEnd();
}
}
}
glPopMatrix(); # copy
}
}
}
gluDeleteTess($tess);
return;
}
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
@ -888,10 +820,6 @@ sub draw_volumes {
glPushMatrix(); glPushMatrix();
glTranslatef(@{$volume->origin}); glTranslatef(@{$volume->origin});
glVertexPointer_p(3, $volume->verts);
glCullFace(GL_BACK);
glNormalPointer_p($volume->norms);
if ($fakecolor) { if ($fakecolor) {
my $r = ($volume_idx & 0x000000FF) >> 0; my $r = ($volume_idx & 0x000000FF) >> 0;
my $g = ($volume_idx & 0x0000FF00) >> 8; my $g = ($volume_idx & 0x0000FF00) >> 8;
@ -904,7 +832,19 @@ sub draw_volumes {
} else { } else {
glColor4f(@{ $volume->color }); glColor4f(@{ $volume->color });
} }
glCullFace(GL_BACK);
if ($volume->verts) {
glVertexPointer_p(3, $volume->verts);
glNormalPointer_p($volume->norms);
glDrawArrays(GL_TRIANGLES, 0, $volume->verts->elements / 3); glDrawArrays(GL_TRIANGLES, 0, $volume->verts->elements / 3);
}
if ($volume->quad_verts) {
glVertexPointer_p(3, $volume->quad_verts);
glNormalPointer_p($volume->quad_norms);
glDrawArrays(GL_QUADS, 0, $volume->quad_verts->elements / 3);
}
glPopMatrix(); glPopMatrix();
} }
@ -923,17 +863,21 @@ sub draw_volumes {
package Slic3r::GUI::3DScene::Volume; package Slic3r::GUI::3DScene::Volume;
use Moo; use Moo;
has 'mesh' => (is => 'rw', required => 0); # only required for cut contours
has 'bounding_box' => (is => 'ro', required => 1); has 'bounding_box' => (is => 'ro', required => 1);
has 'origin' => (is => 'rw', default => sub { Slic3r::Pointf3->new(0,0,0) });
has 'color' => (is => 'ro', required => 1); has 'color' => (is => 'ro', required => 1);
has 'select_group_id' => (is => 'rw', default => sub { -1 }); has 'select_group_id' => (is => 'rw', default => sub { -1 });
has 'drag_group_id' => (is => 'rw', default => sub { -1 }); has 'drag_group_id' => (is => 'rw', default => sub { -1 });
has 'origin' => (is => 'rw', default => sub { Slic3r::Pointf3->new(0,0,0) });
has 'verts' => (is => 'rw');
has 'norms' => (is => 'rw');
has 'selected' => (is => 'rw', default => sub { 0 }); has 'selected' => (is => 'rw', default => sub { 0 });
has 'hover' => (is => 'rw', default => sub { 0 }); has 'hover' => (is => 'rw', default => sub { 0 });
# geometric data
has 'verts' => (is => 'rw');
has 'norms' => (is => 'rw');
has 'quad_verts' => (is => 'rw');
has 'quad_norms' => (is => 'rw');
has 'mesh' => (is => 'rw'); # only required for cut contours
sub transformed_bounding_box { sub transformed_bounding_box {
my ($self) = @_; my ($self) = @_;
@ -945,10 +889,11 @@ sub transformed_bounding_box {
package Slic3r::GUI::3DScene; package Slic3r::GUI::3DScene;
use base qw(Slic3r::GUI::3DScene::Base); use base qw(Slic3r::GUI::3DScene::Base);
use OpenGL qw(:glconstants); use OpenGL qw(:glconstants :gluconstants :glufunctions);
use List::Util qw(first); use List::Util qw(first);
use Slic3r::Geometry qw(unscale);
use constant COLORS => [ [1,1,0], [1,0.5,0.5], [0.5,1,0.5], [0.5,0.5,1] ]; use constant COLORS => [ [1,1,0,1], [1,0.5,0.5,1], [0.5,1,0.5,1], [0.5,0.5,1,1] ];
__PACKAGE__->mk_accessors(qw( __PACKAGE__->mk_accessors(qw(
color_by color_by
@ -1001,7 +946,7 @@ sub load_object {
} }
my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ]; my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ];
push @$color, $volume->modifier ? 0.5 : 1; $color->[3] = $volume->modifier ? 0.5 : 1;
push @{$self->volumes}, my $v = Slic3r::GUI::3DScene::Volume->new( push @{$self->volumes}, my $v = Slic3r::GUI::3DScene::Volume->new(
bounding_box => $mesh->bounding_box, bounding_box => $mesh->bounding_box,
color => $color, color => $color,
@ -1039,6 +984,88 @@ sub load_object {
return @volumes_idx; return @volumes_idx;
} }
sub load_print_object_slices {
my ($self, $object) = @_;
my @verts = ();
my @norms = ();
my @quad_verts = ();
my @quad_norms = ();
foreach my $layer (@{$object->layers}) {
my $gap = 0;
my $top_z = $layer->print_z;
my $bottom_z = $layer->print_z - $layer->height + $gap;
foreach my $copy (@{ $object->_shifted_copies }) {
{
my @expolygons = map $_->clone, @{$layer->slices};
$_->translate(@$copy) for @expolygons;
$self->_expolygons_to_verts(\@expolygons, $layer->print_z, \@verts, \@norms);
}
foreach my $slice (@{$layer->slices}) {
foreach my $polygon (@$slice) {
foreach my $line (@{$polygon->lines}) {
$line->translate(@$copy);
push @quad_norms, (0,0,-1), (0,0,-1);
push @quad_verts, (map unscale($_), @{$line->a}), $bottom_z;
push @quad_verts, (map unscale($_), @{$line->b}), $bottom_z;
push @quad_norms, (0,0,1), (0,0,1);
push @quad_verts, (map unscale($_), @{$line->b}), $top_z;
push @quad_verts, (map unscale($_), @{$line->a}), $top_z;
# We'll use this for the middle normal when using 4 quads:
#my $xy_normal = $line->normal;
#$_xynormal->scale(1/$line->length);
}
}
}
}
}
my $obb = $object->bounding_box;
my $bb = Slic3r::Geometry::BoundingBoxf3->new;
$bb->merge_point(Slic3r::Pointf3->new_unscale(@{$obb->min_point}, 0));
$bb->merge_point(Slic3r::Pointf3->new_unscale(@{$obb->max_point}, $object->size->z));
push @{$self->volumes}, my $v = Slic3r::GUI::3DScene::Volume->new(
bounding_box => $bb,
color => COLORS->[0],
verts => OpenGL::Array->new_list(GL_FLOAT, @verts),
norms => OpenGL::Array->new_list(GL_FLOAT, @norms),
quad_verts => OpenGL::Array->new_list(GL_FLOAT, @quad_verts),
quad_norms => OpenGL::Array->new_list(GL_FLOAT, @quad_norms),
);
}
sub _expolygons_to_verts {
my ($self, $expolygons, $z, $verts, $norms) = @_;
my $tess = gluNewTess();
gluTessCallback($tess, GLU_TESS_BEGIN, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_END, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_VERTEX, sub {
my ($x, $y, $z) = @_;
push @$verts, $x, $y, $z;
push @$norms, (0,0,1), (0,0,1), (0,0,1);
});
gluTessCallback($tess, GLU_TESS_COMBINE, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_ERROR, 'DEFAULT');
gluTessCallback($tess, GLU_TESS_EDGE_FLAG, 'DEFAULT');
foreach my $expolygon (@$expolygons) {
gluTessBeginPolygon($tess);
foreach my $polygon (@$expolygon) {
gluTessBeginContour($tess);
gluTessVertex_p($tess, (map unscale($_), @$_), $z) for @$polygon;
gluTessEndContour($tess);
}
gluTessEndPolygon($tess);
}
gluDeleteTess($tess);
}
sub object_idx { sub object_idx {
my ($self, $volume_idx) = @_; my ($self, $volume_idx) = @_;
return $self->_objects_by_volumes->{$volume_idx}[0]; return $self->_objects_by_volumes->{$volume_idx}[0];

View File

@ -21,4 +21,13 @@ sub new_unscale {
return $class->new(map Slic3r::Geometry::unscale($_), @_); return $class->new(map Slic3r::Geometry::unscale($_), @_);
} }
package Slic3r::Pointf3;
use strict;
use warnings;
sub new_unscale {
my $class = shift;
return $class->new(map Slic3r::Geometry::unscale($_), @_);
}
1; 1;

View File

@ -83,12 +83,11 @@ sub OnInit {
my $canvas; my $canvas;
if ($d3) { if ($d3) {
$canvas = Slic3r::GUI::3DScene->new($panel); $canvas = Slic3r::GUI::3DScene->new($panel);
$canvas->print($print);
$canvas->set_bed_shape($print->config->bed_shape); $canvas->set_bed_shape($print->config->bed_shape);
foreach my $object (@{$print->objects}) { foreach my $object (@{$print->objects}) {
$canvas->load_object($object->model_object); $canvas->load_print_object_slices($object);
#$canvas->load_object($object->model_object);
} }
$canvas->zoom_to_volumes; $canvas->zoom_to_volumes;
} else { } else {

View File

@ -23,6 +23,11 @@ use overload
'@{}' => sub { [ $_[0]->x, $_[0]->y, $_[0]->z ] }, #, '@{}' => sub { [ $_[0]->x, $_[0]->y, $_[0]->z ] }, #,
'fallback' => 1; 'fallback' => 1;
sub pp {
my ($self) = @_;
return [ @$self ];
}
package Slic3r::Pointf; package Slic3r::Pointf;
use overload use overload
'@{}' => sub { $_[0]->arrayref }, '@{}' => sub { $_[0]->arrayref },
@ -33,6 +38,11 @@ use overload
'@{}' => sub { [ $_[0]->x, $_[0]->y, $_[0]->z ] }, #, '@{}' => sub { [ $_[0]->x, $_[0]->y, $_[0]->z ] }, #,
'fallback' => 1; 'fallback' => 1;
sub pp {
my ($self) = @_;
return [ @$self ];
}
package Slic3r::ExPolygon; package Slic3r::ExPolygon;
use overload use overload
'@{}' => sub { $_[0]->arrayref }, '@{}' => sub { $_[0]->arrayref },

View File

@ -88,6 +88,8 @@ new_from_points(CLASS, points)
void translate(double x, double y, double z); void translate(double x, double y, double z);
Clone<Pointf3> size(); Clone<Pointf3> size();
Clone<Pointf3> center(); Clone<Pointf3> center();
Clone<Pointf3> min_point() %code{% RETVAL = THIS->min; %};
Clone<Pointf3> max_point() %code{% RETVAL = THIS->max; %};
double x_min() %code{% RETVAL = THIS->min.x; %}; double x_min() %code{% RETVAL = THIS->min.x; %};
double x_max() %code{% RETVAL = THIS->max.x; %}; double x_max() %code{% RETVAL = THIS->max.x; %};
double y_min() %code{% RETVAL = THIS->min.y; %}; double y_min() %code{% RETVAL = THIS->min.y; %};