mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-23 20:20:09 +00:00
Introduces 'single-crease patch' : implements "Efficient Evaluation of Semi-Smooth Creases in
Catmull-Clark Subdivision Surfaces", Niessner et al, Eurographics 2012. This change includes; -topology identification for single-crease patch during adaptive refinement. -patch array population (similar to boundary) -sharpness buffer generation -glsl shader Eval stuffs will be coming.
This commit is contained in:
parent
c30087cb52
commit
c0907c7bc1
@ -24,7 +24,8 @@
|
|||||||
|
|
||||||
#include "patchColors.h"
|
#include "patchColors.h"
|
||||||
|
|
||||||
static float _colors[4][5][4] = {{{1.0f, 1.0f, 1.0f, 1.0f}, // regular
|
static float _colors[5][6][4] = {{{1.0f, 1.0f, 1.0f, 1.0f}, // regular
|
||||||
|
{1.0f, 0.5f, 0.5f, 1.0f}, // single crease
|
||||||
{0.8f, 0.0f, 0.0f, 1.0f}, // boundary
|
{0.8f, 0.0f, 0.0f, 1.0f}, // boundary
|
||||||
{0.0f, 1.0f, 0.0f, 1.0f}, // corner
|
{0.0f, 1.0f, 0.0f, 1.0f}, // corner
|
||||||
{1.0f, 1.0f, 0.0f, 1.0f}, // gregory
|
{1.0f, 1.0f, 0.0f, 1.0f}, // gregory
|
||||||
@ -36,6 +37,12 @@ static float _colors[4][5][4] = {{{1.0f, 1.0f, 1.0f, 1.0f}, // regular
|
|||||||
{0.5f, 0.0f, 1.0f, 1.0f}, // regular pattern 3
|
{0.5f, 0.0f, 1.0f, 1.0f}, // regular pattern 3
|
||||||
{1.0f, 0.5f, 1.0f, 1.0f}}, // regular pattern 4
|
{1.0f, 0.5f, 1.0f, 1.0f}}, // regular pattern 4
|
||||||
|
|
||||||
|
{{1.0f, 0.7f, 0.6f, 1.0f}, // single crease pattern 0
|
||||||
|
{1.0f, 0.7f, 0.6f, 1.0f}, // single crease pattern 1
|
||||||
|
{1.0f, 0.7f, 0.6f, 1.0f}, // single crease pattern 2
|
||||||
|
{1.0f, 0.7f, 0.6f, 1.0f}, // single crease pattern 3
|
||||||
|
{1.0f, 0.7f, 0.6f, 1.0f}}, // single crease pattern 4
|
||||||
|
|
||||||
{{0.0f, 0.0f, 0.75f, 1.0f}, // boundary pattern 0
|
{{0.0f, 0.0f, 0.75f, 1.0f}, // boundary pattern 0
|
||||||
{0.0f, 0.2f, 0.75f, 1.0f}, // boundary pattern 1
|
{0.0f, 0.2f, 0.75f, 1.0f}, // boundary pattern 1
|
||||||
{0.0f, 0.4f, 0.75f, 1.0f}, // boundary pattern 2
|
{0.0f, 0.4f, 0.75f, 1.0f}, // boundary pattern 2
|
||||||
|
@ -148,9 +148,10 @@ enum HudCheckBox { kHUD_CB_DISPLAY_CAGE_EDGES,
|
|||||||
kHUD_CB_VIEW_LOD,
|
kHUD_CB_VIEW_LOD,
|
||||||
kHUD_CB_FRACTIONAL_SPACING,
|
kHUD_CB_FRACTIONAL_SPACING,
|
||||||
kHUD_CB_PATCH_CULL,
|
kHUD_CB_PATCH_CULL,
|
||||||
kHUD_CB_FREEZE };
|
kHUD_CB_FREEZE,
|
||||||
|
kHUD_CB_DISPLAY_PATCH_COUNTS };
|
||||||
|
|
||||||
int g_currentShape = 0;
|
int g_currentShape = 8;
|
||||||
|
|
||||||
ObjAnim const * g_objAnim = 0;
|
ObjAnim const * g_objAnim = 0;
|
||||||
|
|
||||||
@ -164,16 +165,18 @@ float g_animTime = 0;
|
|||||||
int g_fullscreen = 0,
|
int g_fullscreen = 0,
|
||||||
g_freeze = 0,
|
g_freeze = 0,
|
||||||
g_displayStyle = kWireShaded,
|
g_displayStyle = kWireShaded,
|
||||||
g_adaptive = 0,
|
g_adaptive = 1,
|
||||||
|
g_singleCreasePatch = 1,
|
||||||
g_drawCageEdges = 1,
|
g_drawCageEdges = 1,
|
||||||
g_drawCageVertices = 0,
|
g_drawCageVertices = 0,
|
||||||
g_mbutton[3] = {0, 0, 0},
|
g_mbutton[3] = {0, 0, 0},
|
||||||
g_running = 1;
|
g_running = 1;
|
||||||
|
|
||||||
int g_displayPatchColor = 1,
|
int g_displayPatchColor = 1,
|
||||||
g_screenSpaceTess = 0,
|
g_screenSpaceTess = 1,
|
||||||
g_fractionalSpacing = 0,
|
g_fractionalSpacing = 1,
|
||||||
g_patchCull = 0;
|
g_patchCull = 0,
|
||||||
|
g_displayPatchCounts = 0;
|
||||||
|
|
||||||
float g_rotate[2] = {0, 0},
|
float g_rotate[2] = {0, 0},
|
||||||
g_dolly = 5,
|
g_dolly = 5,
|
||||||
@ -523,10 +526,12 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level, int kernel, Scheme scheme=
|
|||||||
|
|
||||||
// Adaptive refinement currently supported only for catmull-clark scheme
|
// Adaptive refinement currently supported only for catmull-clark scheme
|
||||||
bool doAdaptive = (g_adaptive!=0 and g_scheme==kCatmark),
|
bool doAdaptive = (g_adaptive!=0 and g_scheme==kCatmark),
|
||||||
interleaveVarying = g_displayStyle == kInterleavedVaryingColor;
|
interleaveVarying = g_displayStyle == kInterleavedVaryingColor,
|
||||||
|
doSingleCreasePatch = (g_singleCreasePatch!=0 and g_scheme==kCatmark);
|
||||||
|
|
||||||
OpenSubdiv::Osd::MeshBitset bits;
|
OpenSubdiv::Osd::MeshBitset bits;
|
||||||
bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
|
bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
|
||||||
|
bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, doSingleCreasePatch);
|
||||||
bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, interleaveVarying);
|
bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, interleaveVarying);
|
||||||
bits.set(OpenSubdiv::Osd::MeshFVarData, g_displayStyle == kFaceVaryingColor);
|
bits.set(OpenSubdiv::Osd::MeshFVarData, g_displayStyle == kFaceVaryingColor);
|
||||||
|
|
||||||
@ -1148,7 +1153,9 @@ display() {
|
|||||||
g_mesh->GetDrawContext()->GetPatchArrays();
|
g_mesh->GetDrawContext()->GetPatchArrays();
|
||||||
|
|
||||||
// patch drawing
|
// patch drawing
|
||||||
int patchCount[11][6][4]; // [Type][Pattern][Rotation] (see far/patchTables.h)
|
int patchCount[12][6][4]; // [Type][Pattern][Rotation] (see far/patchTables.h)
|
||||||
|
int numTotalPatches = 0;
|
||||||
|
int numDrawCalls = 0;
|
||||||
memset(patchCount, 0, sizeof(patchCount));
|
memset(patchCount, 0, sizeof(patchCount));
|
||||||
|
|
||||||
// primitive counting
|
// primitive counting
|
||||||
@ -1169,6 +1176,7 @@ display() {
|
|||||||
if (subPatch == 0) {
|
if (subPatch == 0) {
|
||||||
patchCount[patchType][patchPattern][patchRotation] += patch.GetNumPatches();
|
patchCount[patchType][patchPattern][patchRotation] += patch.GetNumPatches();
|
||||||
}
|
}
|
||||||
|
numTotalPatches += patch.GetNumPatches();
|
||||||
|
|
||||||
GLenum primType;
|
GLenum primType;
|
||||||
|
|
||||||
@ -1223,6 +1231,7 @@ display() {
|
|||||||
|
|
||||||
glDrawElements(primType, patch.GetNumIndices(), GL_UNSIGNED_INT,
|
glDrawElements(primType, patch.GetNumIndices(), GL_UNSIGNED_INT,
|
||||||
(void *)(patch.GetVertIndex() * sizeof(unsigned int)));
|
(void *)(patch.GetVertIndex() * sizeof(unsigned int)));
|
||||||
|
++numDrawCalls;
|
||||||
if (g_displayStyle == kWire) {
|
if (g_displayStyle == kWire) {
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
}
|
}
|
||||||
@ -1268,47 +1277,64 @@ display() {
|
|||||||
|
|
||||||
double fps = 1.0/elapsed;
|
double fps = 1.0/elapsed;
|
||||||
|
|
||||||
int x = -280;
|
if (g_displayPatchCounts) {
|
||||||
g_hud.DrawString(x, -360, "NonPatch : %d",
|
int x = -280;
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::QUADS][0][0]);
|
int y = -480;
|
||||||
g_hud.DrawString(x, -340, "Regular : %d",
|
g_hud.DrawString(x, y, "NonPatch : %d",
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][0][0]);
|
patchCount[OpenSubdiv::Far::PatchTables::QUADS][0][0]); y += 20;
|
||||||
g_hud.DrawString(x, -320, "Boundary : %d",
|
g_hud.DrawString(x, y, "Regular : %d",
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][0][0]);
|
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][0][0]); y+= 20;
|
||||||
g_hud.DrawString(x, -300, "Corner : %d",
|
g_hud.DrawString(x, y, "Boundary : %d",
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::CORNER][0][0]);
|
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][0][0]); y+= 20;
|
||||||
g_hud.DrawString(x, -280, "Gregory : %d",
|
g_hud.DrawString(x, y, "Corner : %d",
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::GREGORY][0][0]);
|
patchCount[OpenSubdiv::Far::PatchTables::CORNER][0][0]); y+= 20;
|
||||||
g_hud.DrawString(x, -260, "Boundary Gregory : %d",
|
g_hud.DrawString(x, y, "Single Crease : %d",
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::GREGORY_BOUNDARY][0][0]);
|
patchCount[OpenSubdiv::Far::PatchTables::SINGLE_CREASE][0][0]); y+= 20;
|
||||||
g_hud.DrawString(x, -240, "Trans. Regular : %d %d %d %d %d",
|
g_hud.DrawString(x, y, "Gregory : %d",
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN0][0],
|
patchCount[OpenSubdiv::Far::PatchTables::GREGORY][0][0]); y+= 20;
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN1][0],
|
g_hud.DrawString(x, y, "Boundary Gregory : %d",
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN2][0],
|
patchCount[OpenSubdiv::Far::PatchTables::GREGORY_BOUNDARY][0][0]); y+= 20;
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN3][0],
|
g_hud.DrawString(x, y, "Trans. Regular : %d %d %d %d %d",
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN4][0]);
|
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN0][0],
|
||||||
for (int i=0; i < 5; i++)
|
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN1][0],
|
||||||
g_hud.DrawString(x, -220+i*20, "Trans. Boundary%d : %d %d %d %d", i,
|
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN2][0],
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][0],
|
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN3][0],
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][1],
|
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN4][0]); y+= 20;
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][2],
|
for (int i=0; i < 5; i++) {
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][3]);
|
g_hud.DrawString(x, y, "Trans. Boundary%d : %d %d %d %d", i,
|
||||||
for (int i=0; i < 5; i++)
|
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][0],
|
||||||
g_hud.DrawString(x, -100+i*20, "Trans. Corner%d : %d %d %d %d", i,
|
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][1],
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::CORNER][i+1][0],
|
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][2],
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::CORNER][i+1][1],
|
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][3]); y+= 20;
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::CORNER][i+1][2],
|
}
|
||||||
patchCount[OpenSubdiv::Far::PatchTables::CORNER][i+1][3]);
|
for (int i=0; i < 5; i++) {
|
||||||
|
g_hud.DrawString(x, y, "Trans. Corner%d : %d %d %d %d", i,
|
||||||
|
patchCount[OpenSubdiv::Far::PatchTables::CORNER][i+1][0],
|
||||||
|
patchCount[OpenSubdiv::Far::PatchTables::CORNER][i+1][1],
|
||||||
|
patchCount[OpenSubdiv::Far::PatchTables::CORNER][i+1][2],
|
||||||
|
patchCount[OpenSubdiv::Far::PatchTables::CORNER][i+1][3]); y+= 20;
|
||||||
|
}
|
||||||
|
for (int i=0; i < 5; i++) {
|
||||||
|
g_hud.DrawString(x, y, "Trans. Single Crease%d : %d %d %d %d", i,
|
||||||
|
patchCount[OpenSubdiv::Far::PatchTables::SINGLE_CREASE][i+1][0],
|
||||||
|
patchCount[OpenSubdiv::Far::PatchTables::SINGLE_CREASE][i+1][1],
|
||||||
|
patchCount[OpenSubdiv::Far::PatchTables::SINGLE_CREASE][i+1][2],
|
||||||
|
patchCount[OpenSubdiv::Far::PatchTables::SINGLE_CREASE][i+1][3]); y+= 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g_hud.DrawString(10, -180, "Tess level : %d", g_tessLevel);
|
int y = -220;
|
||||||
g_hud.DrawString(10, -160, "Primitives : %d", numPrimsGenerated);
|
g_hud.DrawString(10, y, "Tess level : %d", g_tessLevel); y+= 20;
|
||||||
g_hud.DrawString(10, -140, "Vertices : %d", g_mesh->GetNumVertices());
|
g_hud.DrawString(10, y, "Patches : %d", numTotalPatches); y+= 20;
|
||||||
g_hud.DrawString(10, -120, "Scheme : %s", g_scheme==kBilinear ? "BILINEAR" : (g_scheme == kLoop ? "LOOP" : "CATMARK"));
|
g_hud.DrawString(10, y, "Draw calls : %d", numDrawCalls); y+= 20;
|
||||||
g_hud.DrawString(10, -100, "GPU Kernel : %.3f ms", g_gpuTime);
|
g_hud.DrawString(10, y, "Primitives : %d", numPrimsGenerated); y+= 20;
|
||||||
g_hud.DrawString(10, -80, "CPU Kernel : %.3f ms", g_cpuTime);
|
g_hud.DrawString(10, y, "Vertices : %d", g_mesh->GetNumVertices()); y+= 20;
|
||||||
g_hud.DrawString(10, -60, "GPU Draw : %.3f ms", drawGpuTime);
|
g_hud.DrawString(10, y, "Scheme : %s", g_scheme==kBilinear ? "BILINEAR" : (g_scheme == kLoop ? "LOOP" : "CATMARK")); y+= 20;
|
||||||
g_hud.DrawString(10, -40, "CPU Draw : %.3f ms", drawCpuTime);
|
g_hud.DrawString(10, y, "GPU Kernel : %.3f ms", g_gpuTime); y+= 20;
|
||||||
g_hud.DrawString(10, -20, "FPS : %3.1f", fps);
|
g_hud.DrawString(10, y, "CPU Kernel : %.3f ms", g_cpuTime); y+= 20;
|
||||||
|
g_hud.DrawString(10, y, "GPU Draw : %.3f ms", drawGpuTime); y+= 20;
|
||||||
|
g_hud.DrawString(10, y, "CPU Draw : %.3f ms", drawCpuTime); y+= 20;
|
||||||
|
g_hud.DrawString(10, y, "FPS : %3.1f", fps); y+= 20;
|
||||||
|
|
||||||
g_hud.Flush();
|
g_hud.Flush();
|
||||||
}
|
}
|
||||||
@ -1519,6 +1545,15 @@ callbackAdaptive(bool checked, int /* a */)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
callbackSingleCreasePatch(bool checked, int /* a */)
|
||||||
|
{
|
||||||
|
if (OpenSubdiv::Osd::GLDrawContext::SupportsAdaptiveTessellation()) {
|
||||||
|
g_singleCreasePatch = checked;
|
||||||
|
rebuildOsdMesh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
callbackCheckBox(bool checked, int button)
|
callbackCheckBox(bool checked, int button)
|
||||||
{
|
{
|
||||||
@ -1547,6 +1582,9 @@ callbackCheckBox(bool checked, int button)
|
|||||||
case kHUD_CB_FREEZE:
|
case kHUD_CB_FREEZE:
|
||||||
g_freeze = checked;
|
g_freeze = checked;
|
||||||
break;
|
break;
|
||||||
|
case kHUD_CB_DISPLAY_PATCH_COUNTS:
|
||||||
|
g_displayPatchCounts = checked;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1614,8 +1652,10 @@ initHUD()
|
|||||||
g_hud.AddPullDownButton(compute_pulldown, "GLSL Compute", kGLSLCompute);
|
g_hud.AddPullDownButton(compute_pulldown, "GLSL Compute", kGLSLCompute);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (OpenSubdiv::Osd::GLDrawContext::SupportsAdaptiveTessellation())
|
if (OpenSubdiv::Osd::GLDrawContext::SupportsAdaptiveTessellation()) {
|
||||||
g_hud.AddCheckBox("Adaptive (`)", g_adaptive!=0, 10, 190, callbackAdaptive, 0, '`');
|
g_hud.AddCheckBox("Adaptive (`)", g_adaptive!=0, 10, 190, callbackAdaptive, 0, '`');
|
||||||
|
g_hud.AddCheckBox("Single Crease Patch (S)", g_singleCreasePatch!=0, 10, 210, callbackSingleCreasePatch, 0, 's');
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 1; i < 11; ++i) {
|
for (int i = 1; i < 11; ++i) {
|
||||||
char level[16];
|
char level[16];
|
||||||
@ -1628,6 +1668,8 @@ initHUD()
|
|||||||
g_hud.AddPullDownButton(shapes_pulldown, g_defaultShapes[i].name.c_str(),i);
|
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.Rebuild(g_width, g_height);
|
g_hud.Rebuild(g_width, g_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +358,9 @@ edgeColor(vec4 Cfill, vec4 edgeDistance)
|
|||||||
min(min(inpt.edgeDistance[0], inpt.edgeDistance[1]),
|
min(min(inpt.edgeDistance[0], inpt.edgeDistance[1]),
|
||||||
min(inpt.edgeDistance[2], inpt.edgeDistance[3]));
|
min(inpt.edgeDistance[2], inpt.edgeDistance[3]));
|
||||||
#endif
|
#endif
|
||||||
vec4 Cedge = vec4(1.0, 1.0, 0.0, 1.0);
|
//vec4 Cedge = vec4(1.0, 1.0, 0.0, 1.0);
|
||||||
|
float v = 0.8;
|
||||||
|
vec4 Cedge = vec4(Cfill.r*v, Cfill.g*v, Cfill.b*v, 1);
|
||||||
float p = exp2(-2 * d * d);
|
float p = exp2(-2 * d * d);
|
||||||
|
|
||||||
#if defined(GEOMETRY_OUT_WIRE)
|
#if defined(GEOMETRY_OUT_WIRE)
|
||||||
|
@ -253,19 +253,23 @@ PatchTables::getAdaptiveCatmarkDescriptors() {
|
|||||||
|
|
||||||
if (_descriptors.empty()) {
|
if (_descriptors.empty()) {
|
||||||
|
|
||||||
_descriptors.reserve(50);
|
_descriptors.reserve(71);
|
||||||
|
|
||||||
// non-transition patches
|
// non-transition patches : 6
|
||||||
for (int i=REGULAR; i<=GREGORY_BOUNDARY; ++i) {
|
for (int i=REGULAR; i<=GREGORY_BOUNDARY; ++i) {
|
||||||
_descriptors.push_back( Descriptor(i, NON_TRANSITION, 0) );
|
_descriptors.push_back( Descriptor(i, NON_TRANSITION, 0) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// transition patches
|
// transition patches (1 + 4 * 3) * 5 = 65
|
||||||
for (int i=PATTERN0; i<=PATTERN4; ++i) {
|
for (int i=PATTERN0; i<=PATTERN4; ++i) {
|
||||||
|
|
||||||
_descriptors.push_back( Descriptor(REGULAR, i, 0) );
|
_descriptors.push_back( Descriptor(REGULAR, i, 0) );
|
||||||
|
|
||||||
// 4 rotations for boundary & corner patches
|
// 4 rotations for single-crease, boundary and corner patches
|
||||||
|
for (int j=0; j<4; ++j) {
|
||||||
|
_descriptors.push_back( Descriptor(SINGLE_CREASE, i, j) );
|
||||||
|
}
|
||||||
|
|
||||||
for (int j=0; j<4; ++j) {
|
for (int j=0; j<4; ++j) {
|
||||||
_descriptors.push_back( Descriptor(BOUNDARY, i, j) );
|
_descriptors.push_back( Descriptor(BOUNDARY, i, j) );
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ public:
|
|||||||
LOOP, ///< Loop patch (currently unsupported)
|
LOOP, ///< Loop patch (currently unsupported)
|
||||||
|
|
||||||
REGULAR, ///< feature-adaptive bicubic patches
|
REGULAR, ///< feature-adaptive bicubic patches
|
||||||
|
SINGLE_CREASE,
|
||||||
BOUNDARY,
|
BOUNDARY,
|
||||||
CORNER,
|
CORNER,
|
||||||
GREGORY,
|
GREGORY,
|
||||||
@ -339,6 +340,12 @@ public:
|
|||||||
/// \brief Returns a PatchParamTable for each type of patch
|
/// \brief Returns a PatchParamTable for each type of patch
|
||||||
PatchParamTable const & GetPatchParamTable() const { return _paramTable; }
|
PatchParamTable const & GetPatchParamTable() const { return _paramTable; }
|
||||||
|
|
||||||
|
/// \brief Returns a sharpness index table for each type of patch (if exists)
|
||||||
|
std::vector<int> const &GetSharpnessIndexTable() const { return _sharpnessIndexTable; }
|
||||||
|
|
||||||
|
/// \brief Returns sharpness values (if exists)
|
||||||
|
std::vector<float> const &GetSharpnessValues() const { return _sharpnessValues; }
|
||||||
|
|
||||||
/// \brief Number of control vertices of Regular Patches in table.
|
/// \brief Number of control vertices of Regular Patches in table.
|
||||||
static short GetRegularPatchSize() { return 16; }
|
static short GetRegularPatchSize() { return 16; }
|
||||||
|
|
||||||
@ -577,6 +584,10 @@ private:
|
|||||||
|
|
||||||
FVarPatchTables const * _fvarPatchTables; // sparse face-varying patch table (one per patch)
|
FVarPatchTables const * _fvarPatchTables; // sparse face-varying patch table (one per patch)
|
||||||
|
|
||||||
|
std::vector<int> _sharpnessIndexTable;// Indices of single-crease sharpness (one per patch)
|
||||||
|
|
||||||
|
std::vector<float> _sharpnessValues; // Sharpness values.
|
||||||
|
|
||||||
// highest vertex valence allowed in the mesh (used for Gregory
|
// highest vertex valence allowed in the mesh (used for Gregory
|
||||||
// vertexValance & quadOffset tables)
|
// vertexValance & quadOffset tables)
|
||||||
int _maxValence;
|
int _maxValence;
|
||||||
@ -591,6 +602,7 @@ inline short
|
|||||||
PatchTables::Descriptor::GetNumControlVertices( PatchTables::Type type ) {
|
PatchTables::Descriptor::GetNumControlVertices( PatchTables::Type type ) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case REGULAR : return PatchTables::GetRegularPatchSize();
|
case REGULAR : return PatchTables::GetRegularPatchSize();
|
||||||
|
case SINGLE_CREASE : return PatchTables::GetRegularPatchSize();
|
||||||
case QUADS : return 4;
|
case QUADS : return 4;
|
||||||
case GREGORY :
|
case GREGORY :
|
||||||
case GREGORY_BOUNDARY : return PatchTables::GetGregoryPatchSize();
|
case GREGORY_BOUNDARY : return PatchTables::GetGregoryPatchSize();
|
||||||
@ -608,6 +620,7 @@ inline short
|
|||||||
PatchTables::Descriptor::GetNumFVarControlVertices( PatchTables::Type type ) {
|
PatchTables::Descriptor::GetNumFVarControlVertices( PatchTables::Type type ) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case REGULAR : // We only support bilinear interpolation for now,
|
case REGULAR : // We only support bilinear interpolation for now,
|
||||||
|
case SINGLE_CREASE :
|
||||||
case QUADS : // so all these patches only carry 4 CVs.
|
case QUADS : // so all these patches only carry 4 CVs.
|
||||||
case GREGORY :
|
case GREGORY :
|
||||||
case GREGORY_BOUNDARY :
|
case GREGORY_BOUNDARY :
|
||||||
@ -811,6 +824,10 @@ PatchTables::Limit(PatchHandle const & handle, float s, float t,
|
|||||||
case REGULAR:
|
case REGULAR:
|
||||||
InterpolateRegularPatch(cvs, Q, Qd1, Qd2, src, dst);
|
InterpolateRegularPatch(cvs, Q, Qd1, Qd2, src, dst);
|
||||||
break;
|
break;
|
||||||
|
case SINGLE_CREASE:
|
||||||
|
// TODO: implement InterpolateSingleCreasePatch().
|
||||||
|
//InterpolateRegularPatch(cvs, Q, Qd1, Qd2, src, dst);
|
||||||
|
break;
|
||||||
case BOUNDARY:
|
case BOUNDARY:
|
||||||
InterpolateBoundaryPatch(cvs, Q, Qd1, Qd2, src, dst);
|
InterpolateBoundaryPatch(cvs, Q, Qd1, Qd2, src, dst);
|
||||||
break;
|
break;
|
||||||
|
@ -46,6 +46,7 @@ struct PatchTypes {
|
|||||||
NUM_ROTATIONS=4;
|
NUM_ROTATIONS=4;
|
||||||
|
|
||||||
TYPE R[NUM_TRANSITIONS], // regular patch
|
TYPE R[NUM_TRANSITIONS], // regular patch
|
||||||
|
S[NUM_TRANSITIONS][NUM_ROTATIONS], // single-crease patch
|
||||||
B[NUM_TRANSITIONS][NUM_ROTATIONS], // boundary patch (4 rotations)
|
B[NUM_TRANSITIONS][NUM_ROTATIONS], // boundary patch (4 rotations)
|
||||||
C[NUM_TRANSITIONS][NUM_ROTATIONS], // corner patch (4 rotations)
|
C[NUM_TRANSITIONS][NUM_ROTATIONS], // corner patch (4 rotations)
|
||||||
G, // gregory patch
|
G, // gregory patch
|
||||||
@ -57,6 +58,7 @@ struct PatchTypes {
|
|||||||
TYPE & getValue( PatchTables::Descriptor desc ) {
|
TYPE & getValue( PatchTables::Descriptor desc ) {
|
||||||
switch (desc.GetType()) {
|
switch (desc.GetType()) {
|
||||||
case PatchTables::REGULAR : return R[desc.GetPattern()];
|
case PatchTables::REGULAR : return R[desc.GetPattern()];
|
||||||
|
case PatchTables::SINGLE_CREASE : return S[desc.GetPattern()][desc.GetRotation()];
|
||||||
case PatchTables::BOUNDARY : return B[desc.GetPattern()][desc.GetRotation()];
|
case PatchTables::BOUNDARY : return B[desc.GetPattern()][desc.GetRotation()];
|
||||||
case PatchTables::CORNER : return C[desc.GetPattern()][desc.GetRotation()];
|
case PatchTables::CORNER : return C[desc.GetPattern()][desc.GetRotation()];
|
||||||
case PatchTables::GREGORY : return G;
|
case PatchTables::GREGORY : return G;
|
||||||
@ -76,6 +78,7 @@ struct PatchTypes {
|
|||||||
if (R[i]) ++result;
|
if (R[i]) ++result;
|
||||||
|
|
||||||
for (int j=0; j<4; ++j) {
|
for (int j=0; j<4; ++j) {
|
||||||
|
if (S[i][j]) ++result;
|
||||||
if (B[i][j]) ++result;
|
if (B[i][j]) ++result;
|
||||||
if (C[i][j]) ++result;
|
if (C[i][j]) ++result;
|
||||||
|
|
||||||
@ -85,10 +88,21 @@ struct PatchTypes {
|
|||||||
if (GB) ++result;
|
if (GB) ++result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if there's any single-crease patch
|
||||||
|
bool hasSingleCreasedPatches() const {
|
||||||
|
for (int i=0; i<6; ++i) {
|
||||||
|
for (int j=0; j<4; ++j) {
|
||||||
|
if (S[i][j]) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef PatchTypes<Index *> PatchCVPointers;
|
typedef PatchTypes<Index *> PatchCVPointers;
|
||||||
typedef PatchTypes<PatchParam *> PatchParamPointers;
|
typedef PatchTypes<PatchParam *> PatchParamPointers;
|
||||||
|
typedef PatchTypes<Index *> SharpnessIndexPointers;
|
||||||
typedef PatchTypes<int> PatchCounters;
|
typedef PatchTypes<int> PatchCounters;
|
||||||
typedef PatchTypes<Index **> PatchFVarPointers;
|
typedef PatchTypes<Index **> PatchFVarPointers;
|
||||||
|
|
||||||
@ -131,6 +145,7 @@ public:
|
|||||||
unsigned int _boundaryIndex : 2;
|
unsigned int _boundaryIndex : 2;
|
||||||
unsigned int _boundaryCount : 3;
|
unsigned int _boundaryCount : 3;
|
||||||
unsigned int _hasBoundaryEdge : 3;
|
unsigned int _hasBoundaryEdge : 3;
|
||||||
|
unsigned int _isSingleCrease : 1;
|
||||||
|
|
||||||
void clear() { std::memset(this, 0, sizeof(*this)); }
|
void clear() { std::memset(this, 0, sizeof(*this)); }
|
||||||
|
|
||||||
@ -251,6 +266,39 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assignTransitionRotationForSingleCrease(int transitionEdgeMask) {
|
||||||
|
//
|
||||||
|
// Single crease transition patches.
|
||||||
|
//
|
||||||
|
// rotate edgemask by boundaryIndex to align the creased edge
|
||||||
|
//
|
||||||
|
transitionEdgeMask = ((transitionEdgeMask >> _boundaryIndex) |
|
||||||
|
(transitionEdgeMask << (4-_boundaryIndex))) % 16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
edgemask type : rotation to match to shader
|
||||||
|
0000 0 : NONE : 0
|
||||||
|
0001 1 : ONE : 0
|
||||||
|
0010 2 : ONE : 3
|
||||||
|
0011 3 : TWO_ADJ : 3
|
||||||
|
0100 4 : ONE : 2
|
||||||
|
0101 5 : TWO_OPP : 0
|
||||||
|
0110 6 : TWO_ADJ : 2
|
||||||
|
0111 7 : THREE : 1 (needs verify)
|
||||||
|
1000 8 : ONE : 1
|
||||||
|
1001 9 : TWO_ADJ : 0
|
||||||
|
1010 10 : TWO_OPP : 1
|
||||||
|
1011 11 : THREE : 2 (needs verify)
|
||||||
|
1100 12 : TWO_ADJ : 1
|
||||||
|
1101 13 : THREE : 3
|
||||||
|
1110 14 : THREE : 0 (needs verify)
|
||||||
|
1111 15 : ALL : 0
|
||||||
|
*/
|
||||||
|
static int transitionRots[16] = {0, 0, 3, 3, 2, 0, 2, 1, 1, 0, 1, 2, 1, 3, 0, 0 };
|
||||||
|
|
||||||
|
_transitionRot = transitionRots[transitionEdgeMask];
|
||||||
|
}
|
||||||
|
|
||||||
void assignTransitionPropertiesFromEdgeMask(int transitionEdgeMask) {
|
void assignTransitionPropertiesFromEdgeMask(int transitionEdgeMask) {
|
||||||
//
|
//
|
||||||
// Note the transition rotations will be a function of the boundary rotations, and
|
// Note the transition rotations will be a function of the boundary rotations, and
|
||||||
@ -286,6 +334,8 @@ public:
|
|||||||
// results below are a function of both transition and boundary properties...
|
// results below are a function of both transition and boundary properties...
|
||||||
if (transitionEdgeMask == 0) {
|
if (transitionEdgeMask == 0) {
|
||||||
_transitionRot = 0;
|
_transitionRot = 0;
|
||||||
|
} else if (_boundaryCount == 0 and _isSingleCrease) {
|
||||||
|
assignTransitionRotationForSingleCrease(transitionEdgeMask);
|
||||||
} else if (_boundaryCount == 0) {
|
} else if (_boundaryCount == 0) {
|
||||||
// XXXX manuelk Rotations are mostly a direct map of the transitionEdgeMask
|
// XXXX manuelk Rotations are mostly a direct map of the transitionEdgeMask
|
||||||
// Except for:
|
// Except for:
|
||||||
@ -335,7 +385,7 @@ namespace {
|
|||||||
// Reserves tables based on the contents of the PatchArrayVector in the PatchTables:
|
// Reserves tables based on the contents of the PatchArrayVector in the PatchTables:
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
PatchTablesFactory::allocateTables(PatchTables * tables, int /* nlevels */) {
|
PatchTablesFactory::allocateTables(PatchTables * tables, int /* nlevels */, bool hasSharpness) {
|
||||||
|
|
||||||
PatchTables::PatchArrayVector const & parrays = tables->GetPatchArrayVector();
|
PatchTables::PatchArrayVector const & parrays = tables->GetPatchArrayVector();
|
||||||
|
|
||||||
@ -352,6 +402,10 @@ PatchTablesFactory::allocateTables(PatchTables * tables, int /* nlevels */) {
|
|||||||
tables->_patches.resize( nverts );
|
tables->_patches.resize( nverts );
|
||||||
|
|
||||||
tables->_paramTable.resize( npatches );
|
tables->_paramTable.resize( npatches );
|
||||||
|
|
||||||
|
if (hasSharpness) {
|
||||||
|
tables->_sharpnessIndexTable.resize( npatches );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchTables::FVarPatchTables *
|
PatchTables::FVarPatchTables *
|
||||||
@ -517,6 +571,20 @@ PatchTablesFactory::getQuadOffsets(Vtr::Level const& level, Vtr::Index fIndex, I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Indexing sharpnesses
|
||||||
|
//
|
||||||
|
int
|
||||||
|
PatchTablesFactory::assignSharpnessIndex( PatchTables *tables, float sharpness ) {
|
||||||
|
|
||||||
|
// linear search
|
||||||
|
for (int i=0; i<(int)tables->_sharpnessValues.size(); ++i) {
|
||||||
|
if (tables->_sharpnessValues[i] == sharpness) return i;
|
||||||
|
}
|
||||||
|
tables->_sharpnessValues.push_back(sharpness);
|
||||||
|
return (int)tables->_sharpnessValues.size()-1;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// We should be able to use a single Create() method for both the adaptive and uniform
|
// We should be able to use a single Create() method for both the adaptive and uniform
|
||||||
// cases. In the past, more additional arguments were passed to the uniform version,
|
// cases. In the past, more additional arguments were passed to the uniform version,
|
||||||
@ -606,7 +674,7 @@ PatchTablesFactory::createUniform( TopologyRefiner const & refiner, Options opti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate various tables
|
// Allocate various tables
|
||||||
allocateTables( tables, 0 );
|
allocateTables( tables, 0, /*hasSharpness=*/false );
|
||||||
|
|
||||||
if (options.generateFVarTables) {
|
if (options.generateFVarTables) {
|
||||||
tables->_fvarPatchTables = allocateFVarTables( refiner, *tables, options );
|
tables->_fvarPatchTables = allocateFVarTables( refiner, *tables, options );
|
||||||
@ -701,7 +769,7 @@ PatchTablesFactory::createAdaptive( TopologyRefiner const & refiner, Options opt
|
|||||||
PatchCounters patchInventory;
|
PatchCounters patchInventory;
|
||||||
std::vector<PatchFaceTag> patchTags;
|
std::vector<PatchFaceTag> patchTags;
|
||||||
|
|
||||||
identifyAdaptivePatches(refiner, patchInventory, patchTags);
|
identifyAdaptivePatches(refiner, patchInventory, patchTags, options);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create the instance of the tables and allocate and initialize its members based on
|
// Create the instance of the tables and allocate and initialize its members based on
|
||||||
@ -729,7 +797,8 @@ PatchTablesFactory::createAdaptive( TopologyRefiner const & refiner, Options opt
|
|||||||
tables->_numPtexFaces = refiner.GetNumPtexFaces();
|
tables->_numPtexFaces = refiner.GetNumPtexFaces();
|
||||||
|
|
||||||
// Allocate various tables
|
// Allocate various tables
|
||||||
allocateTables( tables, 0 );
|
bool hasSharpness = patchInventory.hasSingleCreasedPatches();
|
||||||
|
allocateTables( tables, 0, hasSharpness );
|
||||||
|
|
||||||
if (options.generateFVarTables) {
|
if (options.generateFVarTables) {
|
||||||
tables->_fvarPatchTables = allocateFVarTables( refiner, *tables, options );
|
tables->_fvarPatchTables = allocateFVarTables( refiner, *tables, options );
|
||||||
@ -743,7 +812,7 @@ PatchTablesFactory::createAdaptive( TopologyRefiner const & refiner, Options opt
|
|||||||
//
|
//
|
||||||
// Now populate the patches:
|
// Now populate the patches:
|
||||||
//
|
//
|
||||||
populateAdaptivePatches(refiner, patchInventory, patchTags, tables);
|
populateAdaptivePatches(refiner, patchInventory, patchTags, tables, options);
|
||||||
|
|
||||||
return tables;
|
return tables;
|
||||||
}
|
}
|
||||||
@ -755,9 +824,9 @@ PatchTablesFactory::createAdaptive( TopologyRefiner const & refiner, Options opt
|
|||||||
//
|
//
|
||||||
void
|
void
|
||||||
PatchTablesFactory::identifyAdaptivePatches( TopologyRefiner const & refiner,
|
PatchTablesFactory::identifyAdaptivePatches( TopologyRefiner const & refiner,
|
||||||
PatchCounters & patchInventory,
|
PatchCounters & patchInventory,
|
||||||
PatchTagVector & patchTags ) {
|
PatchTagVector & patchTags,
|
||||||
|
Options options ) {
|
||||||
//
|
//
|
||||||
// Iterate through the levels of refinement to inspect and tag components with information
|
// Iterate through the levels of refinement to inspect and tag components with information
|
||||||
// relative to patch generation. We allocate all of the tags locally and use them to
|
// relative to patch generation. We allocate all of the tags locally and use them to
|
||||||
@ -866,6 +935,24 @@ PatchTablesFactory::identifyAdaptivePatches( TopologyRefiner const & refiner,
|
|||||||
int boundaryEdgeMask = 0;
|
int boundaryEdgeMask = 0;
|
||||||
|
|
||||||
bool hasBoundaryVertex = compFaceVertTag._boundary;
|
bool hasBoundaryVertex = compFaceVertTag._boundary;
|
||||||
|
|
||||||
|
// single crease patch optimization
|
||||||
|
if (options.useSingleCreasePatch and
|
||||||
|
!compFaceVertTag._xordinary and compFaceVertTag._semiSharp and not hasBoundaryVertex) {
|
||||||
|
|
||||||
|
float sharpness = 0;
|
||||||
|
int rotation = 0;
|
||||||
|
if (level->isSingleCreasePatch(faceIndex, &sharpness, &rotation)) {
|
||||||
|
|
||||||
|
// cap sharpness to the max isolation level
|
||||||
|
float cappedSharpness = std::min(sharpness, (float)(options.maxIsolationLevel-i));
|
||||||
|
if (cappedSharpness > 0) {
|
||||||
|
patchTag._isSingleCrease = true;
|
||||||
|
patchTag._boundaryIndex = (rotation + 2) % 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hasBoundaryVertex) {
|
if (hasBoundaryVertex) {
|
||||||
Vtr::IndexArray const& fEdges = level->getFaceEdges(faceIndex);
|
Vtr::IndexArray const& fEdges = level->getFaceEdges(faceIndex);
|
||||||
|
|
||||||
@ -924,8 +1011,10 @@ PatchTablesFactory::identifyAdaptivePatches( TopologyRefiner const & refiner,
|
|||||||
int transIndex = patchTag._transitionType;
|
int transIndex = patchTag._transitionType;
|
||||||
int transRot = patchTag._transitionRot;
|
int transRot = patchTag._transitionRot;
|
||||||
|
|
||||||
if (patchTag._boundaryCount == 0) {
|
if (!patchTag._isSingleCrease && patchTag._boundaryCount == 0) {
|
||||||
patchInventory.R[transIndex]++;
|
patchInventory.R[transIndex]++;
|
||||||
|
} else if (patchTag._isSingleCrease && patchTag._boundaryCount == 0) {
|
||||||
|
patchInventory.S[transIndex][transRot]++;
|
||||||
} else if (patchTag._boundaryCount == 1) {
|
} else if (patchTag._boundaryCount == 1) {
|
||||||
patchInventory.B[transIndex][transRot]++;
|
patchInventory.B[transIndex][transRot]++;
|
||||||
} else {
|
} else {
|
||||||
@ -952,7 +1041,8 @@ void
|
|||||||
PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
||||||
PatchCounters const & patchInventory,
|
PatchCounters const & patchInventory,
|
||||||
PatchTagVector const & patchTags,
|
PatchTagVector const & patchTags,
|
||||||
PatchTables * tables ) {
|
PatchTables * tables,
|
||||||
|
Options options ) {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Setup convenience pointers at the beginning of each patch array for each
|
// Setup convenience pointers at the beginning of each patch array for each
|
||||||
@ -961,6 +1051,7 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
|||||||
PatchCVPointers iptrs;
|
PatchCVPointers iptrs;
|
||||||
PatchParamPointers pptrs;
|
PatchParamPointers pptrs;
|
||||||
PatchFVarPointers fptrs;
|
PatchFVarPointers fptrs;
|
||||||
|
SharpnessIndexPointers sptrs;
|
||||||
|
|
||||||
typedef PatchTables::DescriptorVector DescVec;
|
typedef PatchTables::DescriptorVector DescVec;
|
||||||
|
|
||||||
@ -974,6 +1065,9 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
|||||||
|
|
||||||
iptrs.getValue( *it ) = &tables->_patches[pa->GetVertIndex()];
|
iptrs.getValue( *it ) = &tables->_patches[pa->GetVertIndex()];
|
||||||
pptrs.getValue( *it ) = &tables->_paramTable[pa->GetPatchIndex()];
|
pptrs.getValue( *it ) = &tables->_paramTable[pa->GetPatchIndex()];
|
||||||
|
if (patchInventory.hasSingleCreasedPatches()) {
|
||||||
|
sptrs.getValue( *it ) = &tables->_sharpnessIndexTable[pa->GetPatchIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
if (tables->_fvarPatchTables) {
|
if (tables->_fvarPatchTables) {
|
||||||
int nchannels = refiner.GetNumFVarChannels(),
|
int nchannels = refiner.GetNumFVarChannels(),
|
||||||
@ -1031,7 +1125,7 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
|||||||
int rIndex = patchTag._transitionRot;
|
int rIndex = patchTag._transitionRot;
|
||||||
int bIndex = patchTag._boundaryIndex;
|
int bIndex = patchTag._boundaryIndex;
|
||||||
|
|
||||||
if (patchTag._boundaryCount == 0) {
|
if (!patchTag._isSingleCrease && patchTag._boundaryCount == 0) {
|
||||||
int const permuteInterior[16] = { 5, 6, 7, 8, 4, 0, 1, 9, 15, 3, 2, 10, 14, 13, 12, 11 };
|
int const permuteInterior[16] = { 5, 6, 7, 8, 4, 0, 1, 9, 15, 3, 2, 10, 14, 13, 12, 11 };
|
||||||
|
|
||||||
level->gatherQuadRegularInteriorPatchVertices(faceIndex, patchVerts, rIndex);
|
level->gatherQuadRegularInteriorPatchVertices(faceIndex, patchVerts, rIndex);
|
||||||
@ -1063,7 +1157,23 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
|||||||
// It may be that a separate "face rotation" flag is warranted if we need something
|
// It may be that a separate "face rotation" flag is warranted if we need something
|
||||||
// else dependent on the boundary orientation.
|
// else dependent on the boundary orientation.
|
||||||
//
|
//
|
||||||
if (patchTag._boundaryCount == 1) {
|
if (patchTag._isSingleCrease && patchTag._boundaryCount==0) {
|
||||||
|
int const permuteInterior[16] = { 5, 6, 7, 8, 4, 0, 1, 9, 15, 3, 2, 10, 14, 13, 12, 11 };
|
||||||
|
level->gatherQuadRegularInteriorPatchVertices(faceIndex, patchVerts, bIndex);
|
||||||
|
offsetAndPermuteIndices(patchVerts, 16, levelVertOffset, permuteInterior, iptrs.S[tIndex][rIndex]);
|
||||||
|
|
||||||
|
int creaseEdge = (bIndex+2)%4;
|
||||||
|
float sharpness = level->getEdgeSharpness((level->getFaceEdges(faceIndex)[creaseEdge]));
|
||||||
|
sharpness = std::min(sharpness, (float)(options.maxIsolationLevel-i));
|
||||||
|
|
||||||
|
iptrs.S[tIndex][rIndex] += 16;
|
||||||
|
pptrs.S[tIndex][rIndex] = computePatchParam(refiner, i, faceIndex, rIndex, pptrs.S[tIndex][rIndex]);
|
||||||
|
*sptrs.S[tIndex][rIndex]++ = assignSharpnessIndex(tables, sharpness);
|
||||||
|
|
||||||
|
if (tables->_fvarPatchTables) {
|
||||||
|
gatherFVarPatchVertices(refiner, i, faceIndex, rIndex, levelFVarVertOffsets, fptrs.S[tIndex][rIndex]);
|
||||||
|
}
|
||||||
|
} else if (patchTag._boundaryCount == 1) {
|
||||||
int const permuteBoundary[12] = { 11, 3, 0, 4, 10, 2, 1, 5, 9, 8, 7, 6 };
|
int const permuteBoundary[12] = { 11, 3, 0, 4, 10, 2, 1, 5, 9, 8, 7, 6 };
|
||||||
|
|
||||||
level->gatherQuadRegularBoundaryPatchVertices(faceIndex, patchVerts, bIndex);
|
level->gatherQuadRegularBoundaryPatchVertices(faceIndex, patchVerts, bIndex);
|
||||||
|
@ -53,13 +53,18 @@ public:
|
|||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
|
|
||||||
Options() : generateAllLevels(false),
|
Options(unsigned int maxIsolationLevel=10) : generateAllLevels(false),
|
||||||
triangulateQuads(false),
|
triangulateQuads(false),
|
||||||
generateFVarTables(false) { }
|
generateFVarTables(false),
|
||||||
|
useSingleCreasePatch(false),
|
||||||
|
maxIsolationLevel(maxIsolationLevel)
|
||||||
|
{ }
|
||||||
|
|
||||||
unsigned int generateAllLevels : 1, ///< Include levels from 'firstLevel' to 'maxLevel' (Uniform mode only)
|
unsigned int generateAllLevels : 1, ///< Include levels from 'firstLevel' to 'maxLevel' (Uniform mode only)
|
||||||
triangulateQuads : 1, ///< Triangulate 'QUADS' primitives (Uniform mode only)
|
triangulateQuads : 1, ///< Triangulate 'QUADS' primitives (Uniform mode only)
|
||||||
generateFVarTables : 1; ///< Generate face-varying patch tables
|
generateFVarTables : 1, ///< Generate face-varying patch tables
|
||||||
|
useSingleCreasePatch : 1, ///< Use single crease patch
|
||||||
|
maxIsolationLevel : 4; ///< Cap the sharpnness of single creased patches to be consistent to other feature isolations.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Factory constructor for PatchTables
|
/// \brief Factory constructor for PatchTables
|
||||||
@ -84,15 +89,17 @@ private:
|
|||||||
// High-level methods for identifying and populating patches associated with faces:
|
// High-level methods for identifying and populating patches associated with faces:
|
||||||
static void identifyAdaptivePatches( TopologyRefiner const & refiner,
|
static void identifyAdaptivePatches( TopologyRefiner const & refiner,
|
||||||
PatchTypes<int> & patchInventory,
|
PatchTypes<int> & patchInventory,
|
||||||
std::vector<PatchFaceTag> & patchTags);
|
std::vector<PatchFaceTag> & patchTags,
|
||||||
|
Options options );
|
||||||
|
|
||||||
static void populateAdaptivePatches( TopologyRefiner const & refiner,
|
static void populateAdaptivePatches( TopologyRefiner const & refiner,
|
||||||
PatchTypes<int> const & patchInventory,
|
PatchTypes<int> const & patchInventory,
|
||||||
std::vector<PatchFaceTag> const & patchTags,
|
std::vector<PatchFaceTag> const & patchTags,
|
||||||
PatchTables * tables);
|
PatchTables * tables,
|
||||||
|
Options options );
|
||||||
|
|
||||||
// Methods for allocating and managing the patch table data arrays:
|
// Methods for allocating and managing the patch table data arrays:
|
||||||
static void allocateTables( PatchTables * tables, int nlevels );
|
static void allocateTables( PatchTables * tables, int nlevels, bool hasSharpness );
|
||||||
|
|
||||||
static FVarPatchTables * allocateFVarTables( TopologyRefiner const & refiner,
|
static FVarPatchTables * allocateFVarTables( TopologyRefiner const & refiner,
|
||||||
PatchTables const & tables,
|
PatchTables const & tables,
|
||||||
@ -103,10 +110,12 @@ private:
|
|||||||
int npatches, int * voffset, int * poffset, int * qoffset );
|
int npatches, int * voffset, int * poffset, int * qoffset );
|
||||||
|
|
||||||
static PatchParam * computePatchParam( TopologyRefiner const & refiner, int level,
|
static PatchParam * computePatchParam( TopologyRefiner const & refiner, int level,
|
||||||
int face, int rotation, PatchParam * coord );
|
int face, int rotation, PatchParam * coord );
|
||||||
|
|
||||||
static void getQuadOffsets(Vtr::Level const & level, int face, Index * result);
|
static void getQuadOffsets(Vtr::Level const & level, int face, Index * result);
|
||||||
|
|
||||||
|
static int assignSharpnessIndex( PatchTables *tables, float sharpness );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ TopologyRefiner::TopologyRefiner(Sdc::Type schemeType, Sdc::Options schemeOption
|
|||||||
_subdivType(schemeType),
|
_subdivType(schemeType),
|
||||||
_subdivOptions(schemeOptions),
|
_subdivOptions(schemeOptions),
|
||||||
_isUniform(true),
|
_isUniform(true),
|
||||||
_maxLevel(0) {
|
_maxLevel(0),
|
||||||
|
_useSingleCreasePatch(false) {
|
||||||
|
|
||||||
// Need to revisit allocation scheme here -- want to use smart-ptrs for these
|
// Need to revisit allocation scheme here -- want to use smart-ptrs for these
|
||||||
// but will probably have to settle for explicit new/delete...
|
// but will probably have to settle for explicit new/delete...
|
||||||
@ -318,7 +319,7 @@ TopologyRefiner::RefineUniform(int maxLevel, bool fullTopology) {
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TopologyRefiner::RefineAdaptive(int subdivLevel, bool fullTopology) {
|
TopologyRefiner::RefineAdaptive(int subdivLevel, bool fullTopology, bool useSingleCreasePatch) {
|
||||||
|
|
||||||
assert(_levels[0].getNumVertices() > 0); // Make sure the base level has been initialized
|
assert(_levels[0].getNumVertices() > 0); // Make sure the base level has been initialized
|
||||||
assert(_subdivType == Sdc::TYPE_CATMARK);
|
assert(_subdivType == Sdc::TYPE_CATMARK);
|
||||||
@ -328,6 +329,7 @@ TopologyRefiner::RefineAdaptive(int subdivLevel, bool fullTopology) {
|
|||||||
//
|
//
|
||||||
_isUniform = false;
|
_isUniform = false;
|
||||||
_maxLevel = subdivLevel;
|
_maxLevel = subdivLevel;
|
||||||
|
_useSingleCreasePatch = useSingleCreasePatch;
|
||||||
|
|
||||||
// Should we presize all or grow one at a time as needed?
|
// Should we presize all or grow one at a time as needed?
|
||||||
_levels.resize(subdivLevel + 1);
|
_levels.resize(subdivLevel + 1);
|
||||||
@ -435,7 +437,7 @@ TopologyRefiner::catmarkFeatureAdaptiveSelector(Vtr::SparseSelector& selector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool selectFace = false;
|
bool selectFace = false;
|
||||||
if (compFaceTag._xordinary || compFaceTag._semiSharp) {
|
if (compFaceTag._xordinary) {
|
||||||
selectFace = true;
|
selectFace = true;
|
||||||
} else if (compFaceTag._rule & Sdc::Crease::RULE_DART) {
|
} else if (compFaceTag._rule & Sdc::Crease::RULE_DART) {
|
||||||
// Get this case out of the way before testing hard features
|
// Get this case out of the way before testing hard features
|
||||||
@ -449,6 +451,15 @@ TopologyRefiner::catmarkFeatureAdaptiveSelector(Vtr::SparseSelector& selector) {
|
|||||||
// though some may be regular patches, this currently warrants isolation as we only
|
// though some may be regular patches, this currently warrants isolation as we only
|
||||||
// support regular patches with one corner or one boundary.
|
// support regular patches with one corner or one boundary.
|
||||||
selectFace = true;
|
selectFace = true;
|
||||||
|
} else if (compFaceTag._semiSharp) {
|
||||||
|
// if this is regular and the adjacent edges have same sharpness
|
||||||
|
// and no vertex corner sharpness,
|
||||||
|
// we can stop refinning and use single-crease patch.
|
||||||
|
if (_useSingleCreasePatch) {
|
||||||
|
selectFace = ! level.isSingleCreasePatch(face);
|
||||||
|
} else {
|
||||||
|
selectFace = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// This leaves us with at least one Smooth vertex (and so two smooth adjacent edges
|
// This leaves us with at least one Smooth vertex (and so two smooth adjacent edges
|
||||||
// of the quad) and the rest hard Creases or Corners. This includes the regular
|
// of the quad) and the rest hard Creases or Corners. This includes the regular
|
||||||
|
@ -114,7 +114,9 @@ public:
|
|||||||
/// @param fullTopologyInLastLevel Skip secondary topological relationships
|
/// @param fullTopologyInLastLevel Skip secondary topological relationships
|
||||||
/// at the highest level of refinement.
|
/// at the highest level of refinement.
|
||||||
///
|
///
|
||||||
void RefineAdaptive(int maxLevel, bool fullTopologyInLastLevel = false);
|
/// @param useSingleCreasePatch Use single crease patch and stop isolation if it's applicable
|
||||||
|
///
|
||||||
|
void RefineAdaptive(int maxLevel, bool fullTopologyInLastLevel = false, bool useSingleCreasePatch = false);
|
||||||
|
|
||||||
/// \brief Unrefine the topology (keep control cage)
|
/// \brief Unrefine the topology (keep control cage)
|
||||||
void Unrefine();
|
void Unrefine();
|
||||||
@ -496,6 +498,7 @@ private:
|
|||||||
|
|
||||||
bool _isUniform;
|
bool _isUniform;
|
||||||
int _maxLevel;
|
int _maxLevel;
|
||||||
|
bool _useSingleCreasePatch;
|
||||||
|
|
||||||
std::vector<Vtr::Level> _levels;
|
std::vector<Vtr::Level> _levels;
|
||||||
std::vector<Vtr::Refinement> _refinements;
|
std::vector<Vtr::Refinement> _refinements;
|
||||||
|
@ -167,8 +167,27 @@ GLDrawContext::create(Far::PatchTables const & patchTables, int numVertexElement
|
|||||||
Far::PatchTables::PatchParamTable const &
|
Far::PatchTables::PatchParamTable const &
|
||||||
patchParamTables = patchTables.GetPatchParamTable();
|
patchParamTables = patchTables.GetPatchParamTable();
|
||||||
|
|
||||||
if (not patchParamTables.empty())
|
if (not patchParamTables.empty()) {
|
||||||
_patchParamTextureBuffer = createTextureBuffer(patchParamTables, GL_RG32I);
|
std::vector<int> const &sharpnessIndexTable = patchTables.GetSharpnessIndexTable();
|
||||||
|
if (sharpnessIndexTable.empty()) {
|
||||||
|
_patchParamTextureBuffer = createTextureBuffer(patchParamTables, GL_RG32I);
|
||||||
|
} else {
|
||||||
|
// if indexed sharpnesses exists, flatten them and interleave into 3-component buffer
|
||||||
|
std::vector<float> const &sharpnessValues = patchTables.GetSharpnessValues();
|
||||||
|
size_t nPatches = patchParamTables.size();
|
||||||
|
// PatchParam = sizeof(int)*2, 1 float for sharpness
|
||||||
|
std::vector<unsigned int> buffer(nPatches * 3);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nPatches; ++i) {
|
||||||
|
float sharpness = sharpnessValues[sharpnessIndexTable[i]];
|
||||||
|
buffer[i*3+0] = patchParamTables[i].faceIndex;
|
||||||
|
buffer[i*3+1] = patchParamTables[i].bitField.field;
|
||||||
|
buffer[i*3+2] = *((unsigned int *)&sharpness);
|
||||||
|
}
|
||||||
|
|
||||||
|
_patchParamTextureBuffer = createTextureBuffer(buffer, GL_RGB32I);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
glBindBuffer(GL_TEXTURE_BUFFER, 0);
|
||||||
#endif
|
#endif
|
||||||
|
@ -94,6 +94,19 @@ GLDrawRegistryBase::_CreateDrawSourceConfig(
|
|||||||
sconfig->tessEvalShader.version = "#version 410\n";
|
sconfig->tessEvalShader.version = "#version 410\n";
|
||||||
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
|
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
|
||||||
break;
|
break;
|
||||||
|
case Far::PatchTables::SINGLE_CREASE:
|
||||||
|
sconfig->vertexShader.source = bsplineShaderSource;
|
||||||
|
sconfig->vertexShader.version = "#version 410\n";
|
||||||
|
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_BSPLINE_SHADER");
|
||||||
|
sconfig->tessControlShader.source = bsplineShaderSource;
|
||||||
|
sconfig->tessControlShader.version = "#version 410\n";
|
||||||
|
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER");
|
||||||
|
sconfig->tessControlShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
|
||||||
|
sconfig->tessEvalShader.source = bsplineShaderSource;
|
||||||
|
sconfig->tessEvalShader.version = "#version 410\n";
|
||||||
|
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
|
||||||
|
sconfig->tessEvalShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
|
||||||
|
break;
|
||||||
case Far::PatchTables::BOUNDARY:
|
case Far::PatchTables::BOUNDARY:
|
||||||
sconfig->vertexShader.source = bsplineShaderSource;
|
sconfig->vertexShader.source = bsplineShaderSource;
|
||||||
sconfig->vertexShader.version = "#version 410\n";
|
sconfig->vertexShader.version = "#version 410\n";
|
||||||
@ -176,7 +189,10 @@ GLDrawRegistryBase::_CreateDrawSourceConfig(
|
|||||||
sconfig->tessControlShader.AddDefine("OSD_TRANSITION_ROTATE", ss.str());
|
sconfig->tessControlShader.AddDefine("OSD_TRANSITION_ROTATE", ss.str());
|
||||||
sconfig->tessEvalShader.AddDefine("OSD_TRANSITION_ROTATE", ss.str());
|
sconfig->tessEvalShader.AddDefine("OSD_TRANSITION_ROTATE", ss.str());
|
||||||
|
|
||||||
if (desc.GetType() == Far::PatchTables::BOUNDARY) {
|
if (desc.GetType() == Far::PatchTables::SINGLE_CREASE) {
|
||||||
|
sconfig->tessControlShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
|
||||||
|
sconfig->tessEvalShader.AddDefine("OSD_PATCH_SINGLE_CREASE");
|
||||||
|
} else if (desc.GetType() == Far::PatchTables::BOUNDARY) {
|
||||||
sconfig->tessControlShader.AddDefine("OSD_PATCH_BOUNDARY");
|
sconfig->tessControlShader.AddDefine("OSD_PATCH_BOUNDARY");
|
||||||
} else if (desc.GetType() == Far::PatchTables::CORNER) {
|
} else if (desc.GetType() == Far::PatchTables::CORNER) {
|
||||||
sconfig->tessControlShader.AddDefine("OSD_PATCH_CORNER");
|
sconfig->tessControlShader.AddDefine("OSD_PATCH_CORNER");
|
||||||
|
@ -68,14 +68,14 @@ public:
|
|||||||
_drawContext(0)
|
_drawContext(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive));
|
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
|
||||||
|
|
||||||
int numElements =
|
int numElements =
|
||||||
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
|
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
|
||||||
|
|
||||||
initializeComputeContext(numVertexElements, numVaryingElements);
|
initializeComputeContext(numVertexElements, numVaryingElements);
|
||||||
|
|
||||||
initializeDrawContext(numElements, bits);
|
initializeDrawContext(numElements, level, bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh(ComputeController * computeController,
|
Mesh(ComputeController * computeController,
|
||||||
@ -201,12 +201,13 @@ private:
|
|||||||
delete varyingStencils;
|
delete varyingStencils;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeDrawContext(int numElements, MeshBitset bits) {
|
void initializeDrawContext(int numElements, int level, MeshBitset bits) {
|
||||||
|
|
||||||
assert(_refiner and _vertexBuffer);
|
assert(_refiner and _vertexBuffer);
|
||||||
|
|
||||||
Far::PatchTablesFactory::Options options;
|
Far::PatchTablesFactory::Options options(level);
|
||||||
options.generateFVarTables = bits.test(MeshFVarData);
|
options.generateFVarTables = bits.test(MeshFVarData);
|
||||||
|
options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
|
||||||
|
|
||||||
_patchTables = Far::PatchTablesFactory::Create(*_refiner, options);
|
_patchTables = Far::PatchTablesFactory::Create(*_refiner, options);
|
||||||
|
|
||||||
@ -279,7 +280,7 @@ public:
|
|||||||
{
|
{
|
||||||
assert(_refiner);
|
assert(_refiner);
|
||||||
|
|
||||||
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive));
|
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
|
||||||
|
|
||||||
int numElements =
|
int numElements =
|
||||||
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
|
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
|
||||||
|
@ -57,6 +57,14 @@ uniform mat4 Q = mat4(
|
|||||||
0.f, 1.f/6.f, 4.f/6.f, 1.f/6.f
|
0.f, 1.f/6.f, 4.f/6.f, 1.f/6.f
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Infinite sharp
|
||||||
|
uniform mat4 Mi = mat4(
|
||||||
|
1.f/6.f, 4.f/6.f, 1.f/6.f, 0.f,
|
||||||
|
0.f, 4.f/6.f, 2.f/6.f, 0.f,
|
||||||
|
0.f, 2.f/6.f, 4.f/6.f, 0.f,
|
||||||
|
0.f, 0.f, 1.f, 0.f
|
||||||
|
);
|
||||||
|
|
||||||
// Boundary / Corner
|
// Boundary / Corner
|
||||||
uniform mat4x3 B = mat4x3(
|
uniform mat4x3 B = mat4x3(
|
||||||
1.f, 0.f, 0.f,
|
1.f, 0.f, 0.f,
|
||||||
@ -74,11 +82,34 @@ in block {
|
|||||||
|
|
||||||
out block {
|
out block {
|
||||||
ControlVertex v;
|
ControlVertex v;
|
||||||
|
vec4 P1;
|
||||||
|
vec4 P2;
|
||||||
|
float sharpness;
|
||||||
OSD_USER_VARYING_DECLARE
|
OSD_USER_VARYING_DECLARE
|
||||||
} outpt[];
|
} outpt[];
|
||||||
|
|
||||||
#define ID gl_InvocationID
|
#define ID gl_InvocationID
|
||||||
|
|
||||||
|
// compute single-crease patch matrix
|
||||||
|
mat4
|
||||||
|
ComputeMatrixSimplified(float sharpness)
|
||||||
|
{
|
||||||
|
float s = pow(2.0f, sharpness);
|
||||||
|
float s2 = s*s;
|
||||||
|
float s3 = s2*s;
|
||||||
|
|
||||||
|
mat4 m = mat4(
|
||||||
|
0, s + 1 + 3*s2 - s3, 7*s - 2 - 6*s2 + 2*s3, (1-s)*(s-1)*(s-1),
|
||||||
|
0, (1+s)*(1+s), 6*s - 2 - 2*s2, (s-1)*(s-1),
|
||||||
|
0, 1+s, 6*s - 2, 1-s,
|
||||||
|
0, 1, 6*s - 2, 1);
|
||||||
|
|
||||||
|
m /= (s*6.0);
|
||||||
|
m[0][0] = 1.0/6.0;
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
int i = ID%4;
|
int i = ID%4;
|
||||||
@ -98,6 +129,8 @@ void main()
|
|||||||
pos += B[j][k]*H[k];
|
pos += B[j][k]*H[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outpt[ID].v.position = vec4(pos, 1.0);
|
||||||
|
|
||||||
#elif defined OSD_PATCH_CORNER
|
#elif defined OSD_PATCH_CORNER
|
||||||
vec3 H[3];
|
vec3 H[3];
|
||||||
for (int l=0; l<3; ++l) {
|
for (int l=0; l<3; ++l) {
|
||||||
@ -112,6 +145,8 @@ void main()
|
|||||||
pos += B[j][k]*H[k];
|
pos += B[j][k]*H[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outpt[ID].v.position = vec4(pos, 1.0);
|
||||||
|
|
||||||
#else // not OSD_PATCH_BOUNDARY, not OSD_PATCH_CORNER
|
#else // not OSD_PATCH_BOUNDARY, not OSD_PATCH_CORNER
|
||||||
vec3 H[4];
|
vec3 H[4];
|
||||||
for (int l=0; l<4; ++l) {
|
for (int l=0; l<4; ++l) {
|
||||||
@ -121,14 +156,39 @@ void main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined OSD_PATCH_SINGLE_CREASE
|
||||||
|
float sharpness = GetSharpness();
|
||||||
|
float Sf = floor(sharpness);
|
||||||
|
float Sc = ceil(sharpness);
|
||||||
|
float Sr = fract(sharpness);
|
||||||
|
mat4 Mf = ComputeMatrixSimplified(Sf);
|
||||||
|
mat4 Mc = ComputeMatrixSimplified(Sc);
|
||||||
|
mat4 Mj = (1-Sr) * Mf + Sr * Mi;
|
||||||
|
mat4 Ms = (1-Sr) * Mf + Sr * Mc;
|
||||||
|
|
||||||
|
vec3 P = vec3(0);
|
||||||
|
vec3 P1 = vec3(0);
|
||||||
|
vec3 P2 = vec3(0);
|
||||||
|
for (int k=0; k<4; ++k) {
|
||||||
|
P += Mi[j][k]*H[k]; // 0 to 1-2^(-Sf)
|
||||||
|
P1 += Mj[j][k]*H[k]; // 1-2^(-Sf) to 1-2^(-Sc)
|
||||||
|
P2 += Ms[j][k]*H[k]; // 1-2^(-Sc) to 1
|
||||||
|
}
|
||||||
|
outpt[ID].v.position = vec4(P, 1.0);
|
||||||
|
outpt[ID].P1 = vec4(P1, 1.0);
|
||||||
|
outpt[ID].P2 = vec4(P2, 1.0);
|
||||||
|
outpt[ID].sharpness = sharpness;
|
||||||
|
|
||||||
|
#else // REGULAR
|
||||||
vec3 pos = vec3(0,0,0);
|
vec3 pos = vec3(0,0,0);
|
||||||
for (int k=0; k<4; ++k) {
|
for (int k=0; k<4; ++k) {
|
||||||
pos += Q[j][k]*H[k];
|
pos += Q[j][k]*H[k];
|
||||||
}
|
}
|
||||||
|
outpt[ID].v.position = vec4(pos, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
outpt[ID].v.position = vec4(pos, 1.0);
|
|
||||||
|
|
||||||
#if defined OSD_PATCH_BOUNDARY
|
#if defined OSD_PATCH_BOUNDARY
|
||||||
const int p[16] = int[]( 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 );
|
const int p[16] = int[]( 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 );
|
||||||
@ -215,6 +275,9 @@ void main()
|
|||||||
|
|
||||||
in block {
|
in block {
|
||||||
ControlVertex v;
|
ControlVertex v;
|
||||||
|
vec4 P1;
|
||||||
|
vec4 P2;
|
||||||
|
float sharpness;
|
||||||
OSD_USER_VARYING_DECLARE
|
OSD_USER_VARYING_DECLARE
|
||||||
} inpt[];
|
} inpt[];
|
||||||
|
|
||||||
@ -244,8 +307,35 @@ void main()
|
|||||||
Univar4x4(UV.x, B, D);
|
Univar4x4(UV.x, B, D);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined OSD_PATCH_SINGLE_CREASE
|
||||||
|
float sharpness = inpt[0].sharpness;
|
||||||
|
float s0 = 1.0 - pow(2.0f, -floor(sharpness));
|
||||||
|
float s1 = 1.0 - pow(2.0f, -ceil(sharpness));
|
||||||
|
#endif
|
||||||
|
|
||||||
for (int i=0; i<4; ++i) {
|
for (int i=0; i<4; ++i) {
|
||||||
for (int j=0; j<4; ++j) {
|
for (int j=0; j<4; ++j) {
|
||||||
|
#if defined OSD_PATCH_SINGLE_CREASE
|
||||||
|
#if OSD_TRANSITION_ROTATE == 1
|
||||||
|
int k = 4*(3-j) + i;
|
||||||
|
float s = 1-UV.x;
|
||||||
|
#elif OSD_TRANSITION_ROTATE == 2
|
||||||
|
int k = 4*(3-i) + (3-j);
|
||||||
|
float s = 1-UV.y;
|
||||||
|
#elif OSD_TRANSITION_ROTATE == 3
|
||||||
|
int k = 4*j + (3-i);
|
||||||
|
float s = UV.x;
|
||||||
|
#else // ROTATE=0 or non-transition
|
||||||
|
int k = 4*i + j;
|
||||||
|
float s = UV.y;
|
||||||
|
#endif
|
||||||
|
vec3 A = (s < s0) ?
|
||||||
|
inpt[k].v.position.xyz :
|
||||||
|
((s < s1) ?
|
||||||
|
inpt[k].P1.xyz :
|
||||||
|
inpt[k].P2.xyz);
|
||||||
|
|
||||||
|
#else // !SINGLE_CREASE
|
||||||
#if OSD_TRANSITION_ROTATE == 1
|
#if OSD_TRANSITION_ROTATE == 1
|
||||||
vec3 A = inpt[4*(3-j) + i].v.position.xyz;
|
vec3 A = inpt[4*(3-j) + i].v.position.xyz;
|
||||||
#elif OSD_TRANSITION_ROTATE == 2
|
#elif OSD_TRANSITION_ROTATE == 2
|
||||||
@ -254,6 +344,7 @@ void main()
|
|||||||
vec3 A = inpt[4*j + (3-i)].v.position.xyz;
|
vec3 A = inpt[4*j + (3-i)].v.position.xyz;
|
||||||
#else // OSD_TRANSITION_ROTATE == 0, or non-transition patch
|
#else // OSD_TRANSITION_ROTATE == 0, or non-transition patch
|
||||||
vec3 A = inpt[4*i + j].v.position.xyz;
|
vec3 A = inpt[4*i + j].v.position.xyz;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
BUCP[i] += A * B[j];
|
BUCP[i] += A * B[j];
|
||||||
DUCP[i] += A * D[j];
|
DUCP[i] += A * D[j];
|
||||||
|
@ -184,6 +184,9 @@ uniform isamplerBuffer OsdPatchParamBuffer;
|
|||||||
#define GetPatchLevel() \
|
#define GetPatchLevel() \
|
||||||
(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).y & 0xf)
|
(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).y & 0xf)
|
||||||
|
|
||||||
|
#define GetSharpness() \
|
||||||
|
(intBitsToFloat(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).z))
|
||||||
|
|
||||||
#define OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER \
|
#define OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER \
|
||||||
{ \
|
{ \
|
||||||
ivec2 ptexIndex = texelFetch(OsdPatchParamBuffer, \
|
ivec2 ptexIndex = texelFetch(OsdPatchParamBuffer, \
|
||||||
|
@ -137,8 +137,29 @@ SetTransitionTessLevels(vec3 cp[OSD_PATCH_INPUT_SIZE], int patchLevel)
|
|||||||
vv0 = pv5;
|
vv0 = pv5;
|
||||||
vv1 = (pv5 + pv7) * 0.125 + pv6 * 0.75;
|
vv1 = (pv5 + pv7) * 0.125 + pv6 * 0.75;
|
||||||
#endif
|
#endif
|
||||||
|
#elif defined OSD_PATCH_SINGLE_CREASE
|
||||||
|
// apply smooth, sharp or fractional-semisharp (linear interpolate) rules
|
||||||
|
float weight = min(1, GetSharpness());
|
||||||
|
|
||||||
|
// XXX: current rotation of single-crease patch is inconsistent
|
||||||
|
// to boundary patch. should be fixed.
|
||||||
|
#if OSD_TRANSITION_ROTATE == 2
|
||||||
|
vv0 = mix(vv0, (pv4 + pv6) * 0.125 + pv5 * 0.75, weight);
|
||||||
|
vv1 = mix(vv1, (pv5 + pv7) * 0.125 + pv6 * 0.75, weight);
|
||||||
|
#elif OSD_TRANSITION_ROTATE == 3
|
||||||
|
vv1 = mix(vv1, (pv2 + pv10) * 0.125 + pv6 * 0.75, weight);
|
||||||
|
vv2 = mix(vv2, (pv6 + pv14) * 0.125 + pv10 * 0.75, weight);
|
||||||
|
#elif OSD_TRANSITION_ROTATE == 0
|
||||||
|
vv2 = mix(vv2, (pv9 + pv11) * 0.125 + pv10 * 0.75, weight);
|
||||||
|
vv3 = mix(vv3, (pv8 + pv10) * 0.125 + pv9 * 0.75, weight);
|
||||||
|
#elif OSD_TRANSITION_ROTATE == 1
|
||||||
|
vv3 = mix(vv3, (pv5 + pv13) * 0.125 + pv9 * 0.75, weight);
|
||||||
|
vv0 = mix(vv0, (pv1 + pv9) * 0.125 + pv5 * 0.75, weight);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef OSD_TRANSITION_PATTERN00
|
#ifdef OSD_TRANSITION_PATTERN00
|
||||||
gl_TessLevelOuter[0] = TessAdaptive(ev01, pv9) * 0.5;
|
gl_TessLevelOuter[0] = TessAdaptive(ev01, pv9) * 0.5;
|
||||||
gl_TessLevelOuter[1] = TessAdaptive(ev01, pv10) * 0.5;
|
gl_TessLevelOuter[1] = TessAdaptive(ev01, pv10) * 0.5;
|
||||||
@ -154,6 +175,7 @@ SetTransitionTessLevels(vec3 cp[OSD_PATCH_INPUT_SIZE], int patchLevel)
|
|||||||
|
|
||||||
gl_TessLevelInner[0] =
|
gl_TessLevelInner[0] =
|
||||||
(gl_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.25;
|
(gl_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.25;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef OSD_TRANSITION_PATTERN02
|
#ifdef OSD_TRANSITION_PATTERN02
|
||||||
gl_TessLevelOuter[0] = TessAdaptive(ev01, vv0);
|
gl_TessLevelOuter[0] = TessAdaptive(ev01, vv0);
|
||||||
|
@ -47,11 +47,12 @@ namespace OPENSUBDIV_VERSION {
|
|||||||
namespace Osd {
|
namespace Osd {
|
||||||
|
|
||||||
enum MeshBits {
|
enum MeshBits {
|
||||||
MeshAdaptive = 0,
|
MeshAdaptive = 0,
|
||||||
MeshInterleaveVarying = 1,
|
MeshInterleaveVarying = 1,
|
||||||
MeshPtexData = 2,
|
MeshPtexData = 2,
|
||||||
MeshFVarData = 3,
|
MeshFVarData = 3,
|
||||||
NUM_MESH_BITS = 4,
|
MeshUseSingleCreasePatch = 4,
|
||||||
|
NUM_MESH_BITS = 5,
|
||||||
};
|
};
|
||||||
typedef std::bitset<NUM_MESH_BITS> MeshBitset;
|
typedef std::bitset<NUM_MESH_BITS> MeshBitset;
|
||||||
|
|
||||||
@ -96,12 +97,12 @@ protected:
|
|||||||
refiner.GetNumVerticesTotal();
|
refiner.GetNumVerticesTotal();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void refineMesh(Far::TopologyRefiner & refiner, int level, bool adaptive) {
|
static inline void refineMesh(Far::TopologyRefiner & refiner, int level, bool adaptive, bool singleCreasePatch) {
|
||||||
|
|
||||||
bool fullTopologyInLastLevel = refiner.GetNumFVarChannels()>0;
|
bool fullTopologyInLastLevel = refiner.GetNumFVarChannels()>0;
|
||||||
|
|
||||||
if (adaptive) {
|
if (adaptive) {
|
||||||
refiner.RefineAdaptive(level, fullTopologyInLastLevel);
|
refiner.RefineAdaptive(level, fullTopologyInLastLevel, singleCreasePatch);
|
||||||
} else {
|
} else {
|
||||||
refiner.RefineUniform(level, fullTopologyInLastLevel);
|
refiner.RefineUniform(level, fullTopologyInLastLevel);
|
||||||
}
|
}
|
||||||
@ -136,13 +137,13 @@ public:
|
|||||||
|
|
||||||
assert(_refiner);
|
assert(_refiner);
|
||||||
|
|
||||||
MeshInterface<DRAW_CONTEXT>::refineMesh(*_refiner, level, bits.test(MeshAdaptive));
|
MeshInterface<DRAW_CONTEXT>::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
|
||||||
|
|
||||||
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
|
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
|
||||||
|
|
||||||
initializeComputeContext(numVertexElements, numVaryingElements);
|
initializeComputeContext(numVertexElements, numVaryingElements);
|
||||||
|
|
||||||
initializeDrawContext(numVertexElements, bits);
|
initializeDrawContext(numVertexElements, level, bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh(ComputeController * computeController,
|
Mesh(ComputeController * computeController,
|
||||||
@ -248,12 +249,13 @@ private:
|
|||||||
delete varyingStencils;
|
delete varyingStencils;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeDrawContext(int numElements, MeshBitset bits) {
|
void initializeDrawContext(int numElements, int level, MeshBitset bits) {
|
||||||
|
|
||||||
assert(_refiner and _vertexBuffer);
|
assert(_refiner and _vertexBuffer);
|
||||||
|
|
||||||
Far::PatchTablesFactory::Options options;
|
Far::PatchTablesFactory::Options options(level);
|
||||||
options.generateFVarTables = bits.test(MeshFVarData);
|
options.generateFVarTables = bits.test(MeshFVarData);
|
||||||
|
options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
|
||||||
|
|
||||||
_patchTables = Far::PatchTablesFactory::Create(*_refiner);
|
_patchTables = Far::PatchTablesFactory::Create(*_refiner);
|
||||||
|
|
||||||
|
@ -782,7 +782,93 @@ Level::gatherQuadRegularCornerPatchVertices(
|
|||||||
return 9;
|
return 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Level::isSingleCreasePatch(Index face, float *sharpnessOut, int *rotationOut) const {
|
||||||
|
|
||||||
|
// Note: this function is called twice for the same patch, at topologyRefiner and patchTablesFactory.
|
||||||
|
// we may want to cache the result to improve the Far performance.
|
||||||
|
// To do so, FTag needs to be extended to store isSingleCrease(bool), sharpness(float) and rotation(0-3).
|
||||||
|
//
|
||||||
|
Vtr::IndexArray const fVerts = this->getFaceVertices(face);
|
||||||
|
|
||||||
|
// the face has to be quad
|
||||||
|
if (fVerts.size() != 4) return false;
|
||||||
|
|
||||||
|
// if there's any corner vertex, return false.
|
||||||
|
for (int i = 0; i < fVerts.size(); ++i) {
|
||||||
|
if (this->getVertexSharpness(fVerts[i]) > 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure there's only one edge with sharpness
|
||||||
|
Vtr::IndexArray const fEdges = this->getFaceEdges(face);
|
||||||
|
float sharpness = 0.0f;
|
||||||
|
int rotation = 0;
|
||||||
|
for (int i = 0; i < fEdges.size(); ++i) {
|
||||||
|
float s = this->getEdgeSharpness(fEdges[i]);
|
||||||
|
if (s > 0.0f) {
|
||||||
|
if (sharpness > 0.0f) {
|
||||||
|
// found more than one sharp edges.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sharpness = s;
|
||||||
|
rotation = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotation = 0
|
||||||
|
// | | | |
|
||||||
|
// ---5-----4-----15----14---
|
||||||
|
// | || | |
|
||||||
|
// | || | |
|
||||||
|
// ---6-----0-----3-----13---
|
||||||
|
// | || | |
|
||||||
|
// | || | |
|
||||||
|
// ---7-----1-----2-----12---
|
||||||
|
// | || | |
|
||||||
|
// | || | |
|
||||||
|
// ---8-----9-----10----11---
|
||||||
|
// | | | |
|
||||||
|
|
||||||
|
int v[4];
|
||||||
|
v[0] = fVerts[(0+rotation)%4]; // crease
|
||||||
|
v[1] = fVerts[(1+rotation)%4]; // crease
|
||||||
|
v[2] = fVerts[(2+rotation)%4]; // smooth
|
||||||
|
v[3] = fVerts[(3+rotation)%4]; // smooth
|
||||||
|
|
||||||
|
// check the edges around v[0], v[1]
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
Vtr::IndexArray const vEdges = this->getVertexEdges(v[i]);
|
||||||
|
if (vEdges.size() != 4) return false;
|
||||||
|
int nSharpEdges = 0;
|
||||||
|
float sharpnesses[4];
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
sharpnesses[j] = this->getEdgeSharpness(vEdges[j]);
|
||||||
|
if (sharpnesses[j] > 0.0f) {
|
||||||
|
if (++nSharpEdges == 3) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sharpnesses have to be [0, x, 0, x] or [x, 0, x, 0]
|
||||||
|
if (sharpnesses[0] != sharpnesses[2] or
|
||||||
|
sharpnesses[1] != sharpnesses[3]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check the edges around v[2], v[3]
|
||||||
|
for (int i = 2; i < 4; ++i) {
|
||||||
|
Vtr::IndexArray const vEdges = this->getVertexEdges(v[i]);
|
||||||
|
if (vEdges.size() != 4) return false;
|
||||||
|
// all edges have to be smooth
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
float sharpness = this->getEdgeSharpness(vEdges[j]);
|
||||||
|
if (sharpness > 0.0f) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sharpnessOut) *sharpnessOut = sharpness;
|
||||||
|
if (rotationOut) *rotationOut = rotation;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// What follows is an internal/anonymous class and protected methods to complete all
|
// What follows is an internal/anonymous class and protected methods to complete all
|
||||||
|
@ -238,6 +238,8 @@ public:
|
|||||||
|
|
||||||
int gatherManifoldVertexRingFromIncidentQuads(Index vIndex, int vOffset, int ringVerts[]) const;
|
int gatherManifoldVertexRingFromIncidentQuads(Index vIndex, int vOffset, int ringVerts[]) const;
|
||||||
|
|
||||||
|
bool isSingleCreasePatch(Index face, float* sharpnessOut=NULL, int* rotationOut=NULL) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
friend class Refinement;
|
friend class Refinement;
|
||||||
|
Loading…
Reference in New Issue
Block a user