Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add UV seam & island visualizations #244

Merged
merged 6 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/polyscope/camera_parameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class CameraIntrinsics {
static CameraIntrinsics fromFoVDegVerticalAndAspect(const float& fovVertDeg, const float& aspectRatioWidthOverHeight);
static CameraIntrinsics fromFoVDegHorizontalAndAspect(const float& fovHorzDeg,
const float& aspectRatioWidthOverHeight);
static CameraIntrinsics fromFoVDegHorizontalAndVertical(const float& fovHorzDeg, const float& forV);
static CameraIntrinsics fromFoVDegHorizontalAndVertical(const float& fovHorzDeg, const float& fovVertDeg);

// create/test 'invalid' params
static CameraIntrinsics createInvalid();
Expand Down
8 changes: 7 additions & 1 deletion include/polyscope/parameterization_quantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ class ParameterizationQuantity {
QuantityT& quantity;


// Wrapper around the actual buffer of scalar data stored in the class.
// Wrapper around the actual buffers of data stored in the class.
// Interaction with the data (updating it on CPU or GPU side, accessing it, etc) happens through this wrapper.
render::ManagedBuffer<glm::vec2> coords;
render::ManagedBuffer<float> islandLabels; // only optionally populated. should be integers.

const ParamCoordsType coordsType;

Expand Down Expand Up @@ -71,6 +72,8 @@ class ParameterizationQuantity {
protected:
// Raw storage for the data. You should only interact with this via the managed buffer above
std::vector<glm::vec2> coordsData;
std::vector<float> islandLabelsData;
bool islandLabelsPopulated = false;

// === Visualization parameters

Expand All @@ -82,6 +85,9 @@ class ParameterizationQuantity {
PersistentValue<float> altDarkness;
PersistentValue<std::string> cMap;
float localRot = 0.; // for LOCAL (angular shift, in radians)

// helpers
bool haveIslandLabels();
};

} // namespace polyscope
Expand Down
53 changes: 49 additions & 4 deletions include/polyscope/parameterization_quantity.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ std::string styleName(ParamVizStyle v) {
case ParamVizStyle::CHECKER:
return "checker";
break;
case ParamVizStyle::CHECKER_ISLANDS:
return "checker islands";
break;
case ParamVizStyle::GRID:
return "grid";
break;
Expand All @@ -34,8 +37,15 @@ template <typename QuantityT>
ParameterizationQuantity<QuantityT>::ParameterizationQuantity(QuantityT& quantity_,
const std::vector<glm::vec2>& coords_,
ParamCoordsType type_, ParamVizStyle style_)
: quantity(quantity_), coords(&quantity, quantity.uniquePrefix() + "#coords", coordsData), coordsType(type_),
coordsData(coords_), checkerSize(quantity.uniquePrefix() + "#checkerSize", 0.02),
: quantity(quantity_),

// buffers
coords(&quantity, quantity.uniquePrefix() + "#coords", coordsData),
islandLabels(&quantity, quantity.uniquePrefix() + "#islandLabels", islandLabelsData), coordsType(type_),
coordsData(coords_),

// options
checkerSize(quantity.uniquePrefix() + "#checkerSize", 0.02),
vizStyle(quantity.uniquePrefix() + "#vizStyle", style_),
checkColor1(quantity.uniquePrefix() + "#checkColor1", render::RGB_PINK),
checkColor2(quantity.uniquePrefix() + "#checkColor2", glm::vec3(.976, .856, .885)),
Expand Down Expand Up @@ -70,6 +80,17 @@ void ParameterizationQuantity<QuantityT>::buildParameterizationUI() {
if (ImGui::ColorEdit3("##colors", &checkColor2.get()[0], ImGuiColorEditFlags_NoInputs))
setCheckerColors(getCheckerColors());
break;
case ParamVizStyle::CHECKER_ISLANDS:
ImGui::PushItemWidth(100);
if (ImGui::DragFloat("alt darkness", &altDarkness.get(), 0.01, 0., 1.)) {
altDarkness.manuallyChanged();
requestRedraw();
}
ImGui::PopItemWidth();
if (render::buildColormapSelector(cMap.get())) {
setColorMap(getColorMap());
}
break;
case ParamVizStyle::GRID:
ImGui::SameLine();
if (ImGui::ColorEdit3("##base", &gridBackgroundColor.get()[0], ImGuiColorEditFlags_NoInputs))
Expand Down Expand Up @@ -105,8 +126,13 @@ void ParameterizationQuantity<QuantityT>::buildParameterizationOptionsUI() {

// Choose viz style
if (ImGui::BeginMenu("Style")) {
for (ParamVizStyle s :
{ParamVizStyle::CHECKER, ParamVizStyle::GRID, ParamVizStyle::LOCAL_CHECK, ParamVizStyle::LOCAL_RAD}) {
for (ParamVizStyle s : {ParamVizStyle::CHECKER_ISLANDS, ParamVizStyle::CHECKER, ParamVizStyle::GRID,
ParamVizStyle::LOCAL_CHECK, ParamVizStyle::LOCAL_RAD}) {

if (s == ParamVizStyle::CHECKER_ISLANDS && !haveIslandLabels()) {
// only allow CHECKER_ISLANDS if we actually have island labels
continue;
}

bool selected = s == getStyle();
std::string fancyName = styleName(s);
Expand All @@ -125,6 +151,9 @@ std::vector<std::string> ParameterizationQuantity<QuantityT>::addParameterizatio
case ParamVizStyle::CHECKER:
rules.insert(rules.end(), {"SHADE_CHECKER_VALUE2"});
break;
case ParamVizStyle::CHECKER_ISLANDS:
rules.insert(rules.end(), {"SHADE_CHECKER_CATEGORY"});
break;
case ParamVizStyle::GRID:
rules.insert(rules.end(), {"SHADE_GRID_VALUE2"});
break;
Expand All @@ -144,6 +173,9 @@ void ParameterizationQuantity<QuantityT>::fillParameterizationBuffers(render::Sh
switch (getStyle()) {
case ParamVizStyle::CHECKER:
break;
case ParamVizStyle::CHECKER_ISLANDS:
p.setTextureFromColormap("t_colormap", cMap.get());
break;
case ParamVizStyle::GRID:
break;
case ParamVizStyle::LOCAL_CHECK:
Expand Down Expand Up @@ -175,6 +207,9 @@ void ParameterizationQuantity<QuantityT>::setParameterizationUniforms(render::Sh
p.setUniform("u_color1", getCheckerColors().first);
p.setUniform("u_color2", getCheckerColors().second);
break;
case ParamVizStyle::CHECKER_ISLANDS:
p.setUniform("u_modDarkness", getAltDarkness());
break;
case ParamVizStyle::GRID:
p.setUniform("u_gridLineColor", getGridColors().first);
p.setUniform("u_gridBackgroundColor", getGridColors().second);
Expand All @@ -195,9 +230,19 @@ void ParameterizationQuantity<QuantityT>::updateCoords(const V& newCoords) {
coords.markHostBufferUpdated();
}

template <typename QuantityT>
bool ParameterizationQuantity<QuantityT>::haveIslandLabels() {
return islandLabelsPopulated;
}

template <typename QuantityT>
QuantityT* ParameterizationQuantity<QuantityT>::setStyle(ParamVizStyle newStyle) {

if (newStyle == ParamVizStyle::CHECKER_ISLANDS && !haveIslandLabels()) {
exception("Cannot set parameterization visualization style to 'CHECKER_ISLANDS', no islands have been set");
newStyle = ParamVizStyle::CHECKER;
}

vizStyle = newStyle;
quantity.refresh();
requestRedraw();
Expand Down
1 change: 1 addition & 0 deletions include/polyscope/render/opengl/shaders/rules.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ extern const ShaderReplacementRule SHADE_COLORMAP_VALUE; // colormapped f
extern const ShaderReplacementRule SHADE_COLORMAP_ANGULAR2; // colormapped from angle of shadeValue2
extern const ShaderReplacementRule SHADE_GRID_VALUE2; // generate a two-color grid with lines from shadeValue2
extern const ShaderReplacementRule SHADE_CHECKER_VALUE2; // generate a two-color checker from shadeValue2
extern const ShaderReplacementRule SHADE_CHECKER_CATEGORY; // generate a checker with colors from a categorical int
extern const ShaderReplacementRule SHADEVALUE_MAG_VALUE2; // generate a shadeValue from the magnitude of shadeValue2
extern const ShaderReplacementRule ISOLINE_STRIPE_VALUECOLOR; // modulate albedoColor based on shadeValue
extern const ShaderReplacementRule CHECKER_VALUE2COLOR; // modulate albedoColor based on shadeValue2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ extern const ShaderReplacementRule MESH_BACKFACE_NORMAL_FLIP;
extern const ShaderReplacementRule MESH_BACKFACE_DIFFERENT;
extern const ShaderReplacementRule MESH_BACKFACE_DARKEN;
extern const ShaderReplacementRule MESH_PROPAGATE_VALUE;
extern const ShaderReplacementRule MESH_PROPAGATE_FLAT_VALUE;
extern const ShaderReplacementRule MESH_PROPAGATE_INT;
extern const ShaderReplacementRule MESH_PROPAGATE_VALUE2;
extern const ShaderReplacementRule MESH_PROPAGATE_TCOORD;
extern const ShaderReplacementRule MESH_PROPAGATE_COLOR;
Expand Down
21 changes: 21 additions & 0 deletions include/polyscope/surface_parameterization_quantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

namespace polyscope {

// forward declarations
class CurveNetwork;

// ==============================================================
// ================ Base Parameterization =====================
Expand All @@ -29,12 +31,20 @@ class SurfaceParameterizationQuantity : public SurfaceMeshQuantity,
virtual void refresh() override;
virtual void buildCustomUI() override;

// Set islands labels. Technically, this data is just any categorical integer labels per-face of the mesh.
// The intended use is to label islands (connected components in parameterization space) of the UV map.
// When style == CHECKER_ISLANDS, these will be use to visualize the islands with different colors.
template <typename V>
void setIslandLabels(const V& newIslandLabels);

CurveNetwork* createCurveNetworkFromSeams(std::string structureName = "");

protected:
std::shared_ptr<render::ShaderProgram> program;

// Helpers
void createProgram();
size_t nFaces(); // works around an incomplete def of the parent mesh
virtual void fillCoordBuffers(render::ShaderProgram& p) = 0;
};

Expand Down Expand Up @@ -74,4 +84,15 @@ class SurfaceVertexParameterizationQuantity : public SurfaceParameterizationQuan
virtual void fillCoordBuffers(render::ShaderProgram& p) override;
};


// == template implementations

template <typename V>
void SurfaceParameterizationQuantity::setIslandLabels(const V& newIslandLabels) {
validateSize(newIslandLabels, this->nFaces(), "scalar quantity " + quantity.name);
islandLabels.data = standardizeArray<float, V>(newIslandLabels);
islandLabels.markHostBufferUpdated();
islandLabelsPopulated = true;
}

} // namespace polyscope
10 changes: 8 additions & 2 deletions include/polyscope/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ enum class VolumeCellType { TET = 0, HEX };
enum class ImplicitRenderMode { SphereMarch, FixedStep };
enum class ImageOrigin { LowerLeft, UpperLeft };

enum class ParamCoordsType { UNIT = 0, WORLD }; // UNIT -> [0,1], WORLD -> length-valued
enum class ParamVizStyle { CHECKER = 0, GRID, LOCAL_CHECK, LOCAL_RAD }; // TODO add "UV" with test UV map
enum class ParamCoordsType { UNIT = 0, WORLD }; // UNIT -> [0,1], WORLD -> length-valued
enum class ParamVizStyle {
CHECKER = 0,
GRID,
LOCAL_CHECK,
LOCAL_RAD,
CHECKER_ISLANDS
}; // TODO add "UV" with test UV map

enum class ManagedBufferType {
Float,
Expand Down
2 changes: 2 additions & 0 deletions src/color_management.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ glm::vec3 unitClamp(glm::vec3 x) { return {unitClamp(x[0]), unitClamp(x[1]), uni
// Used to sample colors. Samples a series of most-distant values from a range [0,1]
// offset from a starting value 'start' and wrapped around. index=0 returns start
//
// (We also use this logic via a duplicate implementation in some shaders)
//
// Example: if start = 0, emits f(0, i) = {0, 1/2, 1/4, 3/4, 1/8, 5/8, 3/8, 7/8, ...}
// if start = 0.3 emits (0.3 + f(0, i)) % 1
float getIndexedDistinctValue(float start, int index) {
Expand Down
2 changes: 1 addition & 1 deletion src/render/managed_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ template<> ManagedBufferMap<glm::uvec4>& ManagedBufferMap<glm::uve

std::string typeName(ManagedBufferType type) {
switch (type) {
// clang-format off
// clang-format off
case ManagedBufferType::Float : return "Float";
case ManagedBufferType::Double : return "Double";
case ManagedBufferType::Vec2 : return "Vec2";
Expand Down
2 changes: 2 additions & 0 deletions src/render/mock_opengl/mock_gl_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1953,6 +1953,7 @@ void MockGLEngine::populateDefaultShadersAndRules() {
registerShaderRule("SHADE_COLORMAP_ANGULAR2", SHADE_COLORMAP_ANGULAR2);
registerShaderRule("SHADE_GRID_VALUE2", SHADE_GRID_VALUE2);
registerShaderRule("SHADE_CHECKER_VALUE2", SHADE_CHECKER_VALUE2);
registerShaderRule("SHADE_CHECKER_CATEGORY", SHADE_CHECKER_CATEGORY);
registerShaderRule("SHADEVALUE_MAG_VALUE2", SHADEVALUE_MAG_VALUE2);
registerShaderRule("ISOLINE_STRIPE_VALUECOLOR", ISOLINE_STRIPE_VALUECOLOR);
registerShaderRule("CHECKER_VALUE2COLOR", CHECKER_VALUE2COLOR);
Expand Down Expand Up @@ -1980,6 +1981,7 @@ void MockGLEngine::populateDefaultShadersAndRules() {
registerShaderRule("MESH_BACKFACE_DIFFERENT", MESH_BACKFACE_DIFFERENT);
registerShaderRule("MESH_BACKFACE_DARKEN", MESH_BACKFACE_DARKEN);
registerShaderRule("MESH_PROPAGATE_VALUE", MESH_PROPAGATE_VALUE);
registerShaderRule("MESH_PROPAGATE_FLAT_VALUE", MESH_PROPAGATE_FLAT_VALUE);
registerShaderRule("MESH_PROPAGATE_VALUE2", MESH_PROPAGATE_VALUE2);
registerShaderRule("MESH_PROPAGATE_TCOORD", MESH_PROPAGATE_TCOORD);
registerShaderRule("MESH_PROPAGATE_COLOR", MESH_PROPAGATE_COLOR);
Expand Down
2 changes: 2 additions & 0 deletions src/render/opengl/gl_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,7 @@ void GLEngine::populateDefaultShadersAndRules() {
registerShaderRule("SHADE_COLORMAP_ANGULAR2", SHADE_COLORMAP_ANGULAR2);
registerShaderRule("SHADE_GRID_VALUE2", SHADE_GRID_VALUE2);
registerShaderRule("SHADE_CHECKER_VALUE2", SHADE_CHECKER_VALUE2);
registerShaderRule("SHADE_CHECKER_CATEGORY", SHADE_CHECKER_CATEGORY);
registerShaderRule("SHADEVALUE_MAG_VALUE2", SHADEVALUE_MAG_VALUE2);
registerShaderRule("ISOLINE_STRIPE_VALUECOLOR", ISOLINE_STRIPE_VALUECOLOR);
registerShaderRule("CHECKER_VALUE2COLOR", CHECKER_VALUE2COLOR);
Expand Down Expand Up @@ -2748,6 +2749,7 @@ void GLEngine::populateDefaultShadersAndRules() {
registerShaderRule("MESH_BACKFACE_DIFFERENT", MESH_BACKFACE_DIFFERENT);
registerShaderRule("MESH_BACKFACE_DARKEN", MESH_BACKFACE_DARKEN);
registerShaderRule("MESH_PROPAGATE_VALUE", MESH_PROPAGATE_VALUE);
registerShaderRule("MESH_PROPAGATE_FLAT_VALUE", MESH_PROPAGATE_FLAT_VALUE);
registerShaderRule("MESH_PROPAGATE_VALUE2", MESH_PROPAGATE_VALUE2);
registerShaderRule("MESH_PROPAGATE_TCOORD", MESH_PROPAGATE_TCOORD);
registerShaderRule("MESH_PROPAGATE_COLOR", MESH_PROPAGATE_COLOR);
Expand Down
30 changes: 30 additions & 0 deletions src/render/opengl/shaders/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,36 @@ vec2 sphericalTexCoords(vec3 v) {
return uv;
}

// Used to sample colors. Samples a series of most-distant values from a range [0,1]
// offset from a starting value 'start' and wrapped around. index=0 returns start.
// We only actually output distinct floats for the first 10 bits, then the pattern repeats.
//
// (same logic appears in color_management.cpp)
//
// Example: if start = 0, emits f(0, i) = {0, 1/2, 1/4, 3/4, 1/8, 5/8, 3/8, 7/8, ...}
float intToDistinctReal(float start, int index) {
const int NBitsUntilRepeat = 10;

if (index < 0) {
return 0.0f;
}

// Bit shifts to evaluate f()
float val = 0.f;
float p = 0.5f;
for(int iShift = 0; iShift < NBitsUntilRepeat; iShift++) { // unroll please
val += float((index % 2) == 1) * p;
index = index >> 1;
p /= 2.0;
}

// Apply modular offset
val = mod(val + start, 1.0);

return clamp(val, 0.f, 1.f);
}


// Two useful references:
// - https://stackoverflow.com/questions/38938498/how-do-i-convert-gl-fragcoord-to-a-world-space-point-in-a-fragment-shader
// - https://stackoverflow.com/questions/11277501/how-to-recover-view-space-position-given-view-space-depth-value-and-ndc-xy
Expand Down
41 changes: 41 additions & 0 deletions src/render/opengl/shaders/rules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ const ShaderReplacementRule SHADE_CHECKER_VALUE2 (
uniform vec3 u_color2;
)"},
{"GENERATE_SHADE_COLOR", R"(
// NOTE checker math shared with other shaders
float mX = mod(shadeValue2.x, 2.0 * u_modLen) / u_modLen - 1.f; // in [-1, 1]
float mY = mod(shadeValue2.y, 2.0 * u_modLen) / u_modLen - 1.f;
float minD = min( min(abs(mX), 1.0 - abs(mX)), min(abs(mY), 1.0 - abs(mY))) * 2.; // rect distace from flipping sign in [0,1]
Expand All @@ -224,6 +225,46 @@ const ShaderReplacementRule SHADE_CHECKER_VALUE2 (
/* textures */ {}
);

const ShaderReplacementRule SHADE_CHECKER_CATEGORY(
/* rule name */ "SHADE_CHECKER_CATEGORY",
{ /* replacement sources */
{"FRAG_DECLARATIONS", R"(
uniform float u_modLen;
uniform float u_modDarkness;
uniform sampler1D t_colormap;

float intToDistinctReal(float start, int index);
)"},
{"GENERATE_SHADE_COLOR", R"(
// sample the categorical color
float catVal = intToDistinctReal(0., int(shadeValue));
float scaleFac = 1.2f; // pump up the brightness a bit, so the modDarkness doesn't make it too dark
vec3 catColor = scaleFac * texture(t_colormap, catVal).rgb;
vec3 catColorDark = catColor * u_modDarkness;

// NOTE checker math shared with other shaders
float mX = mod(shadeValue2.x, 2.0 * u_modLen) / u_modLen - 1.f; // in [-1, 1]
float mY = mod(shadeValue2.y, 2.0 * u_modLen) / u_modLen - 1.f;
float minD = min( min(abs(mX), 1.0 - abs(mX)), min(abs(mY), 1.0 - abs(mY))) * 2.; // rect distace from flipping sign in [0,1]
float p = 6;
float minDSmooth = pow(minD, 1. / p);
// TODO do some clever screen space derivative thing to prevent aliasing
float v = (mX * mY); // in [-1, 1], color switches at 0
float adjV = sign(v) * minDSmooth;
float s = smoothstep(-1.f, 1.f, adjV);
vec3 albedoColor = mix(catColor, catColorDark, s);
)"}
},
/* uniforms */ {
{"u_modLen", RenderDataType::Float},
{"u_modDarkness", RenderDataType::Float},
},
/* attributes */ {},
/* textures */ {
{"t_colormap", 1}
}
);

// input vec2 shadeValue2
// output: float shadeValue
const ShaderReplacementRule SHADEVALUE_MAG_VALUE2(
Expand Down
Loading