mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bubnikv
						bubnikv