Skip to content

Commit d034498

Browse files
committed
fix bugs with center projection, adjust clip plane policies, clean up view API
1 parent 334e80e commit d034498

File tree

3 files changed

+82
-30
lines changed

3 files changed

+82
-30
lines changed

include/polyscope/view.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,15 @@ void setVerticalFieldOfViewDegrees(float newVal);
113113
glm::mat4 computeHomeView();
114114
void resetCameraToHomeView();
115115
void flyToHomeView();
116-
void setViewCenter(glm::vec3 newCenter, bool flyTo = false);
116+
void setViewCenterAndLookAt(glm::vec3 newCenter, bool flyTo = false);
117+
void setViewCenterAndProject(glm::vec3 newCenter);
118+
void setViewCenterRaw(glm::vec3 newCenter);
117119
glm::vec3 getViewCenter();
118120

119121
// These both set the new value, and project the current view as-needed to conform to the new setting
120122
void updateViewAndChangeNavigationStyle(NavigateStyle newStyle, bool flyTo = false);
121123
void updateViewAndChangeUpDir(UpDir newUpDir, bool flyTo = false);
122124
void updateViewAndChangeFrontDir(FrontDir newFrontDir, bool flyTo = false);
123-
void updateViewAndChangeCenter(glm::vec3 newCenter, bool flyTo = false);
124125

125126
// Move the camera with a 'flight' where the camera's position is briefly animated
126127
void startFlightTo(const CameraParameters& p, float flightLengthInSeconds = .4);
@@ -169,8 +170,6 @@ std::string getCameraJson(); // DEPRACTED: old names for avove
169170
void setCameraFromJson(std::string jsonData, bool flyTo);
170171

171172
// Misc helpers
172-
std::string to_string(ProjectionMode mode);
173-
std::string to_string(NavigateStyle style);
174173
std::tuple<int, int> screenCoordsToBufferInds(glm::vec2 screenCoords);
175174
glm::ivec2 screenCoordsToBufferIndsVec(glm::vec2 screenCoords);
176175
glm::vec2 bufferIndsToScreenCoords(int xPos, int yPos);
@@ -197,11 +196,15 @@ void ensureViewValid();
197196

198197
float computeRelativeMotionScale();
199198

199+
// For some navigation modes, the view and center must be compatible (e.g.) with turntable the view
200+
// must point at the center along the up axis. This function modifies the center as-needed to ensure compatibility.
201+
void projectCenterToBeValidForView();
202+
200203
// Process user inputs which affect the view
201204
void processTranslate(glm::vec2 delta);
202205
void processRotate(glm::vec2 startP, glm::vec2 endP);
203206
void processClipPlaneShift(float amount);
204-
void processZoom(float amount, bool relativeToCenter = false);
207+
void processZoom(float amount);
205208
void processKeyboardNavigation(ImGuiIO& io);
206209
void processSetCenter(glm::vec2 screenCoords);
207210

