Skip to content

Commit 8191b1e

Browse files
committed
initial WIP on better picking
1 parent f9e70ec commit 8191b1e

File tree

8 files changed

+109
-17
lines changed

8 files changed

+109
-17
lines changed

include/polyscope/context.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ struct Context {
9797
glm::vec3 flightTargetViewT, flightInitialViewT;
9898
float flightTargetFov, flightInitialFov;
9999

100+
// ======================================================
101+
// === Picking globals from pick.h / pick.cpp
102+
// ======================================================
103+
104+
size_t currLocalPickInd = 0;
105+
Structure* currPickStructure = nullptr;
106+
bool haveSelectionVal = false;
107+
size_t nextPickBufferInd = 1;
108+
std::unordered_map<Structure*, std::tuple<size_t, size_t>> structureRanges;
100109

101110
// ======================================================
102111
// === Internal globals from internal.h

include/polyscope/pick.h

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,39 @@
88
#include <utility>
99

1010
namespace polyscope {
11-
namespace pick {
1211

12+
// == Main query
1313

14-
// == Set up picking
15-
// Called by a structure to figure out what data it should render to the pick buffer.
16-
// Request 'count' contiguous indices for drawing a pick buffer. The return value is the start of the range.
17-
size_t requestPickBufferRange(Structure* requestingStructure, size_t count);
14+
// Pick queries test a screen location in the rendered viewport, and return a variety of info about what is underneath
15+
// the pixel at that point, including what structure is under the cursor, and the scene depth and color.
16+
//
17+
// This information can be fed into structure-specific functions like SurfaceMesh::interpretPick(PickQueryResult) to get
18+
// structure-specific info, like which vertex/face was clicked on.
19+
20+
// Return type for pick queries
21+
struct PickQueryResult {
22+
bool isHit;
23+
Structure* structure;
24+
std::string structureType;
25+
std::string structureName;
26+
glm::vec3 position;
27+
float depth;
28+
};
29+
30+
// Query functions to evaluate a pick.
31+
// Internally, these do a render pass to populate relevant information, then query the resulting buffers.
32+
PickQueryResult queryPickAtScreenCoords(glm::vec2 screenCoords); // takes screen coordinates
33+
PickQueryResult queryPickAtBufferCoords(int xPos, int yPos); // takes indices into render buffer
1834

35+
namespace pick {
1936

20-
// == Main query
37+
// Old, deprecated picking API. Use the above functions instead.
2138
// Get the structure which was clicked on (nullptr if none), and the pick ID in local indices for that structure (such
2239
// that 0 is the first index as returned from requestPickBufferRange())
2340
std::pair<Structure*, size_t> pickAtScreenCoords(glm::vec2 screenCoords); // takes screen coordinates
2441
std::pair<Structure*, size_t> pickAtBufferCoords(int xPos, int yPos); // takes indices into the buffer
2542
std::pair<Structure*, size_t> evaluatePickQuery(int xPos, int yPos); // old, badly named. takes buffer coordinates.
2643

27-
2844
// == Stateful picking: track and update a current selection
2945

3046
// Get/Set the "selected" item, if there is one (output has same meaning as evaluatePickQuery());
@@ -38,6 +54,11 @@ void resetSelectionIfStructure(Structure* s); // If something from this structur
3854

3955
// == Helpers
4056

57+
// Set up picking (internal)
58+
// Called by a structure to figure out what data it should render to the pick buffer.
59+
// Request 'count' contiguous indices for drawing a pick buffer. The return value is the start of the range.
60+
size_t requestPickBufferRange(Structure* requestingStructure, size_t count);
61+
4162
// Convert between global pick indexing for the whole program, and local per-structure pick indexing
4263
std::pair<Structure*, size_t> globalIndexToLocal(size_t globalInd);
4364
size_t localIndexToGlobal(std::pair<Structure*, size_t> localPick);

include/polyscope/polyscope.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ Structure* getStructure(std::string type, std::string name = "");
129129
// True if such a structure exists
130130
bool hasStructure(std::string type, std::string name = "");
131131

132+
// Look up the string type and name for a structure from its pointer
133+
// (performs a naive search over all structures for now, use sparingly)
134+
std::tuple<std::string, std::string> lookUpStructure(Structure* structure);
135+
132136
// De-register a structure, of any type. Also removes any quantities associated with the structure
133137
void removeStructure(Structure* structure, bool errorIfAbsent = false);
134138
void removeStructure(std::string type, std::string name, bool errorIfAbsent = false);

include/polyscope/render/engine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ class Engine {
584584
TransparencyMode getTransparencyMode();
585585
bool transparencyEnabled();
586586
virtual void applyTransparencySettings() = 0;
587-
void addSlicePlane(std::string uniquePostfix);
587+
void addSlicePlane(std::string uniquePostfix); // TODO move slice planes out of the engine
588588
void removeSlicePlane(std::string uniquePostfix);
589589
bool slicePlanesEnabled(); // true if there is at least one slice plane in the scene
590590
virtual void setFrontFaceCCW(bool newVal) = 0; // true if CCW triangles are considered front-facing; false otherwise

include/polyscope/view.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ bool getWindowResizable();
139139
glm::vec3 screenCoordsToWorldRay(glm::vec2 screenCoords);
140140
glm::vec3 bufferCoordsToWorldRay(int xPos, int yPos);
141141
glm::vec3 screenCoordsToWorldPosition(glm::vec2 screenCoords); // queries the depth buffer to get full position
142+
glm::vec3 bufferCoordsToWorldPosition(int xPos, int yPos);
142143

143144
// Get and set camera from json string
144145
std::string getViewAsJson();
@@ -150,6 +151,7 @@ void setCameraFromJson(std::string jsonData, bool flyTo);
150151
std::string to_string(ProjectionMode mode);
151152
std::string to_string(NavigateStyle style);
152153
std::tuple<int, int> screenCoordsToBufferInds(glm::vec2 screenCoords);
154+
glm::vec2 bufferIndsToScreenCoords(int xPos, int yPos);
153155

154156
// == Internal helpers. Should probably not be called in user code.
155157

src/pick.cpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,53 @@
99
#include <unordered_map>
1010

1111
namespace polyscope {
12+
13+
PickQueryResult queryPickAtScreenCoords(glm::vec2 screenCoords) {
14+
int xInd, yInd;
15+
std::tie(xInd, yInd) = view::screenCoordsToBufferInds(screenCoords);
16+
return queryPickAtBufferCoords(xInd, yInd);
17+
}
18+
PickQueryResult queryPickAtBufferCoords(int xPos, int yPos) {
19+
PickQueryResult result;
20+
21+
// Query the render buffer
22+
result.position = view::bufferCoordsToWorldPosition(xPos, yPos);
23+
result.depth = glm::length(result.position - view::getCameraWorldPosition());
24+
25+
// Query the pick buffer
26+
std::pair<Structure*, size_t> rawPickResult = pick::evaluatePickQuery(xPos, yPos);
27+
28+
// Transcribe result into return tuple
29+
result.structure = rawPickResult.first;
30+
if (rawPickResult.first == nullptr) {
31+
result.isHit = false;
32+
result.structureType = "";
33+
result.structureName = "";
34+
} else {
35+
result.isHit = true;
36+
std::tuple<std::string, std::string> lookupResult = lookUpStructure(rawPickResult.first);
37+
result.structureType = std::get<0>(lookupResult);
38+
result.structureName = std::get<1>(lookupResult);
39+
}
40+
41+
42+
43+
return result;
44+
}
45+
46+
1247
namespace pick {
1348

14-
size_t currLocalPickInd = 0;
15-
Structure* currPickStructure = nullptr;
16-
bool haveSelectionVal = false;
49+
size_t& currLocalPickInd = state::globalContext.currLocalPickInd;
50+
Structure*& currPickStructure = state::globalContext.currPickStructure;
51+
bool& haveSelectionVal = state::globalContext.haveSelectionVal;
1752

1853
// The next pick index that a structure can use to identify its elements
1954
// (get it by calling request pickBufferRange())
20-
size_t nextPickBufferInd = 1; // 0 reserved for "none"
21-
//
55+
size_t& nextPickBufferInd = state::globalContext.nextPickBufferInd; // 0 reserved for "none"
56+
2257
// Track which ranges have been allocated to which structures
23-
// std::vector<std::tuple<size_t, size_t, Structure*>> structureRanges;
24-
std::unordered_map<Structure*, std::tuple<size_t, size_t>> structureRanges;
58+
std::unordered_map<Structure*, std::tuple<size_t, size_t>> structureRanges = state::globalContext.structureRanges;
2559

2660

2761
// == Set up picking

src/polyscope.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,19 @@ bool hasStructure(std::string type, std::string name) {
10631063
return sMap.find(name) != sMap.end();
10641064
}
10651065

1066+
std::tuple<std::string, std::string> lookUpStructure(Structure* structure) {
1067+
1068+
for (auto& typeMap : state::structures) {
1069+
for (auto& entry : typeMap.second) {
1070+
if (entry.second.get() == structure) {
1071+
return std::tuple<std::string, std::string>(typeMap.first, entry.first);
1072+
}
1073+
}
1074+
}
1075+
1076+
// not found
1077+
return std::tuple<std::string, std::string>("", "");
1078+
}
10661079

10671080
void removeStructure(std::string type, std::string name, bool errorIfAbsent) {
10681081

src/view.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ std::tuple<int, int> screenCoordsToBufferInds(glm::vec2 screenCoords) {
102102
return std::tuple<int, int>(xPos, yPos);
103103
}
104104

105+
glm::vec2 bufferIndsToScreenCoords(int xPos, int yPos) {
106+
return glm::vec2{xPos * static_cast<float>(view::windowWidth) / view::bufferWidth,
107+
yPos * static_cast<float>(view::windowHeight) / view::bufferHeight};
108+
}
109+
105110
void processRotate(glm::vec2 startP, glm::vec2 endP) {
106111

107112
if (startP == endP) {
@@ -521,11 +526,15 @@ glm::vec3 bufferCoordsToWorldRay(glm::vec2 bufferCoords) {
521526
return worldRayDir;
522527
}
523528

524-
525529
glm::vec3 screenCoordsToWorldPosition(glm::vec2 screenCoords) {
526-
527530
int xInd, yInd;
528531
std::tie(xInd, yInd) = screenCoordsToBufferInds(screenCoords);
532+
return bufferCoordsToWorldPosition(xInd, yInd);
533+
}
534+
535+
glm::vec3 bufferCoordsToWorldPosition(int xInd, int yInd) {
536+
537+
glm::vec2 screenCoords = bufferIndsToScreenCoords(xInd, yInd);
529538

530539
glm::mat4 view = getCameraViewMatrix();
531540
glm::mat4 viewInv = glm::inverse(view);

0 commit comments

Comments
 (0)