Skip to content

Commit 9584cf3

Browse files
keenancraneGeometryCollectivenmwsharp
authored
contour line scalar shading, add more perceptual colormaps (#317)
* Add contour shader * Add darkness parameter to contour shader * Add grey and perceptually uniform colormaps * Add gray and perceptually uniform color maps * revert unintended changes * restore recently-added changes * unrelated small warning fix * re-restore new cmap names * missing shader register * merge contour lines to be a variant style for existing isolines option * rename isoline width to period * remove old note * add a few tests * change colormap order --------- Co-authored-by: keenancrane <[email protected]> Co-authored-by: Nicholas Sharp <[email protected]>
1 parent 9d5c3a4 commit 9584cf3

File tree

17 files changed

+208
-22
lines changed

17 files changed

+208
-22
lines changed

include/polyscope/persistent_value.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ extern PersistentCache<ParamVizStyle> persistentCache_paramVizStyle;
143143
extern PersistentCache<BackFacePolicy> persistentCache_BackFacePolicy;
144144
extern PersistentCache<MeshShadeStyle> persistentCache_MeshNormalType;
145145
extern PersistentCache<FilterMode> persistentCache_FilterMode;
146+
extern PersistentCache<IsolineStyle> persistentCache_IsolineStyle;
146147

147148
template<> inline PersistentCache<double>& getPersistentCacheRef<double>() { return persistentCache_double; }
148149
template<> inline PersistentCache<float>& getPersistentCacheRef<float>() { return persistentCache_float; }
@@ -157,6 +158,7 @@ template<> inline PersistentCache<ParamVizStyle>& getPersistentCacheR
157158
template<> inline PersistentCache<BackFacePolicy>& getPersistentCacheRef<BackFacePolicy>() { return persistentCache_BackFacePolicy; }
158159
template<> inline PersistentCache<MeshShadeStyle>& getPersistentCacheRef<MeshShadeStyle>() { return persistentCache_MeshNormalType; }
159160
template<> inline PersistentCache<FilterMode>& getPersistentCacheRef<FilterMode>() { return persistentCache_FilterMode; }
161+
template<> inline PersistentCache<IsolineStyle>& getPersistentCacheRef<IsolineStyle>() { return persistentCache_IsolineStyle; }
160162
}
161163
// clang-format on
162164

