Updated glViewer and glFVarViewer for Loop patches

- Removed Catmark restrictions in the application code and shaders
- Added command line options to specifiy the Scheme for .obj input files
- Added support for Linear end-cap approximation
- Updated GUI labels for end-cap types, i.e. "Linear" instead of "Bilinear"
  and "Regular" instead of "BSpline".
- Added new shading color to glViewer for "Patch Depth"
- Disabled screen-space and fractional tessellation by default
This commit is contained in:
David G Yu 2019-01-18 18:20:21 -08:00
parent 83486cddae
commit 06f4a60939
3 changed files with 164 additions and 59 deletions

View File

@ -63,7 +63,8 @@ enum DisplayStyle { kWire = 0,
kShaded,
kWireShaded };
enum EndCap { kEndCapBSplineBasis,
enum EndCap { kEndCapBilinearBasis,
kEndCapBSplineBasis,
kEndCapGregoryBasis };
int g_currentShape = 0;
@ -109,7 +110,7 @@ std::vector<float> g_orgPositions,
Scheme g_scheme;
int g_endCap = kEndCapBSplineBasis;
int g_endCap = kEndCapGregoryBasis;
int g_level = 2;
int g_tessLevel = 1;
int g_tessLevelMin = 1;
@ -435,13 +436,11 @@ rebuildMesh() {
g_scheme = scheme;
// Adaptive refinement currently supported only for catmull-clark scheme
bool doAdaptive = (g_adaptive!=0 && g_scheme==kCatmark);
OpenSubdiv::Osd::MeshBitset bits;
bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
bits.set(OpenSubdiv::Osd::MeshAdaptive, g_adaptive != 0);
bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
bits.set(OpenSubdiv::Osd::MeshFVarAdaptive, 1);
bits.set(OpenSubdiv::Osd::MeshEndCapBilinearBasis, g_endCap == kEndCapBilinearBasis);
bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, g_endCap == kEndCapBSplineBasis);
bits.set(OpenSubdiv::Osd::MeshEndCapGregoryBasis, g_endCap == kEndCapGregoryBasis);
@ -580,7 +579,9 @@ public:
if (type == Far::PatchDescriptor::QUADS) {
ss << "#define PRIM_QUAD\n";
} else if (type == Far::PatchDescriptor::TRIANGLES) {
} else if (type == Far::PatchDescriptor::TRIANGLES ||
type == Far::PatchDescriptor::LOOP ||
type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define PRIM_TRI\n";
ss << "#define LOOP\n";
} else {
@ -1133,7 +1134,10 @@ initHUD() {
int endcap_pulldown = g_hud.AddPullDown("End cap (E)", 10, 140, 200,
callbackEndCap, 'e');
g_hud.AddPullDownButton(endcap_pulldown, "BSpline",
g_hud.AddPullDownButton(endcap_pulldown, "Linear",
kEndCapBilinearBasis,
g_endCap == kEndCapBilinearBasis);
g_hud.AddPullDownButton(endcap_pulldown, "Regular",
kEndCapBSplineBasis,
g_endCap == kEndCapBSplineBasis);
g_hud.AddPullDownButton(endcap_pulldown, "GregoryBasis",
@ -1228,7 +1232,9 @@ parseIntArg(const char* argString, int dfltValue = 0) {
int main(int argc, char ** argv) {
bool fullscreen = false;
Scheme defaultScheme = kCatmark;
std::string str;
for (int i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-d")) {
if (++i < argc) g_level = parseIntArg(argv[i], g_level);
@ -1236,6 +1242,12 @@ int main(int argc, char ** argv) {
if (++i < argc) g_repeatCount = parseIntArg(argv[i], g_repeatCount);
} else if (!strcmp(argv[i], "-f")) {
fullscreen = true;
} else if (!strcmp(argv[i], "-bilinear")) {
defaultScheme = kBilinear;
} else if (!strcmp(argv[i], "-catmark")) {
defaultScheme = kCatmark;
} else if (!strcmp(argv[i], "-loop")) {
defaultScheme = kLoop;
} else if (argv[i][0] == '-') {
printf("Warning: unrecognized option '%s' ignored\n", argv[i]);
} else {
@ -1245,7 +1257,7 @@ int main(int argc, char ** argv) {
ss << ifs.rdbuf();
ifs.close();
str = ss.str();
g_defaultShapes.push_back(ShapeDesc(argv[i], str.c_str(), kCatmark));
g_defaultShapes.push_back(ShapeDesc(argv[i], str.c_str(), defaultScheme));
} else {
printf("Warning: cannot open shape file '%s'\n", argv[i]);
}

View File

@ -144,10 +144,11 @@ enum ShadingMode { kShadingMaterial,
kShadingInterleavedVaryingColor,
kShadingFaceVaryingColor,
kShadingPatchType,
kShadingPatchDepth,
kShadingPatchCoord,
kShadingNormal };
enum EndCap { kEndCapNone = 0,
enum EndCap { kEndCapBilinearBasis = 0,
kEndCapBSplineBasis,
kEndCapGregoryBasis,
kEndCapLegacyGregory };
@ -189,10 +190,10 @@ int g_fullscreen = 0,
g_mbutton[3] = {0, 0, 0},
g_running = 1;
int g_screenSpaceTess = 1,
g_fractionalSpacing = 1,
int g_screenSpaceTess = 0,
g_fractionalSpacing = 0,
g_patchCull = 0,
g_displayPatchCounts = 1;
g_displayPatchCounts = 0;
float g_rotate[2] = {0, 0},
g_dolly = 5,
@ -394,7 +395,7 @@ updateGeom() {
static const char *
getKernelName(int kernel) {
if (kernel == kCPU)
if (kernel == kCPU)
return "CPU";
else if (kernel == kOPENMP)
return "OpenMP";
@ -420,7 +421,6 @@ rebuildMesh() {
int level = g_level;
int kernel = g_kernel;
bool doAnim = g_objAnim && g_currentShape==0;
Scheme scheme = shapeDesc.scheme;
Shape const * shape = 0;
if (doAnim) {
@ -446,27 +446,21 @@ rebuildMesh() {
delete g_mesh;
g_mesh = NULL;
// Adaptive refinement currently supported only for catmull-clark scheme
bool doAdaptive = (g_adaptive!=0 && scheme==kCatmark);
bool interleaveVarying = g_shadingMode == kShadingInterleavedVaryingColor;
bool doSmoothCornerPatch = (g_smoothCornerPatch!=0 && scheme==kCatmark);
bool doSingleCreasePatch = (g_singleCreasePatch!=0 && scheme==kCatmark);
bool doInfSharpPatch = (g_infSharpPatch!=0 && scheme==kCatmark);
Osd::MeshBitset bits;
bits.set(Osd::MeshAdaptive, doAdaptive);
bits.set(Osd::MeshUseSmoothCornerPatch, doSmoothCornerPatch);
bits.set(Osd::MeshUseSingleCreasePatch, doSingleCreasePatch);
bits.set(Osd::MeshUseInfSharpPatch, doInfSharpPatch);
bits.set(Osd::MeshInterleaveVarying, interleaveVarying);
bits.set(Osd::MeshFVarData, g_shadingMode == kShadingFaceVaryingColor);
bits.set(Osd::MeshEndCapBSplineBasis, g_endCap == kEndCapBSplineBasis);
bits.set(Osd::MeshEndCapGregoryBasis, g_endCap == kEndCapGregoryBasis);
bits.set(Osd::MeshEndCapLegacyGregory, g_endCap == kEndCapLegacyGregory);
bits.set(Osd::MeshAdaptive, g_adaptive != 0);
bits.set(Osd::MeshUseSmoothCornerPatch, g_smoothCornerPatch != 0);
bits.set(Osd::MeshUseSingleCreasePatch, g_singleCreasePatch != 0);
bits.set(Osd::MeshUseInfSharpPatch, g_infSharpPatch != 0);
bits.set(Osd::MeshInterleaveVarying, g_shadingMode == kShadingInterleavedVaryingColor);
bits.set(Osd::MeshFVarData, g_shadingMode == kShadingFaceVaryingColor);
bits.set(Osd::MeshEndCapBilinearBasis, g_endCap == kEndCapBilinearBasis);
bits.set(Osd::MeshEndCapBSplineBasis, g_endCap == kEndCapBSplineBasis);
bits.set(Osd::MeshEndCapGregoryBasis, g_endCap == kEndCapGregoryBasis);
bits.set(Osd::MeshEndCapLegacyGregory, g_endCap == kEndCapLegacyGregory);
int numVertexElements = 3;
int numVaryingElements =
(g_shadingMode == kShadingVaryingColor || interleaveVarying) ? 4 : 0;
(g_shadingMode == kShadingVaryingColor || bits.test(Osd::MeshInterleaveVarying)) ? 4 : 0;
if (kernel == kCPU) {
@ -732,7 +726,8 @@ public:
if (effectDesc.effect.patchCull) {
ss << "#define OSD_ENABLE_PATCH_CULL\n";
}
if (effectDesc.effect.singleCreasePatch) {
if (effectDesc.effect.singleCreasePatch &&
type == Far::PatchDescriptor::REGULAR) {
ss << "#define OSD_PATCH_ENABLE_SINGLE_CREASE\n";
}
// for legacy gregory
@ -773,6 +768,9 @@ public:
case kShadingPatchType:
ss << "#define SHADING_PATCH_TYPE\n";
break;
case kShadingPatchDepth:
ss << "#define SHADING_PATCH_DEPTH\n";
break;
case kShadingPatchCoord:
ss << "#define SHADING_PATCH_COORD\n";
break;
@ -781,10 +779,13 @@ public:
break;
}
if (type == Far::PatchDescriptor::TRIANGLES) {
if (type == Far::PatchDescriptor::TRIANGLES ||
type == Far::PatchDescriptor::LOOP ||
type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define LOOP\n";
} else if (type == Far::PatchDescriptor::QUADS) {
} else {
}
if (type != Far::PatchDescriptor::TRIANGLES &&
type != Far::PatchDescriptor::QUADS) {
ss << "#define SMOOTH_NORMALS\n";
}
@ -795,6 +796,10 @@ public:
ss << "#define OSD_PATCH_GREGORY_BOUNDARY\n";
} else if (type == Far::PatchDescriptor::GREGORY_BASIS) {
ss << "#define OSD_PATCH_GREGORY_BASIS\n";
} else if (type == Far::PatchDescriptor::LOOP) {
ss << "#define OSD_PATCH_LOOP\n";
} else if (type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define OSD_PATCH_GREGORY_TRIANGLE\n";
}
// include osd PatchCommon
@ -1193,18 +1198,24 @@ display() {
double fps = 1.0/elapsed;
if (g_displayPatchCounts) {
int x = -280;
int x = -420;
int y = -180;
g_hud.DrawString(x, y, "NonPatch : %d",
g_hud.DrawString(x, y, "Quads : %d",
patchCount[Descriptor::QUADS]); y += 20;
g_hud.DrawString(x, y, "Triangles : %d",
patchCount[Descriptor::TRIANGLES]); y += 20;
g_hud.DrawString(x, y, "Regular : %d",
patchCount[Descriptor::REGULAR]); y+= 20;
g_hud.DrawString(x, y, "Loop : %d",
patchCount[Descriptor::LOOP]); y+= 20;
g_hud.DrawString(x, y, "Gregory : %d",
patchCount[Descriptor::GREGORY]); y+= 20;
g_hud.DrawString(x, y, "Boundary Gregory : %d",
g_hud.DrawString(x, y, "Gregory Boundary : %d",
patchCount[Descriptor::GREGORY_BOUNDARY]); y+= 20;
g_hud.DrawString(x, y, "Gregory Basis : %d",
patchCount[Descriptor::GREGORY_BASIS]); y+= 20;
g_hud.DrawString(x, y, "Gregory Triangle : %d",
patchCount[Descriptor::GREGORY_TRIANGLE]); y+= 20;
}
int y = -220;
@ -1515,6 +1526,9 @@ initHUD() {
g_hud.AddPullDownButton(shading_pulldown, "Patch Type",
kShadingPatchType,
g_shadingMode == kShadingPatchType);
g_hud.AddPullDownButton(shading_pulldown, "Patch Depth",
kShadingPatchDepth,
g_shadingMode == kShadingPatchDepth);
g_hud.AddPullDownButton(shading_pulldown, "Patch Coord",
kShadingPatchCoord,
g_shadingMode == kShadingPatchCoord);
@ -1558,13 +1572,13 @@ initHUD() {
int endcap_pulldown = g_hud.AddPullDown(
"End cap (E)", 10, 270, 200, callbackEndCap, 'e');
g_hud.AddPullDownButton(endcap_pulldown,"None",
kEndCapNone,
g_endCap == kEndCapNone);
g_hud.AddPullDownButton(endcap_pulldown, "BSpline",
g_hud.AddPullDownButton(endcap_pulldown,"Linear",
kEndCapBilinearBasis,
g_endCap == kEndCapBilinearBasis);
g_hud.AddPullDownButton(endcap_pulldown, "Regular",
kEndCapBSplineBasis,
g_endCap == kEndCapBSplineBasis);
g_hud.AddPullDownButton(endcap_pulldown, "GregoryBasis",
g_hud.AddPullDownButton(endcap_pulldown, "Gregory",
kEndCapGregoryBasis,
g_endCap == kEndCapGregoryBasis);
g_hud.AddPullDownButton(endcap_pulldown, "LegacyGregory",
@ -1575,7 +1589,7 @@ initHUD() {
for (int i = 1; i < 11; ++i) {
char level[16];
sprintf(level, "Lv. %d", i);
g_hud.AddRadioButton(3, level, i==2, 10, 310+i*20, callbackLevel, i, '0'+(i%10));
g_hud.AddRadioButton(3, level, i == g_level, 10, 310+i*20, callbackLevel, i, '0'+(i%10));
}
int shapes_pulldown = g_hud.AddPullDown("Shape (N)", -300, 10, 300, callbackModel, 'n');
@ -1583,7 +1597,7 @@ initHUD() {
g_hud.AddPullDownButton(shapes_pulldown, g_defaultShapes[i].name.c_str(),i);
}
g_hud.AddCheckBox("Show patch counts", g_displayPatchCounts!=0, -280, -20, callbackCheckBox, kHUD_CB_DISPLAY_PATCH_COUNTS);
g_hud.AddCheckBox("Show patch counts", g_displayPatchCounts!=0, -420, -20, callbackCheckBox, kHUD_CB_DISPLAY_PATCH_COUNTS);
g_hud.Rebuild(windowWidth, windowHeight, frameBufferWidth, frameBufferHeight);
}
@ -1629,9 +1643,11 @@ callbackErrorGLFW(int error, const char* description) {
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
int main(int argc, char ** argv) {
bool fullscreen = false;
Scheme defaultScheme = kCatmark;
std::string str;
std::vector<char const *> animobjs;
@ -1642,15 +1658,27 @@ int main(int argc, char ** argv) {
else if (!strcmp(argv[i], "-axis")) {
g_axis = false;
}
else if (!strcmp(argv[i], "-u")) {
g_adaptive = false;
}
else if (!strcmp(argv[i], "-d")) {
g_level = atoi(argv[++i]);
if (++i < argc) g_level = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-c")) {
g_repeatCount = atoi(argv[++i]);
if (++i < argc) g_repeatCount = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-f")) {
fullscreen = true;
}
else if (!strcmp(argv[i], "-bilinear")) {
defaultScheme = kBilinear;
}
else if (!strcmp(argv[i], "-catmark")) {
defaultScheme = kCatmark;
}
else if (!strcmp(argv[i], "-loop")) {
defaultScheme = kLoop;
}
else {
std::ifstream ifs(argv[1]);
if (ifs) {
@ -1658,16 +1686,16 @@ int main(int argc, char ** argv) {
ss << ifs.rdbuf();
ifs.close();
str = ss.str();
g_defaultShapes.push_back(ShapeDesc(argv[1], str.c_str(), kCatmark));
g_defaultShapes.push_back(ShapeDesc(argv[1], str.c_str(), defaultScheme));
}
}
}
if (! animobjs.empty()) {
g_defaultShapes.push_back(ShapeDesc(animobjs[0], "", kCatmark));
g_defaultShapes.push_back(ShapeDesc(animobjs[0], "", defaultScheme));
g_objAnim = ObjAnim::Create(animobjs, g_axis);
g_objAnim = ObjAnim::Create(animobjs, g_axis, defaultScheme);
}
initShapes();
@ -1744,7 +1772,9 @@ int main(int argc, char ** argv) {
#endif
// activate feature adaptive tessellation if OSD supports it
g_adaptive = GLUtils::SupportsAdaptiveTessellation();
if (g_adaptive) {
g_adaptive = GLUtils::SupportsAdaptiveTessellation();
}
initGL();

View File

@ -44,12 +44,20 @@
outpt.color = \
mix(mix(inpt[a].color, inpt[b].color, UV.x), \
mix(inpt[c].color, inpt[d].color, UV.x), UV.y)
#undef OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE
#define OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE(UV, a, b, c) \
outpt.color = \
inpt[a].color * (1.0f - UV.x - UV.y) + \
inpt[b].color * UV.x + \
inpt[c].color * UV.y;
#else
#define OSD_USER_VARYING_DECLARE
#define OSD_USER_VARYING_ATTRIBUTE_DECLARE
#define OSD_USER_VARYING_PER_VERTEX()
#define OSD_USER_VARYING_PER_CONTROL_POINT(ID_OUT, ID_IN)
#define OSD_USER_VARYING_PER_EVAL_POINT(UV, a, b, c, d)
#define OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE(UV, a, b, c)
#endif
//--------------------------------------------------------------
@ -171,6 +179,38 @@ out block {
OSD_USER_VARYING_DECLARE
} outpt;
vec2
interpolateFaceVarying(vec2 uv, int fvarOffset)
{
int patchIndex = OsdGetPatchIndex(gl_PrimitiveID);
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
#ifdef LOOP
int patchType = OSD_PATCH_DESCRIPTOR_TRIANGLES;
OsdPatchParam param = OsdPatchParamInit(0, 0, 0);
int numPoints = OsdEvaluatePatchBasisNormalized(patchType, param,
uv.s, uv.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
#else
int patchType = OSD_PATCH_DESCRIPTOR_QUADS;
OsdPatchParam param = OsdPatchParamInit(0, 0, 0);
int numPoints = OsdEvaluatePatchBasisNormalized(patchType, param,
uv.s, uv.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
#endif
int patchArrayStride = numPoints;
int primOffset = patchIndex * patchArrayStride;
vec2 result = vec2(0);
for (int i=0; i<numPoints; ++i) {
int index = (primOffset+i)*OSD_FVAR_WIDTH + fvarOffset;
vec2 cv = vec2(texelFetch(OsdFVarDataBuffer, index).s,
texelFetch(OsdFVarDataBuffer, index + 1).s);
result += wP[i] * cv;
}
return result;
}
void emit(int index, vec3 normal)
{
outpt.v.position = inpt[index].v.position;
@ -191,8 +231,14 @@ void emit(int index, vec3 normal)
#ifdef SHADING_FACEVARYING_COLOR
#ifdef LOOP // ----- scheme : LOOP
vec2 uv;
OSD_COMPUTE_FACE_VARYING_TRI_2(uv, /*fvarOffste=*/0, index);
#ifdef SHADING_FACEVARYING_UNIFORM_SUBDIVISION
vec2 trist[3] = vec2[](vec2(0,0), vec2(1,0), vec2(0,1));
vec2 st = trist[index];
#else
vec2 st = inpt[index].v.tessCoord;
#endif
vec2 uv = interpolateFaceVarying(st, /*fvarOffset=*/0);
#else // ----- scheme : CATMARK / BILINEAR
@ -202,8 +248,8 @@ void emit(int index, vec3 normal)
#else
vec2 st = inpt[index].v.tessCoord;
#endif
vec2 uv;
OSD_COMPUTE_FACE_VARYING_2(uv, /*fvarOffset=*/0, st);
vec2 uv = interpolateFaceVarying(st, /*fvarOffset=*/0);
#endif // ------ scheme
outpt.color = vec3(uv.s, uv.t, 0);
#endif
@ -452,11 +498,11 @@ getAdaptivePatchColor(ivec3 patchParam)
if (edgeCount == 1) {
patchType = 2; // BOUNDARY
}
if (edgeCount == 2) {
patchType = 3; // CORNER
if (edgeCount > 1) {
patchType = 3; // CORNER (not correct for patches that are not isolated)
}
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
#if defined(OSD_PATCH_ENABLE_SINGLE_CREASE) && !defined(LOOP)
// check this after boundary/corner since single crease patch also has edgeCount.
if (inpt.vSegments.y > 0) {
patchType = 1;
@ -467,6 +513,8 @@ getAdaptivePatchColor(ivec3 patchParam)
patchType = 5;
#elif defined OSD_PATCH_GREGORY_BASIS
patchType = 6;
#elif defined OSD_PATCH_GREGORY_TRIANGLE
patchType = 6;
#endif
int pattern = bitCount(OsdGetPatchTransitionMask(patchParam));
@ -474,6 +522,19 @@ getAdaptivePatchColor(ivec3 patchParam)
return patchColors[6*patchType + pattern];
}
vec4
getAdaptiveDepthColor(ivec3 patchParam)
{
// Represent depth with repeating cycle of four colors:
const vec4 depthColors[4] = vec4[4](
vec4(0.0f, 0.5f, 0.5f, 1.0f),
vec4(1.0f, 1.0f, 1.0f, 1.0f),
vec4(0.0f, 1.0f, 1.0f, 1.0f),
vec4(0.5f, 1.0f, 0.5f, 1.0f)
);
return depthColors[OsdGetPatchRefinementLevel(patchParam) & 3];
}
#if defined(PRIM_QUAD) || defined(PRIM_TRI)
void
main()
@ -488,6 +549,8 @@ main()
int(floor(20*inpt.color.r)+floor(20*inpt.color.g))&1, 1);
#elif defined(SHADING_PATCH_TYPE)
vec4 color = getAdaptivePatchColor(OsdGetPatchParam(OsdGetPatchIndex(gl_PrimitiveID)));
#elif defined(SHADING_PATCH_DEPTH)
vec4 color = getAdaptiveDepthColor(OsdGetPatchParam(OsdGetPatchIndex(gl_PrimitiveID)));
#elif defined(SHADING_PATCH_COORD)
vec4 color = vec4(inpt.v.patchCoord.xy, 0, 1);
#elif defined(SHADING_MATERIAL)