mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-23 12:10:08 +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"
|
||||
|
||||
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.0f, 1.0f, 0.0f, 1.0f}, // corner
|
||||
{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
|
||||
{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.2f, 0.75f, 1.0f}, // boundary pattern 1
|
||||
{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_FRACTIONAL_SPACING,
|
||||
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;
|
||||
|
||||
@ -164,16 +165,18 @@ float g_animTime = 0;
|
||||
int g_fullscreen = 0,
|
||||
g_freeze = 0,
|
||||
g_displayStyle = kWireShaded,
|
||||
g_adaptive = 0,
|
||||
g_adaptive = 1,
|
||||
g_singleCreasePatch = 1,
|
||||
g_drawCageEdges = 1,
|
||||
g_drawCageVertices = 0,
|
||||
g_mbutton[3] = {0, 0, 0},
|
||||
g_running = 1;
|
||||
|
||||
int g_displayPatchColor = 1,
|
||||
g_screenSpaceTess = 0,
|
||||
g_fractionalSpacing = 0,
|
||||
g_patchCull = 0;
|
||||
g_screenSpaceTess = 1,
|
||||
g_fractionalSpacing = 1,
|
||||
g_patchCull = 0,
|
||||
g_displayPatchCounts = 0;
|
||||
|
||||
float g_rotate[2] = {0, 0},
|
||||
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
|
||||
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;
|
||||
bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
|
||||
bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, doSingleCreasePatch);
|
||||
bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, interleaveVarying);
|
||||
bits.set(OpenSubdiv::Osd::MeshFVarData, g_displayStyle == kFaceVaryingColor);
|
||||
|
||||
@ -1148,7 +1153,9 @@ display() {
|
||||
g_mesh->GetDrawContext()->GetPatchArrays();
|
||||
|
||||
// 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));
|
||||
|
||||
// primitive counting
|
||||
@ -1169,6 +1176,7 @@ display() {
|
||||
if (subPatch == 0) {
|
||||
patchCount[patchType][patchPattern][patchRotation] += patch.GetNumPatches();
|
||||
}
|
||||
numTotalPatches += patch.GetNumPatches();
|
||||
|
||||
GLenum primType;
|
||||
|
||||
@ -1223,6 +1231,7 @@ display() {
|
||||
|
||||
glDrawElements(primType, patch.GetNumIndices(), GL_UNSIGNED_INT,
|
||||
(void *)(patch.GetVertIndex() * sizeof(unsigned int)));
|
||||
++numDrawCalls;
|
||||
if (g_displayStyle == kWire) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
@ -1268,47 +1277,64 @@ display() {
|
||||
|
||||
double fps = 1.0/elapsed;
|
||||
|
||||
int x = -280;
|
||||
g_hud.DrawString(x, -360, "NonPatch : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::QUADS][0][0]);
|
||||
g_hud.DrawString(x, -340, "Regular : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][0][0]);
|
||||
g_hud.DrawString(x, -320, "Boundary : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][0][0]);
|
||||
g_hud.DrawString(x, -300, "Corner : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::CORNER][0][0]);
|
||||
g_hud.DrawString(x, -280, "Gregory : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::GREGORY][0][0]);
|
||||
g_hud.DrawString(x, -260, "Boundary Gregory : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::GREGORY_BOUNDARY][0][0]);
|
||||
g_hud.DrawString(x, -240, "Trans. Regular : %d %d %d %d %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN0][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN1][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN2][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN3][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN4][0]);
|
||||
for (int i=0; i < 5; i++)
|
||||
g_hud.DrawString(x, -220+i*20, "Trans. Boundary%d : %d %d %d %d", i,
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][1],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][2],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][3]);
|
||||
for (int i=0; i < 5; i++)
|
||||
g_hud.DrawString(x, -100+i*20, "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]);
|
||||
if (g_displayPatchCounts) {
|
||||
int x = -280;
|
||||
int y = -480;
|
||||
g_hud.DrawString(x, y, "NonPatch : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::QUADS][0][0]); y += 20;
|
||||
g_hud.DrawString(x, y, "Regular : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][0][0]); y+= 20;
|
||||
g_hud.DrawString(x, y, "Boundary : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][0][0]); y+= 20;
|
||||
g_hud.DrawString(x, y, "Corner : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::CORNER][0][0]); y+= 20;
|
||||
g_hud.DrawString(x, y, "Single Crease : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::SINGLE_CREASE][0][0]); y+= 20;
|
||||
g_hud.DrawString(x, y, "Gregory : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::GREGORY][0][0]); y+= 20;
|
||||
g_hud.DrawString(x, y, "Boundary Gregory : %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::GREGORY_BOUNDARY][0][0]); y+= 20;
|
||||
g_hud.DrawString(x, y, "Trans. Regular : %d %d %d %d %d",
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN0][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN1][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN2][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN3][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::REGULAR][OpenSubdiv::Far::PatchTables::PATTERN4][0]); y+= 20;
|
||||
for (int i=0; i < 5; i++) {
|
||||
g_hud.DrawString(x, y, "Trans. Boundary%d : %d %d %d %d", i,
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][0],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][1],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][2],
|
||||
patchCount[OpenSubdiv::Far::PatchTables::BOUNDARY][i+1][3]); y+= 20;
|
||||
}
|
||||
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);
|
||||
g_hud.DrawString(10, -160, "Primitives : %d", numPrimsGenerated);
|
||||
g_hud.DrawString(10, -140, "Vertices : %d", g_mesh->GetNumVertices());
|
||||
g_hud.DrawString(10, -120, "Scheme : %s", g_scheme==kBilinear ? "BILINEAR" : (g_scheme == kLoop ? "LOOP" : "CATMARK"));
|
||||
g_hud.DrawString(10, -100, "GPU Kernel : %.3f ms", g_gpuTime);
|
||||
g_hud.DrawString(10, -80, "CPU Kernel : %.3f ms", g_cpuTime);
|
||||
g_hud.DrawString(10, -60, "GPU Draw : %.3f ms", drawGpuTime);
|
||||
g_hud.DrawString(10, -40, "CPU Draw : %.3f ms", drawCpuTime);
|
||||
g_hud.DrawString(10, -20, "FPS : %3.1f", fps);
|
||||
int y = -220;
|
||||
g_hud.DrawString(10, y, "Tess level : %d", g_tessLevel); y+= 20;
|
||||
g_hud.DrawString(10, y, "Patches : %d", numTotalPatches); y+= 20;
|
||||
g_hud.DrawString(10, y, "Draw calls : %d", numDrawCalls); y+= 20;
|
||||
g_hud.DrawString(10, y, "Primitives : %d", numPrimsGenerated); y+= 20;
|
||||
g_hud.DrawString(10, y, "Vertices : %d", g_mesh->GetNumVertices()); y+= 20;
|
||||
g_hud.DrawString(10, y, "Scheme : %s", g_scheme==kBilinear ? "BILINEAR" : (g_scheme == kLoop ? "LOOP" : "CATMARK")); y+= 20;
|
||||
g_hud.DrawString(10, y, "GPU Kernel : %.3f ms", g_gpuTime); y+= 20;
|
||||
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();
|
||||
}
|
||||
@ -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
|
||||
callbackCheckBox(bool checked, int button)
|
||||
{
|
||||
@ -1547,6 +1582,9 @@ callbackCheckBox(bool checked, int button)
|
||||
case kHUD_CB_FREEZE:
|
||||
g_freeze = checked;
|
||||
break;
|
||||
case kHUD_CB_DISPLAY_PATCH_COUNTS:
|
||||
g_displayPatchCounts = checked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1614,8 +1652,10 @@ initHUD()
|
||||
g_hud.AddPullDownButton(compute_pulldown, "GLSL Compute", kGLSLCompute);
|
||||
}
|
||||
#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("Single Crease Patch (S)", g_singleCreasePatch!=0, 10, 210, callbackSingleCreasePatch, 0, 's');
|
||||
}
|
||||
|
||||
for (int i = 1; i < 11; ++i) {
|
||||
char level[16];
|
||||
@ -1628,6 +1668,8 @@ 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.Rebuild(g_width, g_height);
|
||||
}
|
||||
|
||||
|
@ -358,7 +358,9 @@ edgeColor(vec4 Cfill, vec4 edgeDistance)
|
||||
min(min(inpt.edgeDistance[0], inpt.edgeDistance[1]),
|
||||
min(inpt.edgeDistance[2], inpt.edgeDistance[3]));
|
||||
#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);
|
||||
|
||||
#if defined(GEOMETRY_OUT_WIRE)
|
||||
|
@ -253,19 +253,23 @@ PatchTables::getAdaptiveCatmarkDescriptors() {
|
||||
|
||||
if (_descriptors.empty()) {
|
||||
|
||||
_descriptors.reserve(50);
|
||||
_descriptors.reserve(71);
|
||||
|
||||
// non-transition patches
|
||||
// non-transition patches : 6
|
||||
for (int i=REGULAR; i<=GREGORY_BOUNDARY; ++i) {
|
||||
_descriptors.push_back( Descriptor(i, NON_TRANSITION, 0) );
|
||||
}
|
||||
|
||||
// transition patches
|
||||
// transition patches (1 + 4 * 3) * 5 = 65
|
||||
for (int i=PATTERN0; i<=PATTERN4; ++i) {
|
||||
|
||||
_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) {
|
||||
_descriptors.push_back( Descriptor(BOUNDARY, i, j) );
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ public:
|
||||
LOOP, ///< Loop patch (currently unsupported)
|
||||
|
||||
REGULAR, ///< feature-adaptive bicubic patches
|
||||
SINGLE_CREASE,
|
||||
BOUNDARY,
|
||||
CORNER,
|
||||
GREGORY,
|
||||
@ -339,6 +340,12 @@ public:
|
||||
/// \brief Returns a PatchParamTable for each type of patch
|
||||
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.
|
||||
static short GetRegularPatchSize() { return 16; }
|
||||
|
||||
@ -577,6 +584,10 @@ private:
|
||||
|
||||
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
|
||||
// vertexValance & quadOffset tables)
|
||||
int _maxValence;
|
||||
@ -591,6 +602,7 @@ inline short
|
||||
PatchTables::Descriptor::GetNumControlVertices( PatchTables::Type type ) {
|
||||
switch (type) {
|
||||
case REGULAR : return PatchTables::GetRegularPatchSize();
|
||||
case SINGLE_CREASE : return PatchTables::GetRegularPatchSize();
|
||||
case QUADS : return 4;
|
||||
case GREGORY :
|
||||
case GREGORY_BOUNDARY : return PatchTables::GetGregoryPatchSize();
|
||||
@ -608,6 +620,7 @@ inline short
|
||||
PatchTables::Descriptor::GetNumFVarControlVertices( PatchTables::Type type ) {
|
||||
switch (type) {
|
||||
case REGULAR : // We only support bilinear interpolation for now,
|
||||
case SINGLE_CREASE :
|
||||
case QUADS : // so all these patches only carry 4 CVs.
|
||||
case GREGORY :
|
||||
case GREGORY_BOUNDARY :
|
||||
@ -811,6 +824,10 @@ PatchTables::Limit(PatchHandle const & handle, float s, float t,
|
||||
case REGULAR:
|
||||
InterpolateRegularPatch(cvs, Q, Qd1, Qd2, src, dst);
|
||||
break;
|
||||
case SINGLE_CREASE:
|
||||
// TODO: implement InterpolateSingleCreasePatch().
|
||||
//InterpolateRegularPatch(cvs, Q, Qd1, Qd2, src, dst);
|
||||
break;
|
||||
case BOUNDARY:
|
||||
InterpolateBoundaryPatch(cvs, Q, Qd1, Qd2, src, dst);
|
||||
break;
|
||||
|
@ -46,6 +46,7 @@ struct PatchTypes {
|
||||
NUM_ROTATIONS=4;
|
||||
|
||||
TYPE R[NUM_TRANSITIONS], // regular patch
|
||||
S[NUM_TRANSITIONS][NUM_ROTATIONS], // single-crease patch
|
||||
B[NUM_TRANSITIONS][NUM_ROTATIONS], // boundary patch (4 rotations)
|
||||
C[NUM_TRANSITIONS][NUM_ROTATIONS], // corner patch (4 rotations)
|
||||
G, // gregory patch
|
||||
@ -57,6 +58,7 @@ struct PatchTypes {
|
||||
TYPE & getValue( PatchTables::Descriptor desc ) {
|
||||
switch (desc.GetType()) {
|
||||
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::CORNER : return C[desc.GetPattern()][desc.GetRotation()];
|
||||
case PatchTables::GREGORY : return G;
|
||||
@ -76,6 +78,7 @@ struct PatchTypes {
|
||||
if (R[i]) ++result;
|
||||
|
||||
for (int j=0; j<4; ++j) {
|
||||
if (S[i][j]) ++result;
|
||||
if (B[i][j]) ++result;
|
||||
if (C[i][j]) ++result;
|
||||
|
||||
@ -85,10 +88,21 @@ struct PatchTypes {
|
||||
if (GB) ++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<PatchParam *> PatchParamPointers;
|
||||
typedef PatchTypes<Index *> SharpnessIndexPointers;
|
||||
typedef PatchTypes<int> PatchCounters;
|
||||
typedef PatchTypes<Index **> PatchFVarPointers;
|
||||
|
||||
@ -131,6 +145,7 @@ public:
|
||||
unsigned int _boundaryIndex : 2;
|
||||
unsigned int _boundaryCount : 3;
|
||||
unsigned int _hasBoundaryEdge : 3;
|
||||
unsigned int _isSingleCrease : 1;
|
||||
|
||||
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) {
|
||||
//
|
||||
// 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...
|
||||
if (transitionEdgeMask == 0) {
|
||||
_transitionRot = 0;
|
||||
} else if (_boundaryCount == 0 and _isSingleCrease) {
|
||||
assignTransitionRotationForSingleCrease(transitionEdgeMask);
|
||||
} else if (_boundaryCount == 0) {
|
||||
// XXXX manuelk Rotations are mostly a direct map of the transitionEdgeMask
|
||||
// Except for:
|
||||
@ -335,7 +385,7 @@ namespace {
|
||||
// Reserves tables based on the contents of the PatchArrayVector in the PatchTables:
|
||||
//
|
||||
void
|
||||
PatchTablesFactory::allocateTables(PatchTables * tables, int /* nlevels */) {
|
||||
PatchTablesFactory::allocateTables(PatchTables * tables, int /* nlevels */, bool hasSharpness) {
|
||||
|
||||
PatchTables::PatchArrayVector const & parrays = tables->GetPatchArrayVector();
|
||||
|
||||
@ -352,6 +402,10 @@ PatchTablesFactory::allocateTables(PatchTables * tables, int /* nlevels */) {
|
||||
tables->_patches.resize( nverts );
|
||||
|
||||
tables->_paramTable.resize( npatches );
|
||||
|
||||
if (hasSharpness) {
|
||||
tables->_sharpnessIndexTable.resize( npatches );
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
allocateTables( tables, 0 );
|
||||
allocateTables( tables, 0, /*hasSharpness=*/false );
|
||||
|
||||
if (options.generateFVarTables) {
|
||||
tables->_fvarPatchTables = allocateFVarTables( refiner, *tables, options );
|
||||
@ -701,7 +769,7 @@ PatchTablesFactory::createAdaptive( TopologyRefiner const & refiner, Options opt
|
||||
PatchCounters patchInventory;
|
||||
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
|
||||
@ -729,7 +797,8 @@ PatchTablesFactory::createAdaptive( TopologyRefiner const & refiner, Options opt
|
||||
tables->_numPtexFaces = refiner.GetNumPtexFaces();
|
||||
|
||||
// Allocate various tables
|
||||
allocateTables( tables, 0 );
|
||||
bool hasSharpness = patchInventory.hasSingleCreasedPatches();
|
||||
allocateTables( tables, 0, hasSharpness );
|
||||
|
||||
if (options.generateFVarTables) {
|
||||
tables->_fvarPatchTables = allocateFVarTables( refiner, *tables, options );
|
||||
@ -743,7 +812,7 @@ PatchTablesFactory::createAdaptive( TopologyRefiner const & refiner, Options opt
|
||||
//
|
||||
// Now populate the patches:
|
||||
//
|
||||
populateAdaptivePatches(refiner, patchInventory, patchTags, tables);
|
||||
populateAdaptivePatches(refiner, patchInventory, patchTags, tables, options);
|
||||
|
||||
return tables;
|
||||
}
|
||||
@ -755,9 +824,9 @@ PatchTablesFactory::createAdaptive( TopologyRefiner const & refiner, Options opt
|
||||
//
|
||||
void
|
||||
PatchTablesFactory::identifyAdaptivePatches( TopologyRefiner const & refiner,
|
||||
PatchCounters & patchInventory,
|
||||
PatchTagVector & patchTags ) {
|
||||
|
||||
PatchCounters & patchInventory,
|
||||
PatchTagVector & patchTags,
|
||||
Options options ) {
|
||||
//
|
||||
// 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
|
||||
@ -866,6 +935,24 @@ PatchTablesFactory::identifyAdaptivePatches( TopologyRefiner const & refiner,
|
||||
int boundaryEdgeMask = 0;
|
||||
|
||||
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) {
|
||||
Vtr::IndexArray const& fEdges = level->getFaceEdges(faceIndex);
|
||||
|
||||
@ -924,8 +1011,10 @@ PatchTablesFactory::identifyAdaptivePatches( TopologyRefiner const & refiner,
|
||||
int transIndex = patchTag._transitionType;
|
||||
int transRot = patchTag._transitionRot;
|
||||
|
||||
if (patchTag._boundaryCount == 0) {
|
||||
if (!patchTag._isSingleCrease && patchTag._boundaryCount == 0) {
|
||||
patchInventory.R[transIndex]++;
|
||||
} else if (patchTag._isSingleCrease && patchTag._boundaryCount == 0) {
|
||||
patchInventory.S[transIndex][transRot]++;
|
||||
} else if (patchTag._boundaryCount == 1) {
|
||||
patchInventory.B[transIndex][transRot]++;
|
||||
} else {
|
||||
@ -952,7 +1041,8 @@ void
|
||||
PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
||||
PatchCounters const & patchInventory,
|
||||
PatchTagVector const & patchTags,
|
||||
PatchTables * tables ) {
|
||||
PatchTables * tables,
|
||||
Options options ) {
|
||||
|
||||
//
|
||||
// Setup convenience pointers at the beginning of each patch array for each
|
||||
@ -961,6 +1051,7 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
||||
PatchCVPointers iptrs;
|
||||
PatchParamPointers pptrs;
|
||||
PatchFVarPointers fptrs;
|
||||
SharpnessIndexPointers sptrs;
|
||||
|
||||
typedef PatchTables::DescriptorVector DescVec;
|
||||
|
||||
@ -974,6 +1065,9 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
||||
|
||||
iptrs.getValue( *it ) = &tables->_patches[pa->GetVertIndex()];
|
||||
pptrs.getValue( *it ) = &tables->_paramTable[pa->GetPatchIndex()];
|
||||
if (patchInventory.hasSingleCreasedPatches()) {
|
||||
sptrs.getValue( *it ) = &tables->_sharpnessIndexTable[pa->GetPatchIndex()];
|
||||
}
|
||||
|
||||
if (tables->_fvarPatchTables) {
|
||||
int nchannels = refiner.GetNumFVarChannels(),
|
||||
@ -1031,7 +1125,7 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
|
||||
int rIndex = patchTag._transitionRot;
|
||||
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 };
|
||||
|
||||
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
|
||||
// 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 };
|
||||
|
||||
level->gatherQuadRegularBoundaryPatchVertices(faceIndex, patchVerts, bIndex);
|
||||
|
@ -53,13 +53,18 @@ public:
|
||||
|
||||
struct Options {
|
||||
|
||||
Options() : generateAllLevels(false),
|
||||
triangulateQuads(false),
|
||||
generateFVarTables(false) { }
|
||||
Options(unsigned int maxIsolationLevel=10) : generateAllLevels(false),
|
||||
triangulateQuads(false),
|
||||
generateFVarTables(false),
|
||||
useSingleCreasePatch(false),
|
||||
maxIsolationLevel(maxIsolationLevel)
|
||||
{ }
|
||||
|
||||
unsigned int generateAllLevels : 1, ///< Include levels from 'firstLevel' to 'maxLevel' (Uniform mode only)
|
||||
triangulateQuads : 1, ///< Triangulate 'QUADS' primitives (Uniform mode only)
|
||||
generateFVarTables : 1; ///< Generate face-varying patch tables
|
||||
unsigned int generateAllLevels : 1, ///< Include levels from 'firstLevel' to 'maxLevel' (Uniform mode only)
|
||||
triangulateQuads : 1, ///< Triangulate 'QUADS' primitives (Uniform mode only)
|
||||
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
|
||||
@ -84,15 +89,17 @@ private:
|
||||
// High-level methods for identifying and populating patches associated with faces:
|
||||
static void identifyAdaptivePatches( TopologyRefiner const & refiner,
|
||||
PatchTypes<int> & patchInventory,
|
||||
std::vector<PatchFaceTag> & patchTags);
|
||||
std::vector<PatchFaceTag> & patchTags,
|
||||
Options options );
|
||||
|
||||
static void populateAdaptivePatches( TopologyRefiner const & refiner,
|
||||
PatchTypes<int> const & patchInventory,
|
||||
std::vector<PatchFaceTag> const & patchTags,
|
||||
PatchTables * tables);
|
||||
PatchTables * tables,
|
||||
Options options );
|
||||
|
||||
// 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,
|
||||
PatchTables const & tables,
|
||||
@ -103,10 +110,12 @@ private:
|
||||
int npatches, int * voffset, int * poffset, int * qoffset );
|
||||
|
||||
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 int assignSharpnessIndex( PatchTables *tables, float sharpness );
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,8 @@ TopologyRefiner::TopologyRefiner(Sdc::Type schemeType, Sdc::Options schemeOption
|
||||
_subdivType(schemeType),
|
||||
_subdivOptions(schemeOptions),
|
||||
_isUniform(true),
|
||||
_maxLevel(0) {
|
||||
_maxLevel(0),
|
||||
_useSingleCreasePatch(false) {
|
||||
|
||||
// Need to revisit allocation scheme here -- want to use smart-ptrs for these
|
||||
// but will probably have to settle for explicit new/delete...
|
||||
@ -318,7 +319,7 @@ TopologyRefiner::RefineUniform(int maxLevel, bool fullTopology) {
|
||||
|
||||
|
||||
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(_subdivType == Sdc::TYPE_CATMARK);
|
||||
@ -328,6 +329,7 @@ TopologyRefiner::RefineAdaptive(int subdivLevel, bool fullTopology) {
|
||||
//
|
||||
_isUniform = false;
|
||||
_maxLevel = subdivLevel;
|
||||
_useSingleCreasePatch = useSingleCreasePatch;
|
||||
|
||||
// Should we presize all or grow one at a time as needed?
|
||||
_levels.resize(subdivLevel + 1);
|
||||
@ -435,7 +437,7 @@ TopologyRefiner::catmarkFeatureAdaptiveSelector(Vtr::SparseSelector& selector) {
|
||||
}
|
||||
|
||||
bool selectFace = false;
|
||||
if (compFaceTag._xordinary || compFaceTag._semiSharp) {
|
||||
if (compFaceTag._xordinary) {
|
||||
selectFace = true;
|
||||
} else if (compFaceTag._rule & Sdc::Crease::RULE_DART) {
|
||||
// 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
|
||||
// support regular patches with one corner or one boundary.
|
||||
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 {
|
||||
// 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
|
||||
|
@ -114,7 +114,9 @@ public:
|
||||
/// @param fullTopologyInLastLevel Skip secondary topological relationships
|
||||
/// 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)
|
||||
void Unrefine();
|
||||
@ -496,6 +498,7 @@ private:
|
||||
|
||||
bool _isUniform;
|
||||
int _maxLevel;
|
||||
bool _useSingleCreasePatch;
|
||||
|
||||
std::vector<Vtr::Level> _levels;
|
||||
std::vector<Vtr::Refinement> _refinements;
|
||||
|
@ -167,8 +167,27 @@ GLDrawContext::create(Far::PatchTables const & patchTables, int numVertexElement
|
||||
Far::PatchTables::PatchParamTable const &
|
||||
patchParamTables = patchTables.GetPatchParamTable();
|
||||
|
||||
if (not patchParamTables.empty())
|
||||
_patchParamTextureBuffer = createTextureBuffer(patchParamTables, GL_RG32I);
|
||||
if (not patchParamTables.empty()) {
|
||||
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);
|
||||
#endif
|
||||
|
@ -94,6 +94,19 @@ GLDrawRegistryBase::_CreateDrawSourceConfig(
|
||||
sconfig->tessEvalShader.version = "#version 410\n";
|
||||
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
|
||||
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:
|
||||
sconfig->vertexShader.source = bsplineShaderSource;
|
||||
sconfig->vertexShader.version = "#version 410\n";
|
||||
@ -176,7 +189,10 @@ GLDrawRegistryBase::_CreateDrawSourceConfig(
|
||||
sconfig->tessControlShader.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");
|
||||
} else if (desc.GetType() == Far::PatchTables::CORNER) {
|
||||
sconfig->tessControlShader.AddDefine("OSD_PATCH_CORNER");
|
||||
|
@ -68,14 +68,14 @@ public:
|
||||
_drawContext(0)
|
||||
{
|
||||
|
||||
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive));
|
||||
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
|
||||
|
||||
int numElements =
|
||||
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
|
||||
|
||||
initializeComputeContext(numVertexElements, numVaryingElements);
|
||||
|
||||
initializeDrawContext(numElements, bits);
|
||||
initializeDrawContext(numElements, level, bits);
|
||||
}
|
||||
|
||||
Mesh(ComputeController * computeController,
|
||||
@ -201,12 +201,13 @@ private:
|
||||
delete varyingStencils;
|
||||
}
|
||||
|
||||
void initializeDrawContext(int numElements, MeshBitset bits) {
|
||||
void initializeDrawContext(int numElements, int level, MeshBitset bits) {
|
||||
|
||||
assert(_refiner and _vertexBuffer);
|
||||
|
||||
Far::PatchTablesFactory::Options options;
|
||||
Far::PatchTablesFactory::Options options(level);
|
||||
options.generateFVarTables = bits.test(MeshFVarData);
|
||||
options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
|
||||
|
||||
_patchTables = Far::PatchTablesFactory::Create(*_refiner, options);
|
||||
|
||||
@ -279,7 +280,7 @@ public:
|
||||
{
|
||||
assert(_refiner);
|
||||
|
||||
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive));
|
||||
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
|
||||
|
||||
int numElements =
|
||||
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
|
||||
);
|
||||
|
||||
// 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
|
||||
uniform mat4x3 B = mat4x3(
|
||||
1.f, 0.f, 0.f,
|
||||
@ -74,11 +82,34 @@ in block {
|
||||
|
||||
out block {
|
||||
ControlVertex v;
|
||||
vec4 P1;
|
||||
vec4 P2;
|
||||
float sharpness;
|
||||
OSD_USER_VARYING_DECLARE
|
||||
} outpt[];
|
||||
|
||||
#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()
|
||||
{
|
||||
int i = ID%4;
|
||||
@ -98,6 +129,8 @@ void main()
|
||||
pos += B[j][k]*H[k];
|
||||
}
|
||||
|
||||
outpt[ID].v.position = vec4(pos, 1.0);
|
||||
|
||||
#elif defined OSD_PATCH_CORNER
|
||||
vec3 H[3];
|
||||
for (int l=0; l<3; ++l) {
|
||||
@ -112,6 +145,8 @@ void main()
|
||||
pos += B[j][k]*H[k];
|
||||
}
|
||||
|
||||
outpt[ID].v.position = vec4(pos, 1.0);
|
||||
|
||||
#else // not OSD_PATCH_BOUNDARY, not OSD_PATCH_CORNER
|
||||
vec3 H[4];
|
||||
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);
|
||||
for (int k=0; k<4; ++k) {
|
||||
pos += Q[j][k]*H[k];
|
||||
}
|
||||
outpt[ID].v.position = vec4(pos, 1.0);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
outpt[ID].v.position = vec4(pos, 1.0);
|
||||
|
||||
#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 );
|
||||
@ -215,6 +275,9 @@ void main()
|
||||
|
||||
in block {
|
||||
ControlVertex v;
|
||||
vec4 P1;
|
||||
vec4 P2;
|
||||
float sharpness;
|
||||
OSD_USER_VARYING_DECLARE
|
||||
} inpt[];
|
||||
|
||||
@ -244,8 +307,35 @@ void main()
|
||||
Univar4x4(UV.x, B, D);
|
||||
#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 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
|
||||
vec3 A = inpt[4*(3-j) + i].v.position.xyz;
|
||||
#elif OSD_TRANSITION_ROTATE == 2
|
||||
@ -254,6 +344,7 @@ void main()
|
||||
vec3 A = inpt[4*j + (3-i)].v.position.xyz;
|
||||
#else // OSD_TRANSITION_ROTATE == 0, or non-transition patch
|
||||
vec3 A = inpt[4*i + j].v.position.xyz;
|
||||
#endif
|
||||
#endif
|
||||
BUCP[i] += A * B[j];
|
||||
DUCP[i] += A * D[j];
|
||||
|
@ -184,6 +184,9 @@ uniform isamplerBuffer OsdPatchParamBuffer;
|
||||
#define GetPatchLevel() \
|
||||
(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).y & 0xf)
|
||||
|
||||
#define GetSharpness() \
|
||||
(intBitsToFloat(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).z))
|
||||
|
||||
#define OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER \
|
||||
{ \
|
||||
ivec2 ptexIndex = texelFetch(OsdPatchParamBuffer, \
|
||||
|
@ -137,8 +137,29 @@ SetTransitionTessLevels(vec3 cp[OSD_PATCH_INPUT_SIZE], int patchLevel)
|
||||
vv0 = pv5;
|
||||
vv1 = (pv5 + pv7) * 0.125 + pv6 * 0.75;
|
||||
#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
|
||||
|
||||
|
||||
#ifdef OSD_TRANSITION_PATTERN00
|
||||
gl_TessLevelOuter[0] = TessAdaptive(ev01, pv9) * 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_TessLevelOuter[0] + gl_TessLevelOuter[1] + gl_TessLevelOuter[2]) * 0.25;
|
||||
|
||||
#endif
|
||||
#ifdef OSD_TRANSITION_PATTERN02
|
||||
gl_TessLevelOuter[0] = TessAdaptive(ev01, vv0);
|
||||
|
@ -47,11 +47,12 @@ namespace OPENSUBDIV_VERSION {
|
||||
namespace Osd {
|
||||
|
||||
enum MeshBits {
|
||||
MeshAdaptive = 0,
|
||||
MeshInterleaveVarying = 1,
|
||||
MeshPtexData = 2,
|
||||
MeshFVarData = 3,
|
||||
NUM_MESH_BITS = 4,
|
||||
MeshAdaptive = 0,
|
||||
MeshInterleaveVarying = 1,
|
||||
MeshPtexData = 2,
|
||||
MeshFVarData = 3,
|
||||
MeshUseSingleCreasePatch = 4,
|
||||
NUM_MESH_BITS = 5,
|
||||
};
|
||||
typedef std::bitset<NUM_MESH_BITS> MeshBitset;
|
||||
|
||||
@ -96,12 +97,12 @@ protected:
|
||||
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;
|
||||
|
||||
if (adaptive) {
|
||||
refiner.RefineAdaptive(level, fullTopologyInLastLevel);
|
||||
refiner.RefineAdaptive(level, fullTopologyInLastLevel, singleCreasePatch);
|
||||
} else {
|
||||
refiner.RefineUniform(level, fullTopologyInLastLevel);
|
||||
}
|
||||
@ -136,13 +137,13 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
initializeComputeContext(numVertexElements, numVaryingElements);
|
||||
|
||||
initializeDrawContext(numVertexElements, bits);
|
||||
initializeDrawContext(numVertexElements, level, bits);
|
||||
}
|
||||
|
||||
Mesh(ComputeController * computeController,
|
||||
@ -248,12 +249,13 @@ private:
|
||||
delete varyingStencils;
|
||||
}
|
||||
|
||||
void initializeDrawContext(int numElements, MeshBitset bits) {
|
||||
void initializeDrawContext(int numElements, int level, MeshBitset bits) {
|
||||
|
||||
assert(_refiner and _vertexBuffer);
|
||||
|
||||
Far::PatchTablesFactory::Options options;
|
||||
Far::PatchTablesFactory::Options options(level);
|
||||
options.generateFVarTables = bits.test(MeshFVarData);
|
||||
options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
|
||||
|
||||
_patchTables = Far::PatchTablesFactory::Create(*_refiner);
|
||||
|
||||
|
@ -782,7 +782,93 @@ Level::gatherQuadRegularCornerPatchVertices(
|
||||
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
|
||||
|
@ -238,6 +238,8 @@ public:
|
||||
|
||||
int gatherManifoldVertexRingFromIncidentQuads(Index vIndex, int vOffset, int ringVerts[]) const;
|
||||
|
||||
bool isSingleCreasePatch(Index face, float* sharpnessOut=NULL, int* rotationOut=NULL) const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class Refinement;
|
||||
|
Loading…
Reference in New Issue
Block a user