include/polyscope/render/color_maps.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@ bool buildColormapSelector(std::string& cm, std::string fieldname = "##colormap_
1818

1919

2020
// ColorMaps currently available below
21-
// Sequential:
21+
// Sequential & perceptually uniform:
2222
// - viridis (CM_VIRIDIS)
23+
// - magma (CM_MAGMA)
24+
// - inferno (CM_INFERNO)
25+
// - plasma (CM_PLASMA)
26+
// - gray (CM_GRAY)
27+
//
28+
// Sequential:
2329
// - blues (CM_BLUES)
2430
// - reds (CM_REDS)
2531
//
@@ -32,7 +38,6 @@ bool buildColormapSelector(std::string& cm, std::string fieldname = "##colormap_
3238
// - rainbow (CM_RAINBOW)
3339
// - jet (CM_JET)
3440
// - turbo (CM_TURBO)
35-
// - hsv (CM_HSV)
3641
//
3742
// Cyclic:
3843
// - phase (CM_PHASE)

include/polyscope/render/colormap_defs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ namespace render {
1111
// === the default colormaps themselves
1212
// (stored in color_maps.cpp)
1313

14+
extern const std::vector<glm::vec3> CM_GRAY;
1415
extern const std::vector<glm::vec3> CM_VIRIDIS;
16+
extern const std::vector<glm::vec3> CM_PLASMA;
17+
extern const std::vector<glm::vec3> CM_INFERNO;
18+
extern const std::vector<glm::vec3> CM_MAGMA;
1519
extern const std::vector<glm::vec3> CM_COOLWARM;
1620
extern const std::vector<glm::vec3> CM_BLUES;
1721
extern const std::vector<glm::vec3> CM_PIYG;

include/polyscope/render/opengl/shaders/rules.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern const ShaderReplacementRule SHADE_CHECKER_VALUE2; // generate a tw
2929
extern const ShaderReplacementRule SHADE_CHECKER_CATEGORY; // generate a checker with colors from a categorical int
3030
extern const ShaderReplacementRule SHADEVALUE_MAG_VALUE2; // generate a shadeValue from the magnitude of shadeValue2
3131
extern const ShaderReplacementRule ISOLINE_STRIPE_VALUECOLOR; // modulate albedoColor based on shadeValue
32+
extern const ShaderReplacementRule CONTOUR_VALUECOLOR; // modulate albedoColor based on shadeValue
3233
extern const ShaderReplacementRule CHECKER_VALUE2COLOR; // modulate albedoColor based on shadeValue2
3334
extern const ShaderReplacementRule SHADE_BASECOLOR; // constant from u_baseColor
3435
extern const ShaderReplacementRule PREMULTIPLY_COLOR;

include/polyscope/scalar_quantity.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,21 @@ class ScalarQuantity {
5353
std::pair<double, double> getDataRange();
5454

5555
// Isolines
56+
// NOTE there's a name typo, errant `s` in isolinesEnabled (leaving to avoid breaking change)
5657
QuantityT* setIsolinesEnabled(bool newEnabled);
5758
bool getIsolinesEnabled();
58-
QuantityT* setIsolineWidth(double size, bool isRelative);
59-
double getIsolineWidth();
59+
QuantityT* setIsolineStyle(IsolineStyle val);
60+
IsolineStyle getIsolineStyle();
61+
QuantityT* setIsolinePeriod(double size, bool isRelative);
62+
double getIsolinePeriod();
6063
QuantityT* setIsolineDarkness(double val);
6164
double getIsolineDarkness();
65+
QuantityT* setIsolineContourThickness(double val);
66+
double getIsolineContourThickness();
67+
68+
// Old / depracted methods kept for compatability
69+
QuantityT* setIsolineWidth(double size, bool isRelative);
70+
double getIsolineWidth();
6271

6372
protected:
6473
std::vector<float> valuesData;
@@ -75,8 +84,10 @@ class ScalarQuantity {
7584
// Parameters
7685
PersistentValue<std::string> cMap;
7786
PersistentValue<bool> isolinesEnabled;
78-
PersistentValue<ScaledValue<float>> isolineWidth;
87+
PersistentValue<IsolineStyle> isolineStyle;
88+
PersistentValue<ScaledValue<float>> isolinePeriod;
7989
PersistentValue<float> isolineDarkness;
90+
PersistentValue<float> isolineContourThickness;
8091
};
8192

8293
} // namespace polyscope

include/polyscope/scalar_quantity.ipp

Lines changed: 107 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ ScalarQuantity<QuantityT>::ScalarQuantity(QuantityT& quantity_, const std::vecto
1414
vizRangeMax(quantity.uniquePrefix() + "vizRangeMax", -777.), // including clearing cache
1515
cMap(quantity.uniquePrefix() + "cmap", defaultColorMap(dataType)),
1616
isolinesEnabled(quantity.uniquePrefix() + "isolinesEnabled", false),
17-
isolineWidth(quantity.uniquePrefix() + "isolineWidth",
18-
absoluteValue((dataRange.second - dataRange.first) * 0.02)),
19-
isolineDarkness(quantity.uniquePrefix() + "isolineDarkness", 0.7)
17+
isolineStyle(quantity.uniquePrefix() + "isolinesStyle", IsolineStyle::Stripe),
18+
isolinePeriod(quantity.uniquePrefix() + "isolinePeriod",
19+
absoluteValue((dataRange.second - dataRange.first) * 0.02)),
20+
isolineDarkness(quantity.uniquePrefix() + "isolineDarkness", 0.7),
21+
isolineContourThickness(quantity.uniquePrefix() + "isolineContourThickness", 0.3)
2022

2123
{
2224
values.checkInvalidValues();
@@ -144,22 +146,46 @@ void ScalarQuantity<QuantityT>::buildScalarUI() {
144146

145147
// Isolines
146148
if (isolinesEnabled.get()) {
149+
147150
ImGui::PushItemWidth(100);
148151

152+
153+
auto styleName = [](const IsolineStyle& m) -> std::string {
154+
switch (m) {
155+
case IsolineStyle::Stripe:
156+
return "Stripe";
157+
case IsolineStyle::Contour:
158+
return "Contour";
159+
}
160+
return "";
161+
};
162+
163+
ImGui::TextUnformatted("Isoline style");
164+
ImGui::SameLine();
165+
if (ImGui::BeginCombo("##IsolineStyle", styleName(getIsolineStyle()).c_str())) {
166+
for (IsolineStyle s : {IsolineStyle::Stripe, IsolineStyle::Contour}) {
167+
std::string sName = styleName(s);
168+
if (ImGui::Selectable(sName.c_str(), getIsolineStyle() == s)) {
169+
setIsolineStyle(s);
170+
}
171+
}
172+
ImGui::EndCombo();
173+
}
174+
149175
// Isoline width
150-
ImGui::TextUnformatted("Isoline width");
176+
ImGui::TextUnformatted("Isoline period");
151177
ImGui::SameLine();
152-
if (isolineWidth.get().isRelative()) {
153-
if (ImGui::DragFloat("##Isoline width relative", isolineWidth.get().getValuePtr(), .001, 0.0001, 1.0, "%.4f",
178+
if (isolinePeriod.get().isRelative()) {
179+
if (ImGui::DragFloat("##Isoline period relative", isolinePeriod.get().getValuePtr(), .001, 0.0001, 1.0, "%.4f",
154180
ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat)) {
155-
isolineWidth.manuallyChanged();
181+
isolinePeriod.manuallyChanged();
156182
requestRedraw();
157183
}
158184
} else {
159185
float scaleWidth = dataRange.second - dataRange.first;
160-
if (ImGui::DragFloat("##Isoline width absolute", isolineWidth.get().getValuePtr(), scaleWidth / 1000, 0.,
186+
if (ImGui::DragFloat("##Isoline period absolute", isolinePeriod.get().getValuePtr(), scaleWidth / 1000, 0.,
161187
scaleWidth, "%.4f", ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat)) {
162-
isolineWidth.manuallyChanged();
188+
isolinePeriod.manuallyChanged();
163189
requestRedraw();
164190
}
165191
}
@@ -172,6 +198,18 @@ void ScalarQuantity<QuantityT>::buildScalarUI() {
172198
requestRedraw();
173199
}
174200

201+
202+
// Isoline Contour Thickness
203+
if (isolineStyle.get() == IsolineStyle::Contour) {
204+
ImGui::TextUnformatted("Contour thickness");
205+
ImGui::SameLine();
206+
if (ImGui::DragFloat("##Contour thickness", &isolineContourThickness.get(), .001, 0.0001, 1.0, "%.4f",
207+
ImGuiSliderFlags_Logarithmic | ImGuiSliderFlags_NoRoundToFormat)) {
208+
isolineContourThickness.manuallyChanged();
209+
requestRedraw();
210+
}
211+
}
212+
175213
ImGui::PopItemWidth();
176214
}
177215
}
@@ -192,9 +230,18 @@ std::vector<std::string> ScalarQuantity<QuantityT>::addScalarRules(std::vector<s
192230
// common case
193231
rules.push_back("SHADE_COLORMAP_VALUE");
194232
}
233+
195234
if (isolinesEnabled.get()) {
196-
rules.push_back("ISOLINE_STRIPE_VALUECOLOR");
235+
switch (isolineStyle.get()) {
236+
case IsolineStyle::Stripe:
237+
rules.push_back("ISOLINE_STRIPE_VALUECOLOR");
238+
break;
239+
case IsolineStyle::Contour:
240+
rules.push_back("CONTOUR_VALUECOLOR");
241+
break;
242+
}
197243
}
244+
198245
return rules;
199246
}
200247

@@ -207,8 +254,17 @@ void ScalarQuantity<QuantityT>::setScalarUniforms(render::ShaderProgram& p) {
207254
}
208255

209256
if (isolinesEnabled.get()) {
210-
p.setUniform("u_modLen", getIsolineWidth());
211-
p.setUniform("u_modDarkness", getIsolineDarkness());
257+
switch (isolineStyle.get()) {
258+
case IsolineStyle::Stripe:
259+
p.setUniform("u_modLen", getIsolinePeriod());
260+
p.setUniform("u_modDarkness", getIsolineDarkness());
261+
break;
262+
case IsolineStyle::Contour:
263+
p.setUniform("u_modLen", getIsolinePeriod());
264+
p.setUniform("u_modThickness", getIsolineContourThickness());
265+
p.setUniform("u_modDarkness", getIsolineDarkness());
266+
break;
267+
}
212268
}
213269
}
214270

@@ -277,17 +333,26 @@ std::pair<double, double> ScalarQuantity<QuantityT>::getDataRange() {
277333
}
278334

279335
template <typename QuantityT>
280-
QuantityT* ScalarQuantity<QuantityT>::setIsolineWidth(double size, bool isRelative) {
281-
isolineWidth = ScaledValue<float>(size, isRelative);
336+
QuantityT* ScalarQuantity<QuantityT>::setIsolinePeriod(double size, bool isRelative) {
337+
isolinePeriod = ScaledValue<float>(size, isRelative);
282338
if (!isolinesEnabled.get()) {
283339
setIsolinesEnabled(true);
284340
}
285341
requestRedraw();
286342
return &quantity;
287343
}
288344
template <typename QuantityT>
345+
double ScalarQuantity<QuantityT>::getIsolinePeriod() {
346+
return isolinePeriod.get().asAbsolute();
347+
}
348+
349+
template <typename QuantityT>
350+
QuantityT* ScalarQuantity<QuantityT>::setIsolineWidth(double size, bool isRelative) {
351+
return setIsolinePeriod(size, isRelative);
352+
}
353+
template <typename QuantityT>
289354
double ScalarQuantity<QuantityT>::getIsolineWidth() {
290-
return isolineWidth.get().asAbsolute();
355+
return getIsolinePeriod();
291356
}
292357

293358
template <typename QuantityT>
@@ -319,4 +384,31 @@ bool ScalarQuantity<QuantityT>::getIsolinesEnabled() {
319384
return isolinesEnabled.get();
320385
}
321386

387+
template <typename QuantityT>
388+
QuantityT* ScalarQuantity<QuantityT>::setIsolineStyle(IsolineStyle val) {
389+
isolineStyle = val;
390+
quantity.refresh();
391+
requestRedraw();
392+
return &quantity;
393+
}
394+
template <typename QuantityT>
395+
IsolineStyle ScalarQuantity<QuantityT>::getIsolineStyle() {
396+
return isolineStyle.get();
397+
}
398+
399+
400+
template <typename QuantityT>
401+
QuantityT* ScalarQuantity<QuantityT>::setIsolineContourThickness(double val) {
402+
isolineContourThickness = val;
403+
if (!isolinesEnabled.get()) {
404+
setIsolinesEnabled(true);
405+
}
406+
requestRedraw();
407+
return &quantity;
408+
}
409+
template <typename QuantityT>
410+
double ScalarQuantity<QuantityT>::getIsolineContourThickness() {
411+
return isolineContourThickness.get();
412+
}
413+
322414
} // namespace polyscope

include/polyscope/types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ enum class MeshElement { VERTEX = 0, FACE, EDGE, HALFEDGE, CORNER };
2121
enum class MeshShadeStyle { Smooth = 0, Flat, TriFlat };
2222
enum class VolumeMeshElement { VERTEX = 0, EDGE, FACE, CELL };
2323
enum class VolumeCellType { TET = 0, HEX };
24+
enum class IsolineStyle { Stripe = 0, Contour };
2425

2526
enum class ImplicitRenderMode { SphereMarch, FixedStep };
2627
enum class ImageOrigin { LowerLeft, UpperLeft };

src/persistent_value.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ PersistentCache<ParamVizStyle> persistentCache_paramVizStyle;
2121
PersistentCache<BackFacePolicy> persistentCache_BackFacePolicy;
2222
PersistentCache<MeshShadeStyle> persistentCache_MeshNormalType;
2323
PersistentCache<FilterMode> persistentCache_FilterMode;
24+
PersistentCache<IsolineStyle> persistentCache_IsolineStyle;
2425
// clang-format on
2526
} // namespace detail
2627
} // namespace polyscope

src/render/color_maps.cpp

Lines changed: 12 additions & 0 deletions
Large diffs are not rendered by default.

src/render/engine.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,14 @@ void Engine::loadDefaultColorMap(std::string name) {
11101110
const std::vector<glm::vec3>* buff = nullptr;
11111111
if (name == "viridis") {
11121112
buff = &CM_VIRIDIS;
1113+
} else if (name == "magma") {
1114+
buff = &CM_MAGMA;
1115+
} else if (name == "inferno") {
1116+
buff = &CM_INFERNO;
1117+
} else if (name == "plasma") {
1118+
buff = &CM_PLASMA;
1119+
} else if (name == "gray") {
1120+
buff = &CM_GRAY;
11131121
} else if (name == "coolwarm") {
11141122
buff = &CM_COOLWARM;
11151123
} else if (name == "blues") {
@@ -1142,6 +1150,10 @@ void Engine::loadDefaultColorMap(std::string name) {
11421150

11431151
void Engine::loadDefaultColorMaps() {
11441152
loadDefaultColorMap("viridis");
1153+
loadDefaultColorMap("plasma");
1154+
loadDefaultColorMap("inferno");
1155+
loadDefaultColorMap("magma");
1156+
loadDefaultColorMap("gray");
11451157
loadDefaultColorMap("coolwarm");
11461158
loadDefaultColorMap("blues");
11471159
loadDefaultColorMap("reds");

0 commit comments

Comments
 (0)