Documented.
Fixed rough Z buffer quantization issues with ortographic camera. Initial implementation of a perspective camera.
This commit is contained in:
parent
17d9c8c9dd
commit
55218c8c4d
1 changed files with 93 additions and 17 deletions
|
@ -1,3 +1,19 @@
|
|||
# Implements pure perl packages
|
||||
#
|
||||
# Slic3r::GUI::3DScene::Base;
|
||||
# Slic3r::GUI::3DScene::Volume;
|
||||
# Slic3r::GUI::3DScene;
|
||||
#
|
||||
# It uses static methods of a C++ class Slic3r::GUI::_3DScene::GLVertexArray
|
||||
# for efficient building of vertex arrays for OpenGL rendering.
|
||||
#
|
||||
# Slic3r::GUI::Plater::3D derives from Slic3r::GUI::3DScene,
|
||||
# Slic3r::GUI::Plater::3DPreview, Slic3r::GUI::Plater::ObjectCutDialog and Slic3r::GUI::Plater::ObjectPartsPanel
|
||||
# own $self->{canvas} of the Slic3r::GUI::3DScene type.
|
||||
#
|
||||
# Therefore the 3DScene supports renderng of STLs, extrusions and cutting planes,
|
||||
# and camera manipulation.
|
||||
|
||||
package Slic3r::GUI::3DScene::Base;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
@ -6,12 +22,16 @@ use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL
|
|||
# must load OpenGL *before* Wx::GLCanvas
|
||||
use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants);
|
||||
use base qw(Wx::GLCanvas Class::Accessor);
|
||||
use Math::Trig qw(asin);
|
||||
use Math::Trig qw(asin tan);
|
||||
use List::Util qw(reduce min max first);
|
||||
use Slic3r::Geometry qw(X Y Z MIN MAX triangle_normal normalize deg2rad tan scale unscale scaled_epsilon);
|
||||
use Slic3r::Geometry::Clipper qw(offset_ex intersection_pl);
|
||||
use Wx::GLCanvas qw(:all);
|
||||
use Slic3r::Geometry qw(PI);
|
||||
|
||||
# _dirty: boolean flag indicating, that the screen has to be redrawn on EVT_IDLE.
|
||||
# volumes: reference to vector of Slic3r::GUI::3DScene::Volume.
|
||||
# _camera_type: 'perspective' or 'ortho'
|
||||
__PACKAGE__->mk_accessors( qw(_quat _dirty init
|
||||
enable_picking
|
||||
enable_moving
|
||||
|
@ -36,15 +56,20 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init
|
|||
_drag_start_pos
|
||||
_drag_start_xy
|
||||
_dragged
|
||||
_camera_type
|
||||
_camera_target
|
||||
_camera_distance
|
||||
_zoom
|
||||
) );
|
||||
|
||||
use constant TRACKBALLSIZE => 0.8;
|
||||
use constant TURNTABLE_MODE => 1;
|
||||
use constant GROUND_Z => -0.02;
|
||||
# For mesh selection: Not selected - bright yellow.
|
||||
use constant DEFAULT_COLOR => [1,1,0];
|
||||
# For mesh selection: Selected - bright green.
|
||||
use constant SELECTED_COLOR => [0,1,0,1];
|
||||
# For mesh selection: Mouse hovers over the object, but object not selected yet - dark green.
|
||||
use constant HOVER_COLOR => [0.4,0.9,0,1];
|
||||
|
||||
# make OpenGL::Array thread-safe
|
||||
|
@ -88,7 +113,10 @@ sub new {
|
|||
$self->_zoom(1);
|
||||
|
||||
# 3D point in model space
|
||||
$self->_camera_type('ortho');
|
||||
# $self->_camera_type('perspective');
|
||||
$self->_camera_target(Slic3r::Pointf3->new(0,0,0));
|
||||
$self->_camera_distance(0.);
|
||||
|
||||
$self->reset_objects;
|
||||
|
||||
|
@ -272,6 +300,7 @@ sub mouse_event {
|
|||
}
|
||||
}
|
||||
|
||||
# Reset selection.
|
||||
sub reset_objects {
|
||||
my ($self) = @_;
|
||||
|
||||
|
@ -279,6 +308,7 @@ sub reset_objects {
|
|||
$self->_dirty(1);
|
||||
}
|
||||
|
||||
# Setup camera to view all objects.
|
||||
sub set_viewport_from_scene {
|
||||
my ($self, $scene) = @_;
|
||||
|
||||
|
@ -603,15 +633,31 @@ sub Resize {
|
|||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
my $depth = 10 * max(@{ $self->max_bounding_box->size });
|
||||
glOrtho(
|
||||
-$x/2, $x/2, -$y/2, $y/2,
|
||||
-$depth, 2*$depth,
|
||||
);
|
||||
|
||||
if ($self->_camera_type eq 'ortho') {
|
||||
my $depth = 1.05 * $self->max_bounding_box->radius();
|
||||
glOrtho(
|
||||
-$x/2, $x/2, -$y/2, $y/2,
|
||||
-$depth, $depth,
|
||||
);
|
||||
} else {
|
||||
die "Invalid camera type: ", $self->_camera_type, "\n" if ($self->_camera_type ne 'perspective');
|
||||
my $bbox_r = $self->max_bounding_box->radius();
|
||||
my $fov = PI * 45. / 180.;
|
||||
my $fov_tan = tan(0.5 * $fov);
|
||||
my $cam_distance = 0.5 * $bbox_r / $fov_tan;
|
||||
$self->_camera_distance($cam_distance);
|
||||
my $nr = $cam_distance - $bbox_r * 1.1;
|
||||
my $fr = $cam_distance + $bbox_r * 1.1;
|
||||
$nr = 1 if ($nr < 1);
|
||||
$fr = $nr + 1 if ($fr < $nr + 1);
|
||||
my $h2 = $fov_tan * $nr;
|
||||
my $w2 = $h2 * $x / $y;
|
||||
glFrustum(-$w2, $w2, -$h2, $h2, $nr, $fr);
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
|
||||
sub InitGL {
|
||||
my $self = shift;
|
||||
|
||||
|
@ -632,6 +678,7 @@ sub InitGL {
|
|||
glDisable(GL_LINE_SMOOTH);
|
||||
glDisable(GL_POLYGON_SMOOTH);
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST);
|
||||
|
||||
# ambient lighting
|
||||
glLightModelfv_p(GL_LIGHT_MODEL_AMBIENT, 0.3, 0.3, 0.3, 1);
|
||||
|
@ -675,6 +722,12 @@ sub Render {
|
|||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
{
|
||||
# Shift the perspective camera.
|
||||
my $camera_pos = Slic3r::Pointf3->new(0,0,-$self->_camera_distance);
|
||||
glTranslatef(@$camera_pos);
|
||||
}
|
||||
|
||||
if (TURNTABLE_MODE) {
|
||||
glRotatef(-$self->_stheta, 1, 0, 0); # pitch
|
||||
|
@ -691,6 +744,9 @@ sub Render {
|
|||
glLightfv_p(GL_LIGHT0, GL_DIFFUSE, 0.5, 0.5, 0.5, 1);
|
||||
|
||||
if ($self->enable_picking) {
|
||||
# Render the object for picking.
|
||||
# FIXME This cannot possibly work in a multi-sampled context as the color gets mangled by the anti-aliasing.
|
||||
# Better to use software ray-casting on a bounding-box hierarchy.
|
||||
glDisable(GL_LIGHTING);
|
||||
$self->draw_volumes(1);
|
||||
glFlush();
|
||||
|
@ -729,15 +785,18 @@ sub Render {
|
|||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
# Draws a bluish bottom to top gradient over the complete screen.
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(0.0,0.0,0.0);
|
||||
glVertex2f(-1.0,-1.0);
|
||||
glVertex2f(1,-1.0);
|
||||
glVertex3f(-1.0,-1.0, 1.0);
|
||||
glVertex3f( 1.0,-1.0, 1.0);
|
||||
glColor3f(10/255,98/255,144/255);
|
||||
glVertex2f(1, 1);
|
||||
glVertex2f(-1.0, 1);
|
||||
glVertex3f( 1.0, 1.0, 1.0);
|
||||
glVertex3f(-1.0, 1.0, 1.0);
|
||||
glEnd();
|
||||
glPopMatrix();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
|
@ -839,6 +898,7 @@ sub Render {
|
|||
}
|
||||
|
||||
sub draw_volumes {
|
||||
# $fakecolor is a boolean indicating, that the objects shall be rendered in a color coding the object index for picking.
|
||||
my ($self, $fakecolor) = @_;
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
@ -853,6 +913,7 @@ sub draw_volumes {
|
|||
glTranslatef(@{$volume->origin});
|
||||
|
||||
if ($fakecolor) {
|
||||
# Object picking mode. Render the object with a color encoding the object index.
|
||||
my $r = ($volume_idx & 0x000000FF) >> 0;
|
||||
my $g = ($volume_idx & 0x0000FF00) >> 8;
|
||||
my $b = ($volume_idx & 0x00FF0000) >> 16;
|
||||
|
@ -922,23 +983,34 @@ sub draw_volumes {
|
|||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
# Container for object geometry and selection status.
|
||||
package Slic3r::GUI::3DScene::Volume;
|
||||
use Moo;
|
||||
|
||||
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);
|
||||
# An ID for group selection. It may be the same for all meshes of all object instances, or for just a single object instance.
|
||||
has 'select_group_id' => (is => 'rw', default => sub { -1 });
|
||||
# An ID for group dragging. It may be the same for all meshes of all object instances, or for just a single object instance.
|
||||
has 'drag_group_id' => (is => 'rw', default => sub { -1 });
|
||||
# Boolean: Is this object selected?
|
||||
has 'selected' => (is => 'rw', default => sub { 0 });
|
||||
# Boolean: Is mouse over this object?
|
||||
has 'hover' => (is => 'rw', default => sub { 0 });
|
||||
# Vector of two values: a span in the Z axis. Meaningful for a display of layers.
|
||||
has 'range' => (is => 'rw');
|
||||
|
||||
# geometric data
|
||||
has 'qverts' => (is => 'rw'); # GLVertexArray object
|
||||
has 'tverts' => (is => 'rw'); # GLVertexArray object
|
||||
has 'mesh' => (is => 'rw'); # only required for cut contours
|
||||
has 'offsets' => (is => 'rw'); # [ z => [ qverts_idx, tverts_idx ] ]
|
||||
# Geometric data.
|
||||
# Quads: GLVertexArray object: C++ class maintaining an std::vector<float> for coords and normals.
|
||||
has 'qverts' => (is => 'rw');
|
||||
# Triangles: GLVertexArray object
|
||||
has 'tverts' => (is => 'rw');
|
||||
# If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts
|
||||
# of the extrusions per layer.
|
||||
# [ z => [ qverts_idx, tverts_idx ] ]
|
||||
has 'offsets' => (is => 'rw');
|
||||
|
||||
sub transformed_bounding_box {
|
||||
my ($self) = @_;
|
||||
|
@ -948,6 +1020,8 @@ sub transformed_bounding_box {
|
|||
return $bb;
|
||||
}
|
||||
|
||||
|
||||
# The 3D canvas to display objects and tool paths.
|
||||
package Slic3r::GUI::3DScene;
|
||||
use base qw(Slic3r::GUI::3DScene::Base);
|
||||
|
||||
|
@ -956,6 +1030,7 @@ use List::Util qw(first min max);
|
|||
use Slic3r::Geometry qw(scale unscale epsilon);
|
||||
use Slic3r::Print::State ':steps';
|
||||
|
||||
# Perimeter: yellow, Infill: redish, Suport: greenish, last: blueish,
|
||||
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(
|
||||
|
@ -1303,6 +1378,7 @@ sub _extrusionentity_to_verts {
|
|||
push @$heights, map $path->height, 0..$#$path_lines;
|
||||
}
|
||||
}
|
||||
# Calling the C++ implementation Slic3r::_3DScene::_extrusionentity_to_verts_do()
|
||||
Slic3r::GUI::_3DScene::_extrusionentity_to_verts_do($lines, $widths, $heights,
|
||||
$closed, $top_z, $copy, $qverts, $tverts);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue