Enable GregoryBasis patch.

PatchTablesFactory fills 20 indices topology into patchtable, and use it for eval and draw.

note: currently screen-space adaptive tessellation of gregory basis patches is
broken and cracks appear around them.
This commit is contained in:
Takahito Tejima 2015-04-07 18:34:05 -07:00
parent 5415bc23b9
commit 24f9dc154b
27 changed files with 858 additions and 344 deletions

View File

@ -30,7 +30,7 @@ static float _colors[5][7][4] = {{{1.0f, 1.0f, 1.0f, 1.0f}, // regular
{0.0f, 1.0f, 0.0f, 1.0f}, // corner
{1.0f, 1.0f, 0.0f, 1.0f}, // gregory
{1.0f, 0.5f, 0.0f, 1.0f}, // gregory boundary
{1.0f, 1.0f, 0.0f, 1.0f}}, // gregory basis
{1.0f, 0.7f, 0.3f, 1.0f}}, // gregory basis
{{0.0f, 1.0f, 1.0f, 1.0f}, // regular pattern 0
{0.0f, 0.5f, 1.0f, 1.0f}, // regular pattern 1

View File

@ -376,26 +376,50 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level) {
Far::StencilTables const * varyingStencils =
Far::StencilTablesFactory::Create(*g_topologyRefiner, soptions);
g_kernelBatches.clear();
g_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
// Create an Osd Compute context, used to "pose" the vertices with
// the stencils tables
delete g_computeCtx;
g_computeCtx = Osd::CpuComputeContext::Create(vertexStencils, varyingStencils);
// Generate bi-cubic patch tables for the limit surface
Far::PatchTablesFactory::Options poptions;
// optional : pass the vertex stencils so that the factory can generate gregory basis
// stencils (faster evaluation)
poptions.adaptiveStencilTables = vertexStencils;
poptions.adaptiveVaryingStencilTables = varyingStencils;
Far::PatchTables const * patchTables =
Far::PatchTablesFactory::Create(*g_topologyRefiner, poptions);
Far::StencilTables const *inStencils[] = {
vertexStencils, patchTables->GetEndCapVertexStencilTables()
};
Far::StencilTables const *concatStencils =
Far::StencilTablesFactory::Create(2, inStencils);
// add gregory basis vertices FIXME:
if (patchTables->GetEndCapVertexStencilTables()) {
nverts += patchTables->GetEndCapVertexStencilTables()->GetNumStencils();
}
Far::StencilTables const *concatVaryingStencils = varyingStencils;
if (varyingStencils and patchTables->GetEndCapVaryingStencilTables()) {
Far::StencilTables const *inVaryingStencils[] = {
varyingStencils, patchTables->GetEndCapVaryingStencilTables()
};
concatVaryingStencils =
Far::StencilTablesFactory::Create(2, inVaryingStencils);
}
// Create an Osd Compute context, used to "pose" the vertices with
// the stencils tables
delete g_computeCtx;
g_computeCtx = Osd::CpuComputeContext::Create(concatStencils, concatVaryingStencils);
// Create a limit Eval context with the patch tables
delete g_evalCtx;
g_evalCtx = Osd::CpuEvalLimitContext::Create(*patchTables);
g_kernelBatches.clear();
g_kernelBatches.push_back(Far::StencilTablesFactory::Create(*concatStencils));
}
{ // Create vertex primvar buffer for the CVs

View File

@ -56,6 +56,7 @@ static std::vector<ShapeDesc> g_defaultShapes;
#include <shapes/catmark_fan.h>
#include <shapes/catmark_flap.h>
#include <shapes/catmark_flap2.h>
#include <shapes/catmark_gregory_test0.h>
#include <shapes/catmark_gregory_test1.h>
#include <shapes/catmark_gregory_test2.h>
#include <shapes/catmark_gregory_test3.h>
@ -103,6 +104,7 @@ static void initShapes() {
g_defaultShapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_flap", catmark_flap, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_flap2", catmark_flap2, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) );

View File

@ -1033,6 +1033,7 @@ createOsdMesh(int level, int kernel) {
OpenSubdiv::Osd::MeshBitset bits;
bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
bits.set(OpenSubdiv::Osd::MeshPtexData, true);
bits.set(OpenSubdiv::Osd::MeshUseGregoryBasis, true);
int numVertexElements = g_adaptive ? 3 : 6;
int numVaryingElements = 0;

View File

@ -535,6 +535,7 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level, int kernel, Scheme scheme=
bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, doSingleCreasePatch);
bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, interleaveVarying);
bits.set(OpenSubdiv::Osd::MeshFVarData, g_displayStyle == kFaceVaryingColor);
bits.set(OpenSubdiv::Osd::MeshUseGregoryBasis, true);
int numVertexElements = 3;
int numVaryingElements =
@ -1157,7 +1158,7 @@ display() {
g_mesh->GetDrawContext()->GetPatchArrays();
// patch drawing
int patchCount[12][6][4]; // [Type][Pattern][Rotation] (see far/patchTables.h)
int patchCount[13][6][4]; // [Type][Pattern][Rotation] (see far/patchTables.h)
int numTotalPatches = 0;
int numDrawCalls = 0;
memset(patchCount, 0, sizeof(patchCount));
@ -1300,6 +1301,8 @@ display() {
patchCount[Descriptor::GREGORY][0][0]); y+= 20;
g_hud.DrawString(x, y, "Boundary Gregory : %d",
patchCount[Descriptor::GREGORY_BOUNDARY][0][0]); y+= 20;
g_hud.DrawString(x, y, "Gregory Basis : %d",
patchCount[Descriptor::GREGORY_BASIS][0][0]); y+= 20;
g_hud.DrawString(x, y, "Trans. Regular : %d %d %d %d %d",
patchCount[Descriptor::REGULAR][Descriptor::PATTERN0][0],
patchCount[Descriptor::REGULAR][Descriptor::PATTERN1][0],

View File

@ -60,6 +60,7 @@ static std::vector<ShapeDesc> g_defaultShapes;
#include <shapes/catmark_fvar_bound0.h>
#include <shapes/catmark_fvar_bound1.h>
#include <shapes/catmark_fvar_bound2.h>
#include <shapes/catmark_gregory_test0.h>
#include <shapes/catmark_gregory_test1.h>
#include <shapes/catmark_gregory_test2.h>
#include <shapes/catmark_gregory_test3.h>
@ -126,6 +127,7 @@ static void initShapes() {
g_defaultShapes.push_back( ShapeDesc("catmark_fvar_bound0", catmark_fvar_bound0, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_fvar_bound1", catmark_fvar_bound1, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_fvar_bound2", catmark_fvar_bound2, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) );

View File

@ -160,6 +160,7 @@ out block {
void emit(int index, vec3 normal)
{
outpt.v.position = inpt[index].v.position;
outpt.v.patchCoord = inpt[index].v.patchCoord;
#ifdef SMOOTH_NORMALS
outpt.v.normal = inpt[index].v.normal;
#else

View File

@ -103,7 +103,7 @@ vec2 computeUV( int c )
}
uniform float scale=0.025;
uniform float scale=0.01;
void main()
{
@ -116,10 +116,14 @@ void main()
vec2 ofs = inpt[0].data.xy;
emit(0, scale * (vec2( 1.0, -2.0)+ofs), uv + dim);
emit(1, scale * (vec2( 1.0, 2.0)+ofs), vec2(uv.x+dim.x, uv.y));
emit(2, scale * (vec2(-1.0, -2.0)+ofs), vec2(uv.x, uv.y+dim.y));
emit(3, scale * (vec2(-1.0, 2.0)+ofs), uv);
vec4 clipPos = ProjectionMatrix * inpt[0].position;
float s = scale * clipPos.w;
emit(0, s * (vec2( 1.0, -2.0)+ofs), uv + dim);
emit(1, s * (vec2( 1.0, 2.0)+ofs), vec2(uv.x+dim.x, uv.y));
emit(2, s * (vec2(-1.0, -2.0)+ofs), vec2(uv.x, uv.y+dim.y));
emit(3, s * (vec2(-1.0, 2.0)+ofs), uv);
EndPrimitive();
}

View File

@ -59,6 +59,7 @@ static std::vector<ShapeDesc> g_shapes;
#include <shapes/catmark_fvar_bound0.h>
#include <shapes/catmark_fvar_bound1.h>
#include <shapes/catmark_fvar_bound2.h>
#include <shapes/catmark_gregory_test0.h>
#include <shapes/catmark_gregory_test1.h>
#include <shapes/catmark_gregory_test2.h>
#include <shapes/catmark_gregory_test3.h>
@ -76,6 +77,8 @@ static std::vector<ShapeDesc> g_shapes;
#include <shapes/catmark_tent.h>
#include <shapes/catmark_torus.h>
#include <shapes/catmark_torus_creases0.h>
#include <shapes/catmark_smoothtris0.h>
#include <shapes/catmark_smoothtris1.h>
#include <shapes/loop_cube_creases0.h>
#include <shapes/loop_cube_creases1.h>
@ -113,6 +116,7 @@ static void initShapes() {
g_shapes.push_back( ShapeDesc("catmark_fvar_bound0", catmark_fvar_bound0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_fvar_bound1", catmark_fvar_bound1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_fvar_bound2", catmark_fvar_bound2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) );
@ -131,6 +135,8 @@ static void initShapes() {
g_shapes.push_back( ShapeDesc("catmark_tent", catmark_tent, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_torus", catmark_torus, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_car", catmark_car, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_bishop", catmark_bishop, kCatmark ) );

View File

@ -635,23 +635,18 @@ createGregoryBasis(OpenSubdiv::Far::PatchTables const & patchTables,
typedef OpenSubdiv::Far::PatchDescriptor PatchDescriptor;
int npatches = 0;
int patchArray = 0;
for (int array=0; array<(int)patchTables.GetNumPatchArrays(); ++array) {
if (patchTables.GetPatchArrayDescriptor(array).GetType()==
PatchDescriptor::GREGORY_BASIS) {
npatches = patchTables.GetNumPatches(array);
patchArray = array;
break;
}
}
int nedges = npatches * 20;
std::vector<int> vertsperedge(nedges), edgeindices(nedges*2);
std::vector<Vertex> edgeverts(npatches*20);
OpenSubdiv::Far::StencilTables const * gstencils =
patchTables.GetEndCapStencilTables();
assert(gstencils);
gstencils->UpdateValues(&vertexBuffer[0], &edgeverts[0]);
for (int patch=0; patch<npatches; ++patch) {
@ -664,33 +659,43 @@ createGregoryBasis(OpenSubdiv::Far::PatchTables const & patchTables,
int offset = patch * 20,
* vpe = &vertsperedge[offset],
* indices = &edgeindices[patch * 40];
OpenSubdiv::Far::ConstIndexArray const cvs =
patchTables.GetPatchVertices(patchArray, patch);
for (int i=0; i<20; ++i) {
vpe[i] = 2;
indices[i*2] = basisedges[i*2] + offset;
indices[i*2+1] = basisedges[i*2+1] + offset;
indices[i*2] = cvs[basisedges[i*2]];
indices[i*2+1] = cvs[basisedges[i*2+1]];
}
Vertex const * verts = &edgeverts[offset];
//Vertex const * verts = &edgeverts[offset];
static char buf[16];
for (int i=0; i<4; ++i) {
int vid = i * 5;
snprintf(buf, 16, " P%d", i);
g_font->Print3D(verts[vid].GetPos(), buf, 3);
snprintf(buf, 16, " Ep%d", i);
g_font->Print3D(verts[vid+1].GetPos(), buf, 3);
snprintf(buf, 16, " Em%d", i);
g_font->Print3D(verts[vid+2].GetPos(), buf, 3);
snprintf(buf, 16, " Fp%d", i);
g_font->Print3D(verts[vid+3].GetPos(), buf, 3);
snprintf(buf, 16, " Fm%d", i);
g_font->Print3D(verts[vid+4].GetPos(), buf, 3);
int vid = patch * 20 + i * 5;
const float *P = vertexBuffer[cvs[i*5+0]].GetPos();
const float *Ep = vertexBuffer[cvs[i*5+1]].GetPos();
const float *Em = vertexBuffer[cvs[i*5+2]].GetPos();
const float *Fp = vertexBuffer[cvs[i*5+3]].GetPos();
const float *Fm = vertexBuffer[cvs[i*5+4]].GetPos();
snprintf(buf, 16, " P%d (%d)", i, vid);
g_font->Print3D(P, buf, 3);
snprintf(buf, 16, " Ep%d (%d)", i, vid+1);
g_font->Print3D(Ep, buf, 3);
snprintf(buf, 16, " Em%d (%d)", i, vid+2);
g_font->Print3D(Em, buf, 3);
snprintf(buf, 16, " Fp%d (%d)", i, vid+3);
g_font->Print3D(Fp, buf, 3);
snprintf(buf, 16, " Fm%d (%d)", i, vid+4);
g_font->Print3D(Fm, buf, 3);
}
}
GLMesh::Options options;
gregoryWire.Initialize(options, (int)edgeverts.size(), (int)vertsperedge.size(),
&vertsperedge[0], &edgeindices[0], (float const * )&edgeverts[0]);
gregoryWire.Initialize(options, (int)vertexBuffer.size(), (int)vertsperedge.size(),
&vertsperedge[0], &edgeindices[0], (float const *)&vertexBuffer[0]);
}
//------------------------------------------------------------------------------
@ -770,17 +775,6 @@ createVtrMesh(Shape * shape, int maxlevel) {
// Stencils
//
// create vertex primvar data buffer
std::vector<Vertex> vertexBuffer(refiner->GetNumVerticesTotal());
Vertex * verts = &vertexBuffer[0];
// copy coarse vertices positions
int ncoarseverts = shape->GetNumVertices();
for (int i=0; i<ncoarseverts; ++i) {
float * ptr = &shape->verts[i*3];
verts[i].SetPosition(ptr[0], ptr[1], ptr[2]);
}
//#define no_stencils
#ifdef no_stencils
{
@ -800,8 +794,6 @@ createVtrMesh(Shape * shape, int maxlevel) {
stencilTables =
OpenSubdiv::Far::StencilTablesFactory::Create(*refiner, options);
stencilTables->UpdateValues(verts, verts + ncoarseverts);
}
#endif
@ -848,6 +840,39 @@ createVtrMesh(Shape * shape, int maxlevel) {
refiner->InterpolateFaceVarying(values, values + nCoarseValues);
}
}
// note: gregoryBasisStencilTables is owned by patchTables.
OpenSubdiv::Far::StencilTables const * gregoryBasisStencilTables =
patchTables->GetEndCapVertexStencilTables();
if (gregoryBasisStencilTables) {
OpenSubdiv::Far::StencilTables const *inStencilTables[] = {
stencilTables, gregoryBasisStencilTables
};
OpenSubdiv::Far::StencilTables const *concatStencilTables =
concatStencilTables = OpenSubdiv::Far::StencilTablesFactory::Create(
2, inStencilTables);
delete stencilTables;
stencilTables = concatStencilTables;
}
int numTotalVerts = shape->GetNumVertices() + stencilTables->GetNumStencils();
// create vertex primvar data buffer
std::vector<Vertex> vertexBuffer(numTotalVerts);
Vertex * verts = &vertexBuffer[0];
// copy coarse vertices positions
int ncoarseverts = shape->GetNumVertices();
for (int i=0; i<ncoarseverts; ++i) {
float * ptr = &shape->verts[i*3];
verts[i].SetPosition(ptr[0], ptr[1], ptr[2]);
}
//
// apply stencils
//
stencilTables->UpdateValues(verts, verts + ncoarseverts);
s.Stop();
//
@ -1391,7 +1416,7 @@ initHUD() {
g_hud.AddCheckBox("Adaptive (`)", g_Adaptive!=0, 10, 350, callbackAdaptive, 0, '`');
g_hud.AddSlider("Font Scale", 0.0f, 0.1f, 0.025f,
g_hud.AddSlider("Font Scale", 0.0f, 0.1f, 0.01f,
-900, -50, 100, false, callbackScale, 0);
for (int i = 1; i < 11; ++i) {

View File

@ -89,7 +89,8 @@ getQuadOffsets(Vtr::Level const & level, Vtr::Index fIndex,
16 + maxvalence - 3
// limit valence of 30 because we use a pre-computed closed-form 'ef' table
static const int MAX_VALENCE=30,
// XXXtakahito: revisit here to determine appropriate size
static const int MAX_VALENCE=(30*2),
MAX_ELEMS = GetNumMaxElems(MAX_VALENCE);
namespace Far {
@ -271,6 +272,9 @@ struct ProtoBasis {
//
Point P[4], Ep[4], Em[4], Fp[4], Fm[4];
// for varying interpolation
Point V[4];
};
int
@ -293,6 +297,7 @@ ProtoBasis::OffsetIndices(Index offset) {
Em[vid].OffsetIndices(offset);
Fp[vid].OffsetIndices(offset);
Fm[vid].OffsetIndices(offset);
V[vid].OffsetIndices(offset);
}
}
void
@ -349,6 +354,8 @@ ProtoBasis::ProtoBasis(Vtr::Level const & level, Index faceIndex, int fvarChanne
for (int vid=0; vid<4; ++vid) {
org[vid] = facePoints[vid];
// save for varying stencils
V[vid] = facePoints[vid];
int ringSize =
level.gatherQuadRegularRingAroundVertex(
@ -595,6 +602,8 @@ GregoryBasisFactory::Create(TopologyRefiner const & refiner,
basis.Copy(result->_sizes, &result->_indices[0], &result->_weights[0]);
// note: this function doesn't create varying stencils.
for (int i=0, offset=0; i<20; ++i) {
result->_offsets[i] = offset;
offset += result->_sizes[i];
@ -607,15 +616,19 @@ GregoryBasisFactory::Create(TopologyRefiner const & refiner,
// GregoryBasisFactory for Vertex StencilTables
//
GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner,
StencilTables const & stencils,
StencilTables const *stencils,
StencilTables const *varyingStencils,
int numpatches, int maxvalence) :
_currentStencil(0), _refiner(refiner),
_stencils(stencils), _alloc(GetNumMaxElems(maxvalence)) {
_stencils(stencils), _varyingStencils(varyingStencils),
_alloc(GetNumMaxElems(maxvalence)),
_varyingAlloc(GetNumMaxElems(maxvalence)) {
// Sanity check: the mesh must be adaptively refined
assert(not _refiner.IsUniform());
_alloc.Resize(numpatches * 20);
_varyingAlloc.Resize(numpatches * 20);
// Gregory limit stencils have indices that are relative to the level
// (maxlevel) of subdivision. These indices need to be offset to match
@ -624,9 +637,10 @@ GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner,
// (single weight of 1.0f) as place-holders for coarse mesh vertices,
// which also needs to be accounted for.
_stencilsOffset=-1;
{ int maxlevel = _refiner.GetMaxLevel(),
{
int maxlevel = _refiner.GetMaxLevel(),
nverts = _refiner.GetNumVerticesTotal(),
nstencils = _stencils.GetNumStencils();
nstencils = _stencils->GetNumStencils();
if (nstencils==nverts) {
// the table contain stencils for the control vertices
@ -645,17 +659,20 @@ GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner,
}
}
static inline void
factorizeBasisVertex(StencilTables const & stencils, Point const & p, ProtoStencil dst) {
factorizeBasisVertex(StencilTables const * stencils, Point const & p, ProtoStencil dst) {
// Use the Allocator to factorize the Gregory patch influence CVs with the
// supporting CVs from the stencil tables.
if (!stencils) return;
dst.Clear();
for (int j=0; j<p.GetSize(); ++j) {
dst.AddWithWeight(stencils,
dst.AddWithWeight(*stencils,
p.GetIndices()[j], p.GetWeights()[j]);
}
}
bool
GregoryBasisFactory::AddPatchBasis(Index faceIndex) {
GregoryBasisFactory::AddPatchBasis(Index faceIndex,
bool verticesMask[4][5]) {
// Gregory patches only exist on the hight
Vtr::Level const & level = _refiner.getLevel(_refiner.GetMaxLevel());
@ -677,21 +694,41 @@ GregoryBasisFactory::AddPatchBasis(Index faceIndex) {
// expressed as a linear combination of vertices from the coarse control
// mesh with no data dependencies
for (int i=0; i<4; ++i) {
int offset = _currentStencil + i * 5;
factorizeBasisVertex(_stencils, basis.P[i], _alloc[offset]);
factorizeBasisVertex(_stencils, basis.Ep[i], _alloc[offset+1]);
factorizeBasisVertex(_stencils, basis.Em[i], _alloc[offset+2]);
factorizeBasisVertex(_stencils, basis.Fp[i], _alloc[offset+3]);
factorizeBasisVertex(_stencils, basis.Fm[i], _alloc[offset+4]);
if (verticesMask[i][0]) {
factorizeBasisVertex(_stencils, basis.P[i], _alloc[_currentStencil]);
// need varying stencils only for corners
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
if (verticesMask[i][1]) {
factorizeBasisVertex(_stencils, basis.Ep[i], _alloc[_currentStencil]);
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
if (verticesMask[i][2]) {
factorizeBasisVertex(_stencils, basis.Em[i], _alloc[_currentStencil]);
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
if (verticesMask[i][3]) {
factorizeBasisVertex(_stencils, basis.Fp[i], _alloc[_currentStencil]);
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
if (verticesMask[i][4]) {
factorizeBasisVertex(_stencils, basis.Fm[i], _alloc[_currentStencil]);
factorizeBasisVertex(_varyingStencils, basis.V[i], _varyingAlloc[_currentStencil]);
++_currentStencil;
}
}
_currentStencil += 20;
return true;
}
StencilTables const *
GregoryBasisFactory::CreateStencilTables(int const permute[20]) {
GregoryBasisFactory::createStencilTables(int const permute[20],
StencilAllocator &alloc) {
int nstencils = (int)_alloc.GetNumStencils(),
nelems = _alloc.GetNumVerticesTotal();
int nstencils = _currentStencil;
int nelems = alloc.GetNumVerticesTotal();
if (nstencils==0 or nelems==0) {
return 0;
@ -716,7 +753,7 @@ GregoryBasisFactory::CreateStencilTables(int const permute[20]) {
index = baseIndex + permute[localIndex];
}
*dst._size = _alloc.CopyStencil(index, dst._indices, dst._weights);
*dst._size = alloc.CopyStencil(index, dst._indices, dst._weights);
dst.Next();
}

View File

@ -116,25 +116,39 @@ public:
// this factory is active.
//
GregoryBasisFactory(TopologyRefiner const & refiner,
StencilTables const & stencils,
StencilTables const * stencils,
StencilTables const * varyingStencils,
int numpatches, int maxvalence);
// Creates a basis for the face and adds it to the stencil pool allocator
bool AddPatchBasis(Index faceIndex);
// Creates a basis for the vertices specified in mask on the face and
// adds it to the stencil pool allocator
bool AddPatchBasis(Index faceIndex,
bool newVerticesMask[4][5]);
// After all the patches have been collected, create the final table
StencilTables const * CreateStencilTables(int const permute[20]=0);
StencilTables const * CreateVertexStencilTables(int const permute[20]=0) {
return createStencilTables(permute, _alloc);
}
StencilTables const * CreateVaryingStencilTables(int const permute[20]=0) {
return createStencilTables(permute, _varyingAlloc);
}
private:
StencilTables const * createStencilTables(int const permute[20],
StencilAllocator &alloc);
// XXX: StencilAllocator method's constness needs to be fixed.
int _currentStencil;
TopologyRefiner const & _refiner; // XXXX these should be smart pointers !
Index _stencilsOffset;
StencilTables const & _stencils;
StencilTables const * _stencils;
StencilTables const * _varyingStencils;
StencilAllocator _alloc;
StencilAllocator _varyingAlloc;
};
} // end namespace Far

View File

@ -33,7 +33,9 @@ namespace OPENSUBDIV_VERSION {
namespace Far {
PatchTables::PatchTables(int maxvalence) :
_maxValence(maxvalence), _endcapStencilTables(0) { }
_maxValence(maxvalence),
_endcapVertexStencilTables(0),
_endcapVaryingStencilTables(0) { }
// Copy constructor
// XXXX manuelk we need to eliminate this constructor (C++11 smart pointers)
@ -43,21 +45,21 @@ PatchTables::PatchTables(PatchTables const & src) :
_patchArrays(src._patchArrays),
_patchVerts(src._patchVerts),
_paramTable(src._paramTable),
#ifdef ENDCAP_TOPOPOLGY
_endcapTopology(src._endcapTopology),
#endif
_quadOffsetsTable(src._quadOffsetsTable),
_vertexValenceTable(src._vertexValenceTable),
_fvarChannels(src._fvarChannels),
_sharpnessIndices(src._sharpnessIndices),
_sharpnessValues(src._sharpnessValues) {
_endcapStencilTables = src._endcapStencilTables ?
new StencilTables(*src._endcapStencilTables) : 0;
_endcapVertexStencilTables = src._endcapVertexStencilTables ?
new StencilTables(*src._endcapVertexStencilTables) : 0;
_endcapVaryingStencilTables = src._endcapVaryingStencilTables ?
new StencilTables(*src._endcapVaryingStencilTables) : 0;
}
PatchTables::~PatchTables() {
delete _endcapStencilTables;
delete _endcapVertexStencilTables;
delete _endcapVaryingStencilTables;
}
//
@ -242,13 +244,7 @@ PatchTables::setBicubicFVarPatchChannelValues(int channel, int patchSize,
inline int
getPatchSize(PatchDescriptor desc) {
int size = desc.GetNumControlVertices();
// XXXX manuelk we do not store the topology for Gregory Basis
// patch types yet - so point to the 4 corners of the 0-ring
if (desc.GetType() == PatchDescriptor::GREGORY_BASIS) {
size = 4;
}
return size;
return desc.GetNumControlVertices();
}
void
@ -339,13 +335,7 @@ PatchTables::GetPatchArrayVertices(int arrayIndex) const {
ConstIndexArray
PatchTables::GetPatchVertices(PatchHandle const & handle) const {
PatchArray const & pa = getPatchArray(handle.arrayIndex);
Index vert = pa.vertIndex;
// XXXX manuelk we do not store the topology for Gregory Basis
// patch types yet - so point to the 4 corners of the 0-ring
vert += (pa.desc.GetType() == PatchDescriptor::GREGORY_BASIS) ?
handle.vertIndex / 5 : handle.vertIndex;
assert(vert<(Index)_patchVerts.size());
Index vert = pa.vertIndex + handle.vertIndex;
return ConstIndexArray(&_patchVerts[vert], getPatchSize(pa.desc));
}
ConstIndexArray
@ -409,7 +399,7 @@ bool
PatchTables::IsFeatureAdaptive() const {
// check for presence of tables only used by adaptive patches
if (not _vertexValenceTable.empty() or _endcapStencilTables)
if (not _vertexValenceTable.empty() or _endcapVertexStencilTables)
return true;
// otherwise, we have to check each patch array

View File

@ -174,11 +174,9 @@ public:
}
/// \brief Returns a stencil table for the control vertices of end-cap patches
StencilTables const * GetEndCapStencilTables() const { return _endcapStencilTables; }
StencilTables const * GetEndCapVertexStencilTables() const { return _endcapVertexStencilTables; }
StencilTables const * GetEndCapVaryingStencilTables() const { return _endcapVaryingStencilTables; }
Index GetEndCapStencilIndex(PatchHandle const & handle) const {
return handle.vertIndex;
}
//@}
@ -418,10 +416,8 @@ private:
// XXXX manuelk end-cap stencils will obsolete the other tables
StencilTables const * _endcapStencilTables;
#ifdef ENDCAP_TOPOPOLGY
std::vector<Index> _endcapTopology;
#endif
StencilTables const * _endcapVertexStencilTables;
StencilTables const * _endcapVaryingStencilTables;
QuadOffsetsTable _quadOffsetsTable; // Quad offsets (for Gregory patches)
VertexValenceTable _vertexValenceTable; // Vertex valence table (for Gregory patches)
@ -494,10 +490,10 @@ PatchTables::Evaluate(PatchHandle const & handle, float s, float t,
}
} else if (ptype==PatchDescriptor::GREGORY_BASIS) {
assert(_endcapStencilTables);
assert(_endcapVertexStencilTables);
GetBezierWeights(bits, s, t, Q, Qd1, Qd2);
InterpolateGregoryPatch(_endcapStencilTables, handle.vertIndex,
InterpolateGregoryPatch(_endcapVertexStencilTables, handle.vertIndex,
s, t, Q, Qd1, Qd2, src, dst);
} else if (ptype==PatchDescriptor::QUADS) {

View File

@ -904,7 +904,6 @@ PatchTablesFactory::computePatchParam(TopologyRefiner const & refiner,
return ++coord;
}
#ifdef ENDCAP_TOPOPOLGY
// XXXX manuelk work in progress for end-cap topology gathering
//
// Populates the topology table used by Gregory-basis patches
@ -913,17 +912,21 @@ PatchTablesFactory::computePatchParam(TopologyRefiner const & refiner,
// Note 2: this code attempts to identify basis vertices shared along
// gregory patch edges
static int
gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVertices,
gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex,
int numGregoryBasisPatches,
int numGregoryBasisVertices,
PatchFaceTag const * levelPatchTags,
bool skip[0], std::vector<Index> & basisIndices, PatchTables::PTable & topology) {
std::vector<Index> & basisIndices,
PatchTables::PatchVertsTable & topology,
bool newVerticesMask[4][5]) {
assert(not topology.empty());
Index * dest = &topology[basisIndices.size()*20];
Index * dest = &topology[numGregoryBasisPatches*20];
assert(Vtr::INDEX_INVALID==0xFFFFFFFF);
memset(dest, 0xFF, 20*sizeof(Index));
IndexArray fedges = level.getFaceEdges(faceIndex);
ConstIndexArray fedges = level.getFaceEdges(faceIndex);
assert(fedges.size()==4);
for (int i=0; i<4; ++i) {
@ -931,7 +934,7 @@ gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVert
adjface = 0;
{ // Gather adjacent faces
IndexArray adjfaces = level.getEdgeFaces(edge);
ConstIndexArray adjfaces = level.getEdgeFaces(edge);
for (int i=0; i<adjfaces.size(); ++i) {
if (adjfaces[i]==faceIndex) {
// XXXX manuelk if 'edge' is non-manifold, arbitrarily pick the
@ -943,12 +946,12 @@ gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVert
}
// We are looking for adjacent faces that:
// - exist (no boundary)
// - have alraedy been processed (known CV indices)
// - have already been processed (known CV indices)
// - are also Gregory basis patches
if (adjface!=Vtr::INDEX_INVALID and (adjface < faceIndex) and
(not levelPatchTags[adjface]._isRegular)) {
IndexArray aedges = level.getFaceEdges(adjface);
ConstIndexArray aedges = level.getFaceEdges(adjface);
int aedge = aedges.FindIndexIn4Tuple(edge);
assert(aedge!=Vtr::INDEX_INVALID);
@ -963,6 +966,11 @@ gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVert
basisIndices.size(), sizeof(Index), compare::op);
int srcBasisIdx = ptr - &basisIndices[0];
if (!ptr) {
// if the adjface is hole, it won't be found
break;
}
assert(ptr and srcBasisIdx>=0 and srcBasisIdx<(int)basisIndices.size());
// Copy the indices of CVs from the face on the other side of the
@ -973,23 +981,26 @@ gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVert
{15, 16, 2, 0} };
Index * src = &topology[srcBasisIdx*20];
for (int j=0; j<4; ++j) {
dest[i*4+j] = src[gregoryEdgeVerts[aedge][j]];
// invert direction
dest[gregoryEdgeVerts[i][3-j]] = src[gregoryEdgeVerts[aedge][j]];
}
skip[i] = true;
}
}
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 5; ++j) {
if (dest[i*5+j]==Vtr::INDEX_INVALID) {
// assign new vertex
dest[i*5+j] = numGregoryBasisVertices++;
newVerticesMask[i][j] = true;
} else {
skip[i] = false;
// share vertex
newVerticesMask[i][j] = false;
}
}
for (int i=0; i<20; ++i) {
if (dest[i]==Vtr::INDEX_INVALID) {
dest[i] = numVertices++;
}
}
basisIndices.push_back(faceIndex);
return numVertices;
return numGregoryBasisVertices;
}
#endif
//
// Indexing sharpnesses
@ -1602,27 +1613,37 @@ PatchTablesFactory::populateAdaptivePatches(AdaptiveContext & context) {
bool hasGregoryPatches =
context.RequiresLegacyGregoryPatches() or context.RequiresGregoryBasisPatches();
GregoryBasisFactory * gregoryStencilsFactory = 0;
#ifdef ENDCAP_TOPOPOLGY
int numGregoryBasisVertices=0;
int numGregoryBasisPatches=0;
std::vector<Index> gregoryBasisIndices;
#endif
std::vector<Index> endcapTopology;
if (hasGregoryPatches) {
StencilTables const * adaptiveStencils = context.options.adaptiveStencilTables;
if (adaptiveStencils and context.RequiresGregoryBasisPatches()) {
StencilTables const * adaptiveVertexStencils =
context.options.adaptiveStencilTables;
StencilTables const * adaptiveVaryingStencils =
context.options.adaptiveVaryingStencilTables;
if (adaptiveVertexStencils and
context.RequiresGregoryBasisPatches()) {
assert(not context.RequiresLegacyGregoryPatches());
int maxvalence = refiner.GetMaxValence(),
npatches = context.patchInventory.GP;
gregoryStencilsFactory =
new GregoryBasisFactory(refiner, *adaptiveStencils, npatches, maxvalence);
#ifdef ENDCAP_TOPOPOLGY
gregoryStencilsFactory =
new GregoryBasisFactory(refiner,
adaptiveVertexStencils,
adaptiveVaryingStencils,
npatches, maxvalence);
// XXX reconsider these variable names:
// gregoryBasisIndices holds patch indices,
// endcapTopology contains vert indices.
gregoryBasisIndices.reserve(npatches);
tables->_endcapTopology.resize(npatches*20);
#endif
endcapTopology.resize(npatches*20);
}
gregoryVertexFlags.resize(refiner.GetNumVerticesTotal(), false);
}
@ -1739,19 +1760,24 @@ PatchTablesFactory::populateAdaptivePatches(AdaptiveContext & context) {
// Gregory basis end-cap (20 CVs - no quad-offsets / valence tables)
assert(i==refiner.GetMaxLevel());
// Gregory Boundary Patch (4 CVs 0-ring for varying interpolation)
Vtr::ConstIndexArray faceVerts = level->getFaceVertices(faceIndex);
for (int j = 0; j < 4; ++j) {
iptrs.GP[j] = faceVerts[j] + levelVertOffset;
gregoryVertexFlags[iptrs.GP[j]] = true;
}
iptrs.GP += 4;
bool newVerticesMask[4][5];
numGregoryBasisVertices = gatherGregoryBasisTopology(*level, faceIndex,
numGregoryBasisPatches,
numGregoryBasisVertices,
levelPatchTags,
gregoryBasisIndices,
endcapTopology,
newVerticesMask);
gregoryStencilsFactory->AddPatchBasis(faceIndex, newVerticesMask);
#ifdef ENDCAP_TOPOPOLGY
bool edgeSkip[4];
numGregoryBasisVertices = gatherGregoryBasisTopology(*level, faceIndex, numGregoryBasisVertices,
levelPatchTags, edgeSkip, gregoryBasisIndices, tables->_endcapTopology);
#endif
gregoryStencilsFactory->AddPatchBasis(faceIndex);
// populate 20 indices with offset
for (int j = 0; j < 20; ++j) {
iptrs.GP[j] = endcapTopology[numGregoryBasisPatches*20+j]
+ refiner.GetNumVerticesTotal();
}
iptrs.GP += 20;
++numGregoryBasisPatches;
pptrs.GP = computePatchParam(refiner, i, faceIndex, 0, pptrs.GP);
@ -1807,8 +1833,10 @@ PatchTablesFactory::populateAdaptivePatches(AdaptiveContext & context) {
}
if (gregoryStencilsFactory) {
tables->_endcapStencilTables =
gregoryStencilsFactory->CreateStencilTables();
tables->_endcapVertexStencilTables =
gregoryStencilsFactory->CreateVertexStencilTables();
tables->_endcapVaryingStencilTables =
gregoryStencilsFactory->CreateVaryingStencilTables();
delete gregoryStencilsFactory;
}

View File

@ -62,7 +62,9 @@ public:
useFVarQuadEndCaps(true), // XXXX change to false when FVar Gregory is ready
numFVarChannels(-1),
fvarChannelIndices(0),
adaptiveStencilTables(0) { }
adaptiveStencilTables(0),
adaptiveVaryingStencilTables(0)
{ }
unsigned int generateAllLevels : 1, ///< Include levels from 'firstLevel' to 'maxLevel' (Uniform mode only)
triangulateQuads : 1, ///< Triangulate 'QUADS' primitives (Uniform mode only)
@ -79,6 +81,7 @@ public:
StencilTables const * adaptiveStencilTables; ///< Passing a valid stencil table allows the factory to generate
///< stencils for gregory patches and replace them with a much
///< more efficient basis.
StencilTables const * adaptiveVaryingStencilTables;
};
/// \brief Factory constructor for PatchTables

View File

@ -190,40 +190,53 @@ StencilTablesFactory::Create(TopologyRefiner const & refiner,
StencilTables const *
StencilTablesFactory::Create(int numTables, StencilTables const ** tables) {
StencilTables * result = new StencilTables;
// XXXtakahito:
// This function returns NULL for empty inputs or erroneous condition.
// It's convenient for skipping varying stencils etc, however,
// other Create() API returns an empty stencil instead of NULL.
// They need to be consistent.
if ( (numTables<=0) or (not tables)) {
return result;
return NULL;
}
int ncvs = tables[0]->GetNumControlVertices(),
int ncvs = -1,
nstencils = 0,
nelems = 0;
for (int i=0; i<numTables; ++i) {
StencilTables const & st = *tables[i];
StencilTables const * st = tables[i];
// allow the tables could have a null entry.
if (!st) continue;
if (st.GetNumControlVertices()!=ncvs) {
return result;
if (ncvs >= 0 and st->GetNumControlVertices() != ncvs) {
return NULL;
}
nstencils += st.GetNumStencils();
nelems += (int)st.GetControlIndices().size();
ncvs = st->GetNumControlVertices();
nstencils += st->GetNumStencils();
nelems += (int)st->GetControlIndices().size();
}
if (ncvs == -1) {
return NULL;
}
StencilTables * result = new StencilTables;
result->resize(nstencils, nelems);
unsigned char * sizes = &result->_sizes[0];
Index * indices = &result->_indices[0];
float * weights = &result->_weights[0];
for (int i=0; i<numTables; ++i) {
StencilTables const & st = *tables[i];
StencilTables const * st = tables[i];
if (!st) continue;
int st_nstencils = st.GetNumStencils(),
st_nelems = (int)st._indices.size();
memcpy(sizes, &st._sizes[0], st_nstencils*sizeof(unsigned char));
memcpy(indices, &st._indices[0], st_nelems*sizeof(Index));
memcpy(weights, &st._weights[0], st_nelems*sizeof(float));
int st_nstencils = st->GetNumStencils(),
st_nelems = (int)st->_indices.size();
memcpy(sizes, &st->_sizes[0], st_nstencils*sizeof(unsigned char));
memcpy(indices, &st->_indices[0], st_nelems*sizeof(Index));
memcpy(weights, &st->_weights[0], st_nelems*sizeof(float));
sizes += st_nstencils;
indices += st_nelems;

View File

@ -200,6 +200,7 @@ if( OPENGL_FOUND OR OPENGLES_FOUND )
glslPatchCommon.glsl
glslPatchBSpline.glsl
glslPatchGregory.glsl
glslPatchGregoryBasis.glsl
glslPatchTransition.glsl
glslPtexCommon.glsl
)

View File

@ -105,12 +105,8 @@ CpuEvalLimitController::EvalLimitSample( LimitLocation const & coord,
outQ, outDQU, outDQV );
break;
case Desc::GREGORY_BASIS : {
Far::StencilTables const * stencils =
ptables.GetEndCapStencilTables();
assert(stencils and stencils->GetNumStencils()>0);
evalGregoryBasis( pparam.bitField, s, t,
*stencils,
ptables.GetEndCapStencilIndex(*handle),
cvs.begin(),
vertexData.inDesc,
vertexData.in,
vertexData.outDesc,
@ -206,12 +202,8 @@ CpuEvalLimitController::_EvalLimitSample( LimitLocation const & coords,
out, outDu, outDv );
break;
case Desc::GREGORY_BASIS : {
Far::StencilTables const * stencils =
ptables.GetEndCapStencilTables();
assert(stencils and stencils->GetNumStencils()>0);
evalGregoryBasis( pparam.bitField, s, t,
*stencils,
ptables.GetEndCapStencilIndex(*handle),
cvs.begin(),
vertexData.inDesc,
vertexData.in,
vertexData.outDesc,
@ -236,7 +228,8 @@ CpuEvalLimitController::_EvalLimitSample( LimitLocation const & coords,
static int const zeroRings[6][4] = { {5, 6,10, 9}, // regular
{1, 2, 6, 5}, // boundary / single-crease
{1, 2, 5, 4}, // corner
{0, 1, 2, 3} }; // no permutation
{0, 1, 2, 3}, // no permutation
{0, 5, 10, 15} }; // gregory basis
int const * permute = 0;
switch (desc.GetType()) {
@ -245,8 +238,8 @@ CpuEvalLimitController::_EvalLimitSample( LimitLocation const & coords,
case Desc::BOUNDARY : permute = zeroRings[1]; break;
case Desc::CORNER : permute = zeroRings[2]; break;
case Desc::GREGORY :
case Desc::GREGORY_BOUNDARY :
case Desc::GREGORY_BASIS : permute = zeroRings[3]; break;
case Desc::GREGORY_BOUNDARY : permute = zeroRings[3]; break;
case Desc::GREGORY_BASIS : permute = zeroRings[4]; break;
default:
assert(0);
};

View File

@ -372,8 +372,7 @@ evalCorner(Far::PatchParam::BitField bits,
void
evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v,
Far::StencilTables const & basisStencils,
int stencilIndex,
Far::Index const * vertexIndices,
VertexBufferDescriptor const & inDesc,
float const * inQ,
VertexBufferDescriptor const & outDesc,
@ -390,10 +389,10 @@ evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v,
float const *inOffset = inQ + inDesc.offset;
float * Q = outQ + outDesc.offset;
outQ += outDesc.offset;
// clear result
memset(Q, 0, length*sizeof(float));
memset(outQ, 0, length*sizeof(float));
if (outDQU) {
memset(outDQU, 0, length*sizeof(float));
}
@ -404,22 +403,17 @@ evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v,
float uu = 1-u,
vv = 1-v;
// remark #1572: floating-point equality and inequality comparisons are unreliable
#ifdef __INvEL_COMPILER
#pragma warning diuable 1572
#ifdef __INTEL_COMPILER
#pragma warning disable 1572
#endif
float d11 = u+v; if(u+v==0.0f) d11 = 1.0f;
float d12 = uu+v; if(uu+v==0.0f) d12 = 1.0f;
float d21 = u+vv; if(u+vv==0.0f) d21 = 1.0f;
float d22 = uu+vv; if(uu+vv==0.0f) d22 = 1.0f;
#ifdef __INvEL_COMPILER
#ifdef __INTEL_COMPILER
#pragma warning enable 1572
#endif
float weights[4][2] = { { u/d11, v/d11 },
{ uu/d12, v/d12 },
{ u/d21, vv/d21 },
{ uu/d22, vv/d22 } };
//
// P3 e3- e2+ P2
// O--------O--------O--------O
@ -441,89 +435,44 @@ evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v,
// P0 e0+ e1- P1
//
float const *v3 = inOffset + vertexIndices[3]*inDesc.stride,
*v4 = inOffset + vertexIndices[4]*inDesc.stride,
*v8 = inOffset + vertexIndices[8]*inDesc.stride,
*v9 = inOffset + vertexIndices[9]*inDesc.stride,
*v13 = inOffset + vertexIndices[13]*inDesc.stride,
*v14 = inOffset + vertexIndices[14]*inDesc.stride,
*v18 = inOffset + vertexIndices[18]*inDesc.stride,
*v19 = inOffset + vertexIndices[19]*inDesc.stride;
float *CP = (float*)alloca(inDesc.length*4*sizeof(float));
for (int k=0; k<inDesc.length; ++k) {
CP[0*inDesc.length + k] = (u * v3[k] + v * v4[k])/d11;
CP[1*inDesc.length + k] = (uu * v9[k] + v * v8[k])/d12;
CP[2*inDesc.length + k] = (u * v19[k] + vv * v18[k])/d21;
CP[3*inDesc.length + k] = (uu * v13[k] + vv * v14[k])/d22;
}
// XXXX manuelk re-order stencils in factory and get rid of permutation ?
static int const permute[16] =
{ 0, 1, 7, 5, 2, -1, -1, 6, 16, -1, -1, 12, 15, 17, 11, 10 };
{ 0, 1, 7, 5, 2, 3, 8, 6, 16, 18, 13, 12, 15, 17, 11, 10 };
int offset = stencilIndex;
for (int i=0, fcount=0; i<16; ++i) {
for (int i=0; i<16; ++i) {
int index = permute[i];
if (index==-1) {
float const * in = inOffset + vertexIndices[index]*inDesc.stride;
if (index < 0) {
in = &CP[-index-1];
}
// 0-ring vertex: blend 2 extra basis CVs
static int const fpermute[4][2] = { {3, 4}, {9, 8}, {19, 18}, {13, 14} };
assert(fcount < 4);
int v0 = fpermute[fcount][0],
v1 = fpermute[fcount][1];
Far::Stencil s0 = basisStencils.GetStencil(offset + v0),
s1 = basisStencils.GetStencil(offset + v1);
float w0=weights[fcount][0],
w1=weights[fcount][1];
{
Far::Index const * srcIndices = s0.GetVertexIndices();
float const * srcWeights = s0.GetWeights();
for (int j=0; j<s0.GetSize(); ++j) {
float const * in = inOffset + srcIndices[j]*inDesc.stride;
float w = BU[i] * w0 * srcWeights[j],
dw1 = DU[i] * w0 * srcWeights[j],
dw2 = DV[i] * w0 * srcWeights[
j];
for (int k=0; k<length; ++k) {
Q[k] += in[k] * w;
for (int k=0; k<inDesc.length; ++k) {
outQ[k] += BU[i] * in[k];
if (outDQU) {
outDQU[k] += in[k] * dw1;
outDQU[k] += DU[i] * in[k];
}
if (outDQV) {
outDQV[k] += in[k] * dw2;
}
}
}
}
{
Far::Index const * srcIndices = s1.GetVertexIndices();
float const * srcWeights = s1.GetWeights();
for (int j=0; j<s1.GetSize(); ++j) {
float const * in = inOffset + srcIndices[j]*inDesc.stride;
float w = BU[i] * w1 * srcWeights[j],
dw1 = DU[i] * w1 * srcWeights[j],
dw2 = DV[i] * w1 * srcWeights[j];
for (int k=0; k<length; ++k) {
Q[k] += in[k] * w;
if (outDQU) {
outDQU[k] += in[k] * dw1;
}
if (outDQV) {
outDQV[k] += in[k] * dw2;
}
}
}
}
++fcount;
} else {
Far::Stencil s = basisStencils.GetStencil(offset + index);
Far::Index const * srcIndices = s.GetVertexIndices();
float const * srcWeights = s.GetWeights();
for (int j=0; j<s.GetSize(); ++j) {
float const * in = inOffset + srcIndices[j]*inDesc.stride;
float w = BU[i] * srcWeights[j],
dw1 = DU[i] * srcWeights[j],
dw2 = DV[i] * srcWeights[j];
for (int k=0; k<length; ++k) {
Q[k] += in[k] * w;
if (outDQU) {
outDQU[k] += in[k] * dw1;
}
if (outDQV) {
outDQV[k] += in[k] * dw2;
}
}
outDQV[k] += DV[i] * in[k];
}
}
}

View File

@ -86,9 +86,9 @@ evalCorner(Far::PatchParam::BitField bits,
float * outDQV );
void
evalGregoryBasis(Far::PatchParam::BitField bits, float u, float v,
Far::StencilTables const & basisStencils,
int stencilIndex,
evalGregoryBasis(Far::PatchParam::BitField bits,
float u, float v,
Far::Index const *vertsIndices,
VertexBufferDescriptor const & inDesc,
float const * inQ,
VertexBufferDescriptor const & outDesc,

View File

@ -52,6 +52,9 @@ static const char *bsplineShaderSource =
static const char *gregoryShaderSource =
#include "glslPatchGregory.gen.h"
;
static const char *gregoryBasisShaderSource =
#include "glslPatchGregoryBasis.gen.h"
;
static const char *transitionShaderSource =
#include "glslPatchTransition.gen.h"
;
@ -156,6 +159,17 @@ GLDrawRegistryBase::_CreateDrawSourceConfig(
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_SHADER");
sconfig->tessEvalShader.AddDefine("OSD_PATCH_GREGORY_BOUNDARY");
break;
case Far::PatchDescriptor::GREGORY_BASIS:
sconfig->vertexShader.source = gregoryBasisShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_GREGORY_BASIS_SHADER");
sconfig->tessControlShader.source = gregoryBasisShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_GREGORY_BASIS_SHADER");
sconfig->tessEvalShader.source = gregoryBasisShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_GREGORY_BASIS_SHADER");
break;
default: // POINTS, LINES, QUADS, TRIANGLES
// do nothing
break;

View File

@ -68,14 +68,31 @@ public:
_drawContext(0)
{
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
GLMeshInterface::refineMesh(*_refiner, level,
bits.test(MeshAdaptive),
bits.test(MeshUseSingleCreasePatch));
int numElements =
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
int numVertexElementsInterleaved = numVertexElements +
(bits.test(MeshInterleaveVarying) ? numVaryingElements : 0);
int numVaryingElementsNonInterleaved =
(bits.test(MeshInterleaveVarying) ? 0 : numVaryingElements);
initializeComputeContext(numVertexElements, numVaryingElements);
initializeContext(numVertexElements, numVaryingElements,
numVertexElementsInterleaved, level, bits);
initializeDrawContext(numElements, level, bits);
int numVertices = GLMeshInterface::getNumVertices(*_refiner);
// FIXME: need a better API for numTotalVertices.
if (_patchTables->GetEndCapVertexStencilTables()) {
numVertices += _patchTables->GetEndCapVertexStencilTables()->GetNumStencils();
}
initializeVertexBuffers(numVertices,
numVertexElementsInterleaved,
numVaryingElementsNonInterleaved);
// will retire soon
_drawContext->UpdateVertexTexture(_vertexBuffer);
}
Mesh(ComputeController * computeController,
@ -170,8 +187,9 @@ public:
private:
void initializeComputeContext(int numVertexElements,
int numVaryingElements ) {
void initializeContext(int numVertexElements,
int numVaryingElements,
int numElements, int level, MeshBitset bits) {
assert(_refiner);
@ -185,7 +203,6 @@ private:
vertexStencils = Far::StencilTablesFactory::Create(*_refiner, options);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
}
if (numVaryingElements>0) {
@ -195,44 +212,69 @@ private:
varyingStencils = Far::StencilTablesFactory::Create(*_refiner, options);
}
_computeContext = ComputeContext::Create(vertexStencils, varyingStencils);
assert(_refiner);
Far::PatchTablesFactory::Options poptions(level);
poptions.generateFVarTables = bits.test(MeshFVarData);
poptions.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
if (bits.test(MeshUseGregoryBasis)) {
poptions.adaptiveStencilTables = vertexStencils;
poptions.adaptiveVaryingStencilTables = varyingStencils;
}
_patchTables = Far::PatchTablesFactory::Create(*_refiner, poptions);
_drawContext = DrawContext::Create(_patchTables, numElements);
// XXX: factory API fix needed
// merge greogry basis stencils
Far::StencilTables const * endCapVertexStencils =
_patchTables->GetEndCapVertexStencilTables();
if (endCapVertexStencils) {
Far::StencilTables const * endCapVaryingStencils =
_patchTables->GetEndCapVaryingStencilTables();
// concatinate vertexStencils and endCapStencils.
// note that endCapStensils is owned by patchTable.
Far::StencilTables const *inStencils[] = {
vertexStencils, endCapVertexStencils
};
Far::StencilTables const *concatStencils =
Far::StencilTablesFactory::Create(2, inStencils);
Far::StencilTables const *inVaryingStencils[] = {
varyingStencils, endCapVaryingStencils
};
Far::StencilTables const *concatVaryingStencils =
Far::StencilTablesFactory::Create(2, inVaryingStencils);
delete vertexStencils;
vertexStencils = concatStencils;
delete varyingStencils;
varyingStencils = concatVaryingStencils;
}
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
_computeContext = ComputeContext::Create(vertexStencils,
varyingStencils);
delete vertexStencils;
delete varyingStencils;
}
void initializeDrawContext(int numElements, int level, MeshBitset bits) {
assert(_refiner and _vertexBuffer);
Far::PatchTablesFactory::Options options(level);
options.generateFVarTables = bits.test(MeshFVarData);
options.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
_patchTables = Far::PatchTablesFactory::Create(*_refiner, options);
_drawContext = DrawContext::Create(_patchTables, numElements);
_drawContext->UpdateVertexTexture(_vertexBuffer);
}
int initializeVertexBuffers(int numVertexElements,
int numVaryingElements, MeshBitset bits) {
int numVertices = GLMeshInterface::getNumVertices(*_refiner);
int numElements = numVertexElements +
(bits.test(MeshInterleaveVarying) ? numVaryingElements : 0);
void initializeVertexBuffers(int numVertices,
int numVertexElements,
int numVaryingElements) {
if (numVertexElements) {
_vertexBuffer = VertexBuffer::Create(numElements, numVertices);
_vertexBuffer = VertexBuffer::Create(numVertexElements, numVertices);
}
if (numVaryingElements>0 and (not bits.test(MeshInterleaveVarying))) {
if (numVaryingElements) {
_varyingBuffer = VertexBuffer::Create(numVaryingElements, numVertices);
}
return numElements;
}
Far::TopologyRefiner * _refiner;
@ -280,14 +322,32 @@ public:
{
assert(_refiner);
GLMeshInterface::refineMesh(*_refiner, level, bits.test(MeshAdaptive), bits.test(MeshUseSingleCreasePatch));
GLMeshInterface::refineMesh(*_refiner, level,
bits.test(MeshAdaptive),
bits.test(MeshUseSingleCreasePatch));
int numElements =
initializeVertexBuffers(numVertexElements, numVaryingElements, bits);
initializeComputeContext(numVertexElements, numVaryingElements);
int numVertexElementsInterleaved = numVertexElements +
(bits.test(MeshInterleaveVarying) ? numVaryingElements : 0);
int numVaryingElementsNonInterleaved =
(bits.test(MeshInterleaveVarying) ? 0 : numVaryingElements);
initializeDrawContext(numElements, level, bits);
initializeContext(numVertexElements, numVaryingElements,
numVertexElementsInterleaved, level, bits);
int numVertices = GLMeshInterface::getNumVertices(*_refiner);
// FIXME: need better API for total number of vertices.
if (_patchTables->GetEndCapVertexStencilTables()) {
numVertices += _patchTables->GetEndCapVertexStencilTables()->GetNumStencils();
}
initializeVertexBuffers(numVertices,
numVertexElementsInterleaved,
numVaryingElementsNonInterleaved);
// will retire
_drawContext->UpdateVertexTexture(_vertexBuffer);
}
Mesh(ComputeController * computeController,
@ -382,9 +442,9 @@ public:
private:
void initializeComputeContext(int numVertexElements,
int numVaryingElements ) {
void initializeContext(int numVertexElements,
int numVaryingElements,
int numElements, int level, MeshBitset bits) {
assert(_refiner);
Far::StencilTablesFactory::Options options;
@ -396,8 +456,6 @@ private:
if (numVertexElements>0) {
vertexStencils = Far::StencilTablesFactory::Create(*_refiner, options);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
}
if (numVaryingElements>0) {
@ -409,41 +467,73 @@ private:
_computeContext = ComputeContext::Create(_clContext, vertexStencils, varyingStencils);
assert(_refiner);
Far::PatchTablesFactory::Options poptions(level);
poptions.generateFVarTables = bits.test(MeshFVarData);
poptions.useSingleCreasePatch = bits.test(MeshUseSingleCreasePatch);
// use gregory stencils
if (bits.test(MeshUseGregoryBasis)) {
poptions.adaptiveStencilTables = vertexStencils;
poptions.adaptiveVaryingStencilTables = varyingStencils;
}
_patchTables = Far::PatchTablesFactory::Create(*_refiner, poptions);
_drawContext = DrawContext::Create(_patchTables, numElements);
Far::StencilTables const *endCapVertexStencils =
_patchTables->GetEndCapVertexStencilTables();
if (endCapVertexStencils) {
Far::StencilTables const *endCapVaryingStencils =
_patchTables->GetEndCapVaryingStencilTables();
// concatinate vertexStencils and endCapStencils.
// note that endCapStensils is owned by patchTable.
Far::StencilTables const *inStencils[] = {
vertexStencils, endCapVertexStencils
};
Far::StencilTables const *concatStencils =
Far::StencilTablesFactory::Create(2, inStencils);
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*concatStencils));
Far::StencilTables const *inVaryingStencils[] = {
varyingStencils, endCapVaryingStencils
};
Far::StencilTables const *concatVaryingStencils =
Far::StencilTablesFactory::Create(2, inVaryingStencils);
delete vertexStencils;
vertexStencils = concatStencils;
delete varyingStencils;
varyingStencils = concatVaryingStencils;
}
_kernelBatches.push_back(Far::StencilTablesFactory::Create(*vertexStencils));
_computeContext = ComputeContext::Create(_clContext,
vertexStencils,
varyingStencils);
delete vertexStencils;
delete varyingStencils;
}
void initializeDrawContext(int numElements, int level, MeshBitset bits) {
assert(_refiner and _vertexBuffer);
Far::PatchTablesFactory::Options options(level);
options.generateFVarTables = bits.test(MeshFVarData);
_patchTables = Far::PatchTablesFactory::Create(*_refiner);
_drawContext = DrawContext::Create(_patchTables, numElements);
_drawContext->UpdateVertexTexture(_vertexBuffer);
}
int initializeVertexBuffers(int numVertexElements,
int numVaryingElements, MeshBitset bits) {
int numVertices = GLMeshInterface::getNumVertices(*_refiner);
int numElements = numVertexElements +
(bits.test(MeshInterleaveVarying) ? numVaryingElements : 0);
void initializeVertexBuffers(int numVertices,
int numVertexElements,
int numVaryingElements) {
if (numVertexElements) {
_vertexBuffer = VertexBuffer::Create(numElements, numVertices, _clContext);
_vertexBuffer = VertexBuffer::Create(numVertexElements, numVertices, _clContext);
}
if (numVaryingElements>0 and (not bits.test(MeshInterleaveVarying))) {
if (numVaryingElements) {
_varyingBuffer = VertexBuffer::Create(numVaryingElements, numVertices, _clContext);
}
return numElements;
}
Far::TopologyRefiner * _refiner;

View File

@ -93,7 +93,9 @@ struct ControlVertex {
vec4 position;
centroid vec4 patchCoord; // u, v, level, faceID
ivec4 ptexInfo; // U offset, V offset, 2^ptexlevel', rotation
#ifdef OSD_ENABLE_PATCH_CULL
ivec3 clipFlag;
#endif
};
struct OutputVertex {

View File

@ -0,0 +1,294 @@
//
// Copyright 2015 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
//----------------------------------------------------------
// Patches.VertexGregoryBasis
//----------------------------------------------------------
#ifdef OSD_PATCH_VERTEX_GREGORY_BASIS_SHADER
layout(location = 0) in vec4 position;
OSD_USER_VARYING_ATTRIBUTE_DECLARE
out block {
ControlVertex v;
OSD_USER_VARYING_DECLARE
} outpt;
void main()
{
outpt.v.position = OsdModelViewMatrix() * position;
outpt.v.patchCoord = vec4(0);
outpt.v.ptexInfo = ivec4(0);
OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(position);
OSD_USER_VARYING_PER_VERTEX();
}
#endif
//----------------------------------------------------------
// Patches.TessControlGregoryBasis
//----------------------------------------------------------
#ifdef OSD_PATCH_TESS_CONTROL_GREGORY_BASIS_SHADER
layout(vertices = 20) out;
in block {
ControlVertex v;
OSD_USER_VARYING_DECLARE
} inpt[];
out block {
ControlVertex v;
OSD_USER_VARYING_DECLARE
} outpt[];
#define ID gl_InvocationID
void main()
{
outpt[ID].v = inpt[ID].v;
OSD_USER_VARYING_PER_CONTROL_POINT(ID, ID);
int patchLevel = GetPatchLevel();
// +0.5 to avoid interpolation error of integer value
outpt[ID].v.patchCoord = vec4(0, 0,
patchLevel+0.5,
GetPrimitiveID()+0.5);
OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER;
if (ID == 0) {
OSD_PATCH_CULL(OSD_PATCH_INPUT_SIZE);
// XXX: this metric is not consistent.
// we will 1) compute the cage length as before
// or 2) compute limit length for all patches.
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
gl_TessLevelOuter[0] =
TessAdaptive(inpt[0].v.position.xyz, inpt[5].v.position.xyz);
gl_TessLevelOuter[1] =
TessAdaptive(inpt[0].v.position.xyz, inpt[15].v.position.xyz);
gl_TessLevelOuter[2] =
TessAdaptive(inpt[10].v.position.xyz, inpt[15].v.position.xyz);
gl_TessLevelOuter[3] =
TessAdaptive(inpt[5].v.position.xyz, inpt[10].v.position.xyz);
gl_TessLevelInner[0] =
max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] =
max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#else
gl_TessLevelInner[0] = GetTessLevel(patchLevel);
gl_TessLevelInner[1] = GetTessLevel(patchLevel);
gl_TessLevelOuter[0] = GetTessLevel(patchLevel);
gl_TessLevelOuter[1] = GetTessLevel(patchLevel);
gl_TessLevelOuter[2] = GetTessLevel(patchLevel);
gl_TessLevelOuter[3] = GetTessLevel(patchLevel);
#endif
}
}
#endif
//----------------------------------------------------------
// Patches.TessEvalGregory
//----------------------------------------------------------
#ifdef OSD_PATCH_TESS_EVAL_GREGORY_BASIS_SHADER
layout(quads) in;
layout(cw) in;
#if defined OSD_FRACTIONAL_ODD_SPACING
layout(fractional_odd_spacing) in;
#elif defined OSD_FRACTIONAL_EVEN_SPACING
layout(fractional_even_spacing) in;
#endif
in block {
ControlVertex v;
OSD_USER_VARYING_DECLARE
} inpt[];
out block {
OutputVertex v;
OSD_USER_VARYING_DECLARE
} outpt;
void main()
{
float u = gl_TessCoord.x,
v = gl_TessCoord.y;
vec3 p[20];
for (int i = 0; i < 20; ++i) {
p[i] = inpt[i].v.position.xyz;
}
vec3 q[16];
float U = 1-u, V=1-v;
float d11 = u+v; if(u+v==0.0f) d11 = 1.0f;
float d12 = U+v; if(U+v==0.0f) d12 = 1.0f;
float d21 = u+V; if(u+V==0.0f) d21 = 1.0f;
float d22 = U+V; if(U+V==0.0f) d22 = 1.0f;
#if 1
q[ 5] = (u*p[3] + v*p[4])/d11;
q[ 6] = (U*p[9] + v*p[8])/d12;
q[ 9] = (u*p[19] + V*p[18])/d21;
q[10] = (U*p[13] + V*p[14])/d22;
#else
q[ 5] = (p[3] + p[4])/2.0;
q[ 6] = (p[9] + p[8])/2.0;
q[ 9] = (p[19] + p[18])/2.0;
q[10] = (p[13] + p[14])/2.0;
#endif
q[ 0] = p[0];
q[ 1] = p[1];
q[ 2] = p[7];
q[ 3] = p[5];
q[ 4] = p[2];
q[ 7] = p[6];
q[ 8] = p[16];
q[11] = p[12];
q[12] = p[15];
q[13] = p[17];
q[14] = p[11];
q[15] = p[10];
vec3 WorldPos = vec3(0, 0, 0);
vec3 Tangent = vec3(0, 0, 0);
vec3 BiTangent = vec3(0, 0, 0);
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
float B[4], D[4], C[4];
vec3 BUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0)),
DUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0)),
CUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0));
vec3 dUU = vec3(0);
vec3 dVV = vec3(0);
vec3 dUV = vec3(0);
Univar4x4(u, B, D, C);
for (int i=0; i<4; ++i) {
for (uint j=0; j<4; ++j) {
// reverse face front
vec3 A = q[i + 4*j];
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
CUCP[i] += A * C[j];
}
}
Univar4x4(v, B, D, C);
for (int i=0; i<4; ++i) {
WorldPos += B[i] * BUCP[i];
Tangent += B[i] * DUCP[i];
BiTangent += D[i] * BUCP[i];
dUU += B[i] * CUCP[i];
dVV += C[i] * BUCP[i];
dUV += D[i] * DUCP[i];
}
int level = int(inpt[0].v.ptexInfo.z);
BiTangent *= 3 * level;
Tangent *= 3 * level;
dUU *= 6 * level;
dVV *= 6 * level;
dUV *= 9 * level;
vec3 n = cross(BiTangent, Tangent);
vec3 normal = normalize(n);
float E = dot(Tangent, Tangent);
float F = dot(Tangent, BiTangent);
float G = dot(BiTangent, BiTangent);
float e = dot(normal, dUU);
float f = dot(normal, dUV);
float g = dot(normal, dVV);
vec3 Nu = (f*F-e*G)/(E*G-F*F) * Tangent + (e*F-f*E)/(E*G-F*F) * BiTangent;
vec3 Nv = (g*F-f*G)/(E*G-F*F) * Tangent + (f*F-g*E)/(E*G-F*F) * BiTangent;
Nu = Nu/length(n) - n * (dot(Nu,n)/pow(dot(n,n), 1.5));
Nv = Nv/length(n) - n * (dot(Nv,n)/pow(dot(n,n), 1.5));
outpt.v.Nu = Nu;
outpt.v.Nv = Nv;
#else
float B[4], D[4];
vec3 BUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0)),
DUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0));
Univar4x4(u, B, D);
for (int i=0; i<4; ++i) {
for (uint j=0; j<4; ++j) {
// reverse face front
vec3 A = q[i + 4*j];
BUCP[i] += A * B[j];
DUCP[i] += A * D[j];
}
}
Univar4x4(v, B, D);
for (int i=0; i<4; ++i) {
WorldPos += B[i] * BUCP[i];
Tangent += B[i] * DUCP[i];
BiTangent += D[i] * BUCP[i];
}
int level = int(inpt[0].v.ptexInfo.z);
BiTangent *= 3 * level;
Tangent *= 3 * level;
vec3 normal = normalize(cross(BiTangent, Tangent));
#endif
outpt.v.position = vec4(WorldPos, 1.0f);
outpt.v.normal = normal;
outpt.v.tangent = BiTangent;
outpt.v.bitangent = Tangent;
//OSD_USER_VARYING_PER_EVAL_POINT(vec2(u,v), 0, 3, 1, 2);
OSD_USER_VARYING_PER_EVAL_POINT(vec2(u,v), 0, 15, 5, 10);
outpt.v.patchCoord = inpt[0].v.patchCoord;
outpt.v.patchCoord.xy = vec2(v, u);
OSD_COMPUTE_PTEX_COORD_TESSEVAL_SHADER;
OSD_DISPLACEMENT_CALLBACK;
gl_Position = OsdProjectionMatrix() * outpt.v.position;
}
#endif

View File

@ -51,7 +51,8 @@ enum MeshBits {
MeshPtexData = 2,
MeshFVarData = 3,
MeshUseSingleCreasePatch = 4,
NUM_MESH_BITS = 5,
MeshUseGregoryBasis = 5,
NUM_MESH_BITS = 6,
};
typedef std::bitset<NUM_MESH_BITS> MeshBitset;

View File

@ -0,0 +1,21 @@
static const std::string catmark_gregory_test0 = std::string(
"# This file uses centimeters as units for non-parametric coordinates.\n"
"v -0.500000 0.204097 -0.500000\n"
"v 0.000000 0.117710 -0.500000\n"
"v -0.500000 0.142210 -0.000000\n"
"v 0.000000 0.000000 0.000000\n"
"v -0.500000 0.204097 0.500000\n"
"v 0.000000 0.117710 0.500000\n"
"v 0.500000 0.348563 -0.003642\n"
"vt -0.500000 -0.500000\n"
"vt 0.000000 -0.500000\n"
"vt -0.500000 -0.000000\n"
"vt 0.000000 0.000000\n"
"vt -0.500000 0.500000\n"
"vt 0.000000 0.500000\n"
"vt 0.500000 -0.003642\n"
"s 1\n"
"f 1/1/1 2/2/2 4/4/4 3/3/3\n"
"f 3/3/3 4/4/4 6/6/6 5/5/5\n"
"f 2/2/2 7/7/7 6/6/6 4/4/4\n"
);