src/polyscope.cpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -464,25 +464,23 @@ void processInputEvents() {
464464
float xoffset = io.MouseWheelH;
465465
float yoffset = io.MouseWheel;
466466
float scrollOffset = yoffset;
467+
float clipPlaneOffset = std::abs(xoffset) > std::abs(yoffset) ? xoffset : yoffset;
467468

468469
// NOTE: here we used to scroll according the to the larger of the two offsets (x or y)
469470
// (there was a comment about 'shift swaps scroll on some platforms'). However, on many
470471
// common machines (e.g. macs with touchpads), two finger scrolling produces both x and y
471472
// offsets simultaneously, leading to jumpy zooms when an x was greater than a y.
472-
// So now we just use the y offset always.
473+
// So now we just use the y offset always for zooming. (But still use either for clip plane shifting,
474+
// which might involve intentionally holding shift)
473475

474-
if (scrollOffset != 0.0f) {
476+
bool scrollClipPlane = io.KeyShift && !io.KeyCtrl;
477+
if (scrollClipPlane && clipPlaneOffset != 0.0f) {
478+
view::processClipPlaneShift(clipPlaneOffset);
479+
requestRedraw();
480+
}
481+
if (!scrollClipPlane && scrollOffset != 0.0f) {
482+
view::processZoom(0.5 * scrollOffset);
475483
requestRedraw();
476-
477-
// Pass camera commands to the camera
478-
bool scrollClipPlane = io.KeyShift && !io.KeyCtrl;
479-
480-
if (scrollClipPlane) {
481-
view::processClipPlaneShift(scrollOffset);
482-
} else {
483-
// always relative
484-
view::processZoom(scrollOffset, true);
485-
}
486484
}
487485
}
488486

@@ -502,7 +500,7 @@ void processInputEvents() {
502500
bool isDragZoom = dragLeft && io.KeyShift && io.KeyCtrl;
503501

504502
if (isDragZoom) {
505-
view::processZoom(dragDelta.y * 5, true);
503+
view::processZoom(dragDelta.y * 5);
506504
}
507505
if (isRotate) {
508506
glm::vec2 currPos{io.MousePos.x / view::windowWidth,

src/view.cpp

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ float& flightInitialFov = state::globalContext.flightInitialFov;
4848
// Default values
4949
const int defaultWindowWidth = 1280;
5050
const int defaultWindowHeight = 720;
51-
const float defaultNearClipRatio = 1e-2;
52-
const float defaultFarClipRatio = 1e2;
51+
const float defaultNearClipRatio = 0.005f;
52+
const float defaultFarClipRatio = 20.f;
5353
const float defaultFov = 45.;
5454
const float minFov = 5.; // for UI
5555
const float maxFov = 160.; // for UI
@@ -274,9 +274,11 @@ void processTranslate(glm::vec2 delta) {
274274
glm::vec3 worldspaceT =
275275
glm::transpose(glm::mat3(viewMat)) * glm::vec3(-movementScale * delta.x, -movementScale * delta.y, 0.0);
276276
glm::vec3 newCenter = oldCenter + worldspaceT;
277-
setViewCenter(newCenter, false);
277+
setViewCenterRaw(newCenter);
278278
}
279279

280+
projectCenterToBeValidForView();
281+
280282
requestRedraw();
281283
immediatelyEndFlight();
282284
}
@@ -288,7 +290,7 @@ void processClipPlaneShift(float amount) {
288290
requestRedraw();
289291
}
290292

291-
void processZoom(float amount, bool relativeToCenter) {
293+
void processZoom(float amount) {
292294
if (amount == 0.0) return;
293295
if (getNavigateStyle() == NavigateStyle::None || getNavigateStyle() == NavigateStyle::FirstPerson) {
294296
return;
@@ -381,7 +383,7 @@ void processSetCenter(glm::vec2 screenCoords) {
381383
PickResult pickResult = pickAtScreenCoords(screenCoords);
382384

383385
if (pickResult.isHit) {
384-
setViewCenter(pickResult.position, true);
386+
setViewCenterAndLookAt(pickResult.position, true);
385387
}
386388
}
387389

@@ -424,6 +426,36 @@ float computeRelativeMotionScale() {
424426
}
425427
}
426428

429+
void projectCenterToBeValidForView() {
430+
// If necessary, move the view center to be one that is compatible with the current view matrix and navigation style.
431+
432+
switch (style) {
433+
case NavigateStyle::Turntable: {
434+
435+
// Center must lie exactly along the camera look direction
436+
437+
glm::vec3 camPos = getCameraWorldPosition();
438+
glm::vec3 camLookDir, camUpDir, camRightDir;
439+
getCameraFrame(camLookDir, camUpDir, camRightDir);
440+
glm::vec3 sceneUpDir = getUpVec();
441+
glm::vec3 vecToCenter = viewCenter - camPos;
442+
float distToCenter = glm::length(vecToCenter);
443+
glm::vec3 newCenter = camPos + camLookDir * distToCenter;
444+
445+
setViewCenterRaw(newCenter);
446+
447+
break;
448+
}
449+
case NavigateStyle::Planar:
450+
case NavigateStyle::Free:
451+
case NavigateStyle::Arcball:
452+
case NavigateStyle::None:
453+
case NavigateStyle::FirstPerson:
454+
// No constraints
455+
break;
456+
}
457+
}
458+
427459
glm::mat4 computeHomeView() {
428460

429461
glm::vec3 target = view::viewCenter;
@@ -558,7 +590,7 @@ void updateViewAndChangeFrontDir(FrontDir newFrontDir, bool flyTo) {
558590
}
559591
}
560592

561-
void updateViewAndChangeCenter(glm::vec3 newCenter, bool flyTo) {
593+
void setViewCenterAndLookAt(glm::vec3 newCenter, bool flyTo) {
562594

563595
view::viewCenter = newCenter;
564596

@@ -594,7 +626,12 @@ void updateViewAndChangeCenter(glm::vec3 newCenter, bool flyTo) {
594626
}
595627
}
596628

597-
void setViewCenter(glm::vec3 newCenter, bool flyTo) { updateViewAndChangeCenter(newCenter, flyTo); }
629+
void setViewCenterAndProject(glm::vec3 newCenter) {
630+
view::viewCenter = newCenter;
631+
projectCenterToBeValidForView();
632+
}
633+
634+
void setViewCenterRaw(glm::vec3 newCenter) { view::viewCenter = newCenter; }
598635

599636
glm::vec3 getViewCenter() { return view::viewCenter; }
600637

@@ -621,10 +658,12 @@ void lookAt(glm::vec3 cameraLocation, glm::vec3 target, glm::vec3 upDir, bool fl
621658
// just continue after; our view handling will take care of the NaN and set it to the default view
622659
}
623660

661+
624662
if (flyTo) {
625663
startFlightTo(targetView, fov);
626664
} else {
627665
viewMat = targetView;
666+
projectCenterToBeValidForView();
628667
requestRedraw();
629668
}
630669
}
@@ -646,6 +685,7 @@ void setViewToCamera(const CameraParameters& p) {
646685
fov = p.getFoVVerticalDegrees();
647686
// aspectRatio = p.focalLengths.x / p.focalLengths.y; // TODO should be
648687
// flipped?
688+
projectCenterToBeValidForView();
649689
}
650690

651691
CameraParameters getCameraParametersForCurrentView() {
@@ -656,7 +696,11 @@ CameraParameters getCameraParametersForCurrentView() {
656696
CameraExtrinsics::fromMatrix(viewMat));
657697
}
658698

659-
void setCameraViewMatrix(glm::mat4 mat) { viewMat = mat; }
699+
void setCameraViewMatrix(glm::mat4 mat) {
700+
viewMat = mat;
701+
projectCenterToBeValidForView();
702+
requestRedraw();
703+
}
660704

661705
glm::mat4 getCameraViewMatrix() { return viewMat; }
662706

@@ -778,7 +822,14 @@ glm::vec3 bufferCoordsToWorldRay(glm::vec2 bufferCoords) {
778822
std::tuple<float, float> computeClipPlanes() {
779823
float s = computeRelativeMotionScale();
780824
float absFarClip = farClip * s;
781-
float absNearClip = nearClip * s;
825+
826+
// it's tempting to compute both near and far clip planes from the scale,
827+
// but computing the near clip plane this way gives flickering very quickly when zooming in on surface details
828+
// float absNearClip = nearClip * s;
829+
830+
// instead, always use the length scale for the near clip plane
831+
float absNearClip = nearClip * state::lengthScale;
832+
782833
return std::make_tuple(absNearClip, absFarClip);
783834
}
784835

@@ -1000,10 +1051,10 @@ void setViewFromJson(std::string jsonData, bool flyTo) {
10001051
newCenter.x = centerData[0];
10011052
newCenter.y = centerData[1];
10021053
newCenter.z = centerData[2];
1003-
setViewCenter(newCenter, flyTo);
1054+
setViewCenterRaw(newCenter);
10041055
}
10051056
}
1006-
1057+
10071058
// NOTE: it's important that we do this after the mode/dir settings, as this
10081059
// lets us do our flight
10091060
bool viewChanged = false;
@@ -1027,7 +1078,7 @@ void setViewFromJson(std::string jsonData, bool flyTo) {
10271078
if (flyTo) {
10281079
startFlightTo(newViewMat, fov);
10291080
} else {
1030-
viewMat = newViewMat;
1081+
setCameraViewMatrix(newViewMat);
10311082
fov = newFov;
10321083
requestRedraw();
10331084
}

0 commit comments

Comments
 (0)