diff --git a/3d-viewer/3d_canvas/eda_3d_canvas.cpp b/3d-viewer/3d_canvas/eda_3d_canvas.cpp index 0db97f0514..b7d1f29302 100644 --- a/3d-viewer/3d_canvas/eda_3d_canvas.cpp +++ b/3d-viewer/3d_canvas/eda_3d_canvas.cpp @@ -483,18 +483,25 @@ void EDA_3D_CANVAS::DoRePaint() { m_3d_render->SetCurWindowSize( clientSize ); - bool reloadRaytracingForIntersectionCalculations = false; + bool reloadRaytracingForCalculations = false; if( m_boardAdapter.GetRenderEngine() == RENDER_ENGINE::OPENGL && m_3d_render_opengl->IsReloadRequestPending() ) { - reloadRaytracingForIntersectionCalculations = true; + reloadRaytracingForCalculations = true; } requested_redraw = m_3d_render->Redraw( m_mouse_was_moved || m_camera_is_moving, &activityReporter, &warningReporter ); - if( reloadRaytracingForIntersectionCalculations ) + // Raytracer renderer is responsible for some features also used by the OpenGL + // renderer. + // FIXME: Presumably because raytracing renderer reload is called only after current + // renderer redraw, the old zoom value stays for a single frame. This is ugly, but only + // cosmetic, so I'm not fixing that for now: I don't know how to do this without + // reloading twice (maybe it's not too bad of an idea?) or doing a complicated + // refactor. + if( reloadRaytracingForCalculations ) m_3d_render_raytracing->Reload( nullptr, nullptr, true ); } catch( std::runtime_error& ) @@ -510,7 +517,7 @@ void EDA_3D_CANVAS::DoRePaint() if( m_render_pivot ) { - const float scale = glm::min( m_camera.ZoomGet(), 1.0f ); + const float scale = glm::min( m_camera.GetZoom(), 1.0f ); render_pivot( curtime_delta_s, scale * scale ); } @@ -584,7 +591,7 @@ void EDA_3D_CANVAS::OnMouseWheel( wxMouseEvent& event ) if( m_camera_is_moving ) return; - float delta_move = m_delta_move_step_factor * m_camera.ZoomGet(); + float delta_move = m_delta_move_step_factor * m_camera.GetZoom(); if( m_boardAdapter.GetFlag( FL_MOUSEWHEEL_PANNING ) ) delta_move *= 0.01f * event.GetWheelRotation(); @@ -945,7 +952,7 @@ bool EDA_3D_CANVAS::SetView3D( int aKeycode ) if( m_camera_is_moving ) return false; - const float delta_move = m_delta_move_step_factor * m_camera.ZoomGet(); + const float delta_move = m_delta_move_step_factor * m_camera.GetZoom(); const float arrow_moving_time_speed = 8.0f; bool handled = false; @@ -987,7 +994,7 @@ bool EDA_3D_CANVAS::SetView3D( int aKeycode ) m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER ); m_camera.SetT0_and_T1_current_T(); m_camera.Reset_T1(); - request_start_moving_camera( glm::min( glm::max( m_camera.ZoomGet(), 1/1.26f ), 1.26f ) ); + request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 1 / 1.26f ), 1.26f ) ); return true; case WXK_END: @@ -1023,7 +1030,7 @@ bool EDA_3D_CANVAS::SetView3D( int aKeycode ) m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER ); m_camera.SetT0_and_T1_current_T(); m_camera.Reset_T1(); - request_start_moving_camera( glm::min( glm::max( m_camera.ZoomGet(), 0.5f ), 1.125f ) ); + request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 0.5f ), 1.125f ) ); return true; case ID_VIEW3D_RIGHT: @@ -1069,7 +1076,7 @@ bool EDA_3D_CANVAS::SetView3D( int aKeycode ) m_camera.SetInterpolateMode( CAMERA_INTERPOLATION::BEZIER ); m_camera.SetT0_and_T1_current_T(); m_camera.Reset_T1(); - request_start_moving_camera( glm::min( glm::max( m_camera.ZoomGet(), 0.5f ), 1.125f ) ); + request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 0.5f ), 1.125f ) ); return true; case ID_VIEW3D_BOTTOM: @@ -1077,7 +1084,7 @@ bool EDA_3D_CANVAS::SetView3D( int aKeycode ) m_camera.SetT0_and_T1_current_T(); m_camera.Reset_T1(); m_camera.RotateY_T1( glm::radians( 179.999f ) ); // Rotation = 180 - epsilon - request_start_moving_camera( glm::min( glm::max( m_camera.ZoomGet(), 0.5f ), 1.125f ) ); + request_start_moving_camera( glm::min( glm::max( m_camera.GetZoom(), 0.5f ), 1.125f ) ); return true; case ID_VIEW3D_FLIP: diff --git a/3d-viewer/3d_rendering/camera.cpp b/3d-viewer/3d_rendering/camera.cpp index 69e33f3f90..9099b060f3 100644 --- a/3d-viewer/3d_rendering/camera.cpp +++ b/3d-viewer/3d_rendering/camera.cpp @@ -47,8 +47,8 @@ inline void normalise2PI( float& aAngle ) const wxChar *CAMERA::m_logTrace = wxT( "KI_TRACE_CAMERA" ); -#define MIN_ZOOM 0.10f -#define MAX_ZOOM 2.00f +#define DEFAULT_MIN_ZOOM 0.10f +#define DEFAULT_MAX_ZOOM 1.20f CAMERA::CAMERA( float aInitialDistance ) @@ -61,6 +61,9 @@ CAMERA::CAMERA( float aInitialDistance ) m_projectionType = PROJECTION_TYPE::PERSPECTIVE; m_interpolation_mode = CAMERA_INTERPOLATION::BEZIER; + m_minZoom = DEFAULT_MIN_ZOOM; + m_maxZoom = DEFAULT_MAX_ZOOM; + Reset(); } @@ -118,6 +121,21 @@ void CAMERA::Reset_T1() } +void CAMERA::zoomChanged() +{ + if( m_zoom < m_minZoom ) + m_zoom = m_minZoom; + + if( m_zoom > m_maxZoom ) + m_zoom = m_maxZoom; + + m_camera_pos.z = m_camera_pos_init.z * m_zoom; + + updateViewMatrix(); + rebuildProjection(); +} + + void CAMERA::updateViewMatrix() { m_viewMatrix = glm::translate( glm::mat4( 1.0f ), m_camera_pos ) * @@ -159,9 +177,7 @@ void CAMERA::rebuildProjection() return; m_frustum.ratio = (float) m_windowSize.x / (float)m_windowSize.y; - - // Consider that we can render double the length multiplied by the 2/sqrt(2) - m_frustum.farD = glm::length( m_camera_pos_init ) * 2.0f * ( 2.0f * sqrtf( 2.0f ) ); + m_frustum.farD = glm::length( m_camera_pos_init ) * m_maxZoom * 2.0f; switch( m_projectionType ) { @@ -384,6 +400,12 @@ const glm::mat4& CAMERA::GetProjectionMatrixInv() const } +float CAMERA::GetCameraMinDimension() const +{ + return -m_camera_pos_init.z * m_frustum.tang; +} + + void CAMERA::ResetXYpos() { m_parametersChanged = true; @@ -459,40 +481,34 @@ void CAMERA::ZoomReset() bool CAMERA::Zoom( float aFactor ) { - if( ( m_zoom == MIN_ZOOM && aFactor > 1 ) || ( m_zoom == MAX_ZOOM && aFactor < 1 ) - || aFactor == 1 ) + if( ( m_zoom == m_minZoom && aFactor > 1 ) || ( m_zoom == m_maxZoom && aFactor < 1 ) + || aFactor == 1 ) + { return false; + } m_zoom /= aFactor; - if( m_zoom <= MIN_ZOOM ) - m_zoom = MIN_ZOOM; - - if( m_zoom >= MAX_ZOOM ) - m_zoom = MAX_ZOOM; - - m_camera_pos.z = m_camera_pos_init.z * m_zoom; - - updateViewMatrix(); - rebuildProjection(); - + zoomChanged(); return true; } bool CAMERA::Zoom_T1( float aFactor ) { - if( ( m_zoom == MIN_ZOOM && aFactor > 1 ) || ( m_zoom == MAX_ZOOM && aFactor < 1 ) - || aFactor == 1 ) + if( ( m_zoom == m_minZoom && aFactor > 1 ) || ( m_zoom == m_maxZoom && aFactor < 1 ) + || aFactor == 1 ) + { return false; + } m_zoom_t1 = m_zoom / aFactor; - if( m_zoom_t1 < MIN_ZOOM ) - m_zoom_t1 = MIN_ZOOM; + if( m_zoom_t1 < m_minZoom ) + m_zoom_t1 = m_minZoom; - if( m_zoom_t1 > MAX_ZOOM ) - m_zoom_t1 = MAX_ZOOM; + if( m_zoom_t1 > m_maxZoom ) + m_zoom_t1 = m_maxZoom; m_camera_pos_t1.z = m_camera_pos_init.z * m_zoom_t1; @@ -500,12 +516,6 @@ bool CAMERA::Zoom_T1( float aFactor ) } -float CAMERA::ZoomGet() const -{ - return m_zoom; -} - - void CAMERA::RotateX( float aAngleInRadians ) { m_rotate_aux.x += aAngleInRadians; diff --git a/3d-viewer/3d_rendering/camera.h b/3d-viewer/3d_rendering/camera.h index b46d12078f..01c52daea4 100644 --- a/3d-viewer/3d_rendering/camera.h +++ b/3d-viewer/3d_rendering/camera.h @@ -128,6 +128,9 @@ public: const SFVEC3F& GetLookAtPos_T1() const { return m_lookat_pos_t1; } const SFVEC3F& GetCameraPos() const { return m_camera_pos; } + const SFVEC3F& GetCameraInitPos() const { return m_camera_pos_init; } + + float GetCameraMinDimension() const; /** * Calculate a new mouse drag position @@ -171,7 +174,21 @@ public: bool Zoom_T1( float aFactor ); - float ZoomGet() const ; + float GetZoom() const { return m_zoom; } + + float GetMinZoom() { return m_minZoom; } + void SetMinZoom( float minZoom ) + { + m_minZoom = minZoom; + zoomChanged(); + } + + float GetMaxZoom() { return m_maxZoom; } + void SetMaxZoom( float maxZoom ) + { + m_maxZoom = maxZoom; + zoomChanged(); + } void RotateX( float aAngleInRadians ); void RotateY( float aAngleInRadians ); @@ -236,6 +253,7 @@ public: void MakeRayAtCurrrentMousePosition( SFVEC3F& aOutOrigin, SFVEC3F& aOutDirection ) const; protected: + void zoomChanged(); void rebuildProjection(); void updateFrustum(); void updateViewMatrix(); @@ -249,6 +267,12 @@ protected: float m_zoom_t0; float m_zoom_t1; + /** + * Possible 3D zoom range + */ + float m_minZoom; + float m_maxZoom; + /** * The window size that this camera is working. */ diff --git a/3d-viewer/3d_rendering/raytracing/create_scene.cpp b/3d-viewer/3d_rendering/raytracing/create_scene.cpp index 29c610827e..b798284a15 100644 --- a/3d-viewer/3d_rendering/raytracing/create_scene.cpp +++ b/3d-viewer/3d_rendering/raytracing/create_scene.cpp @@ -917,6 +917,21 @@ void RENDER_3D_RAYTRACE::Reload( REPORTER* aStatusReporter, REPORTER* aWarningRe } } + // Set min. and max. zoom range. This doesn't really fit here, but moving this outside of this + // class would require reimplementing bounding box calculation (feel free to do this if you + // have time and patience). + if( m_objectContainer.GetList().size() > 0 ) + { + /*float ratio = std::max( 1.0f, m_objectContainer.GetBBox().GetMaxDimension() + / m_boardAdapter.GetBBox().GetMaxDimension() );*/ + float ratio = + std::max( 1.0f, m_objectContainer.GetBBox().GetMaxDimension() / RANGE_SCALE_3D ); + m_camera.SetMaxZoom( m_camera.GetMaxZoom() * ratio ); + + m_camera.SetMinZoom( static_cast( MIN_DISTANCE_IU * m_boardAdapter.BiuTo3dUnits() + / -m_camera.GetCameraInitPos().z ) ); + } + // Create an accelerator delete m_accelerator; m_accelerator = new BVH_PBRT( m_objectContainer, 8, SPLITMETHOD::MIDDLE ); diff --git a/3d-viewer/3d_rendering/raytracing/render_3d_raytrace.h b/3d-viewer/3d_rendering/raytracing/render_3d_raytrace.h index aab9a22466..115fc9c603 100644 --- a/3d-viewer/3d_rendering/raytracing/render_3d_raytrace.h +++ b/3d-viewer/3d_rendering/raytracing/render_3d_raytrace.h @@ -55,6 +55,10 @@ typedef enum class RENDER_3D_RAYTRACE : public RENDER_3D_BASE { public: + // TODO: Take into account board thickness so that the camera won't move inside of the board + // when facing it perpendicularly. + static constexpr float MIN_DISTANCE_IU = 4 * PCB_IU_PER_MM; + explicit RENDER_3D_RAYTRACE( EDA_3D_CANVAS* aCanvas, BOARD_ADAPTER& aAdapter, CAMERA& aCamera ); ~RENDER_3D_RAYTRACE();