Merge pull request #1 from PixarAnimationStudios/master

sync to 3.0.5 release
This commit is contained in:
xiao-deng 2016-04-06 17:14:33 +08:00
commit 3f82cb6666
27 changed files with 837 additions and 382 deletions

View File

@ -42,9 +42,9 @@ before_script:
- sudo apt-get install cmake
- cmake --version
# install GL related libs from utopic
- sudo add-apt-repository 'deb http://us.archive.ubuntu.com/ubuntu/ utopic main restricted universe multiverse'
- sudo add-apt-repository 'deb http://us.archive.ubuntu.com/ubuntu/ utopic-updates main restricted universe multiverse'
# install GL related libs from wily
- sudo add-apt-repository 'deb http://us.archive.ubuntu.com/ubuntu/ wily main restricted universe multiverse'
- sudo add-apt-repository 'deb http://us.archive.ubuntu.com/ubuntu/ wily-updates main restricted universe multiverse'
- sudo apt-get update -qq
# install glut and xxf86vm (for GL libs)
- sudo apt-get install freeglut3-dev

View File

@ -703,21 +703,27 @@ macro(_add_glfw_executable target)
_add_possibly_cuda_executable(${target} ${ARGN})
if(WIN32)
# Windows needs some of its dependency dll's copied into the same
# directory as the executable.
set( LIBRARIES ${GLFW_LIBRARIES})
foreach (LIB ${LIBRARIES} )
string(REPLACE ".lib" ".dll" DLL ${LIB})
string(REPLACE ".LIB" ".DLL" DLL ${DLL})
add_custom_command(
TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${DLL}
$<TARGET_FILE_DIR:${target}>
)
endforeach()
endif()
#
# manuelk : commenting this out as it seems to be causing more problems than
# it is worth. Moving glfw as a native git recursive dependency will make this
# redundant anyway.
#
# if(WIN32)
# # Windows needs some of its dependency dll's copied into the same
# # directory as the executable.
# set(LIBRARIES ${GLFW_LIBRARIES})
# foreach (LIB ${LIBRARIES} )
# string(REPLACE ".lib" ".dll" DLL ${LIB})
# string(REPLACE ".LIB" ".DLL" DLL ${DLL})
# add_custom_command(
# TARGET ${target} POST_BUILD
# COMMAND ${CMAKE_COMMAND} -E copy_if_different
# ${DLL}
# $<TARGET_FILE_DIR:${target}>
# )
# endforeach()
# endif()
endmacro()

View File

@ -31,6 +31,34 @@
----
Release 3.0.5
=============
Release 3.0.5 is a minor stability release with performance and correctness bug fixes.
**Bug Fixes**
- The previous release reduced transient memory use during PatchTable construction, but increased the amount of memory consumed by the resulting PatchTable itself, this regression has been fixed.
- The example Ptex texture sampling code has been fixed to prevent sampling beyond the texels for a face when multisample rasterization is enabled.
Release 3.0.4
=============
Release 3.0.4 is a minor stability release which includes important performance
and bug fixes.
**New Features**
- Added accessor methods to Far::LimitStencilTable to retrieve limit stencil data including derivative weights
- Added support for OpenCL event control to Osd::CLVertexBuffer and Osd::CLEvaluator
**Changes**
- Major reduction in memory use during Far::PatchTable construction for topologies with large numbers of extraordinary features
- Improved performance for GL and D3D11 tessellation control / hull shader execution when drawing BSpline patches with the single crease patch optimization enabled
**Bug Fixes**
- Restored support for drawing with fractional tessellation
- Fixed far_tutorial_6 to refine primvar data only up to the number of levels produced by topological refinement
- Fixed build warnings and errors reported by Visual Studio 2015
Release 3.0.3
=============

View File

@ -114,7 +114,7 @@ vec4 PtexLookupNearest(vec4 patchCoord,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = patchCoord.xy;
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID);
vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset,
@ -127,7 +127,7 @@ vec4 PtexLookupNearest(vec4 patchCoord,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = patchCoord.xy;
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset,
@ -139,7 +139,7 @@ vec4 PtexLookupFast(vec4 patchCoord,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = patchCoord.xy;
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID);
@ -154,7 +154,7 @@ vec4 PtexLookupFast(vec4 patchCoord,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = patchCoord.xy;
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
@ -169,7 +169,7 @@ vec4 PtexLookup(vec4 patchCoord,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = patchCoord.xy;
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
@ -203,7 +203,7 @@ vec4 PtexLookupQuadratic(out vec4 du,
sampler2DArray data,
isamplerBuffer packings)
{
vec2 uv = patchCoord.xy;
vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);

View File

@ -114,7 +114,7 @@ float4 PtexLookupNearest(float4 patchCoord,
Texture2DArray data,
Buffer<uint> packings)
{
float2 uv = patchCoord.xy;
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
@ -127,7 +127,7 @@ float4 PtexLookupNearest(float4 patchCoord,
Texture2DArray data,
Buffer<uint> packings)
{
float2 uv = patchCoord.xy;
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
float2 coords = float2(uv.x * ppack.width + ppack.uOffset,
@ -140,7 +140,7 @@ float4 PtexLookup(float4 patchCoord,
Texture2DArray data,
Buffer<uint> packings)
{
float2 uv = patchCoord.xy;
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);
@ -174,7 +174,7 @@ float4 PtexLookupQuadratic(out float4 du,
Texture2DArray data,
Buffer<uint> packings)
{
float2 uv = patchCoord.xy;
float2 uv = clamp(patchCoord.xy, float2(0,0), float2(1,1));
int faceID = int(patchCoord.w);
PtexPacking ppack = getPtexPacking(packings, faceID, level);

View File

@ -1403,8 +1403,8 @@ initHUD() {
450, 10, callbackCheckBox, HUD_CB_ANIMATE_VERTICES, 'm');
g_hud->AddCheckBox("Screen space LOD (V)", g_screenSpaceTess,
450, 30, callbackCheckBox, HUD_CB_VIEW_LOD, 'v');
//g_hud->AddCheckBox("Fractional spacing (T)", g_fractionalSpacing,
// 450, 50, callbackCheckBox, HUD_CB_FRACTIONAL_SPACING, 't');
g_hud->AddCheckBox("Fractional spacing (T)", g_fractionalSpacing,
450, 50, callbackCheckBox, HUD_CB_FRACTIONAL_SPACING, 't');
g_hud->AddCheckBox("Frustum Patch Culling (B)", g_patchCull,
450, 70, callbackCheckBox, HUD_CB_PATCH_CULL, 'b');
g_hud->AddCheckBox("Freeze (spc)", g_freeze,

View File

@ -1213,9 +1213,9 @@ initHUD() {
g_hud->AddCheckBox("Screen space LOD (V)", g_screenSpaceTess != 0,
10, y, callbackCheckBox, kHUD_CB_VIEW_LOD, 'V');
y += 20;
//g_hud->AddCheckBox("Fractional spacing (T)", g_fractionalSpacing != 0,
// 10, y, callbackCheckBox, kHUD_CB_FRACTIONAL_SPACING, 'T');
//y += 20;
g_hud->AddCheckBox("Fractional spacing (T)", g_fractionalSpacing != 0,
10, y, callbackCheckBox, kHUD_CB_FRACTIONAL_SPACING, 'T');
y += 20;
g_hud->AddCheckBox("Frustum Patch Culling (B)", g_patchCull != 0,
10, y, callbackCheckBox, kHUD_CB_PATCH_CULL, 'B');
y += 20;

View File

@ -42,10 +42,6 @@
GLFWwindow* g_window=0;
GLFWmonitor* g_primary=0;
#if _MSC_VER
#define snprintf _snprintf
#endif
#include <osd/cpuGLVertexBuffer.h>
#include <far/patchTableFactory.h>
@ -70,6 +66,12 @@ GLFWmonitor* g_primary=0;
#include <set>
#include <fstream>
#include <sstream>
#include <cstdio>
#if _MSC_VER
#define snprintf _snprintf
#endif
//------------------------------------------------------------------------------
int g_level = 3,

View File

@ -1879,8 +1879,8 @@ int main(int argc, char ** argv) {
10, 30, callbackCheckBox, HUD_CB_ANIMATE_VERTICES, 'm');
g_hud.AddCheckBox("Screen space LOD (V)", g_screenSpaceTess,
10, 50, callbackCheckBox, HUD_CB_VIEW_LOD, 'v');
//g_hud.AddCheckBox("Fractional spacing (T)", g_fractionalSpacing,
// 10, 70, callbackCheckBox, HUD_CB_FRACTIONAL_SPACING, 't');
g_hud.AddCheckBox("Fractional spacing (T)", g_fractionalSpacing,
10, 70, callbackCheckBox, HUD_CB_FRACTIONAL_SPACING, 't');
g_hud.AddCheckBox("Frustum Patch Culling (B)", g_patchCull,
10, 90, callbackCheckBox, HUD_CB_PATCH_CULL, 'b');
g_hud.AddCheckBox("Bloom (Y)", g_bloom,

View File

@ -454,15 +454,15 @@ public:
void EnableVertexAttributes( ) {
long int offset = 0;
GLvoid * offset = 0;
for (AttrList::iterator i=_attrs.begin(); i!=_attrs.end(); ++i) {
glEnableVertexAttribArray( i->location );
glVertexAttribPointer( i->location, i->size,
GL_FLOAT, GL_FALSE, sizeof(GLfloat) * _attrStride, (void*)offset);
GL_FLOAT, GL_FALSE, sizeof(GLfloat) * _attrStride, (GLvoid*)offset);
offset += sizeof(GLfloat) * i->size;
offset = (GLubyte*)offset + sizeof(GLfloat) * i->size;
}
}
GLuint GetUniformScale() const {
@ -645,6 +645,8 @@ linkDefaultPrograms() {
g_samplesProgram.SetFragShaderSource(fsSrc);
g_samplesProgram.AddAttribute( "position",3 );
g_samplesProgram.AddAttribute( "uTangent",3 );
g_samplesProgram.AddAttribute( "vTangent",3 );
}
return true;

View File

@ -1461,9 +1461,9 @@ initHUD() {
g_hud.AddCheckBox("Screen space LOD (V)", g_screenSpaceTess != 0,
10, y, callbackCheckBox, kHUD_CB_VIEW_LOD, 'v');
y += 20;
//g_hud.AddCheckBox("Fractional spacing (T)", g_fractionalSpacing != 0,
// 10, y, callbackCheckBox, kHUD_CB_FRACTIONAL_SPACING, 't');
//y += 20;
g_hud.AddCheckBox("Fractional spacing (T)", g_fractionalSpacing != 0,
10, y, callbackCheckBox, kHUD_CB_FRACTIONAL_SPACING, 't');
y += 20;
g_hud.AddCheckBox("Frustum Patch Culling (B)", g_patchCull != 0,
10, y, callbackCheckBox, kHUD_CB_PATCH_CULL, 'b');
y += 20;

View File

@ -49,7 +49,10 @@ namespace {
}
EndCapBSplineBasisPatchFactory::EndCapBSplineBasisPatchFactory(
TopologyRefiner const & refiner) :
TopologyRefiner const & refiner,
StencilTable * vertexStencils,
StencilTable * varyingStencils) :
_vertexStencils(vertexStencils), _varyingStencils(varyingStencils),
_refiner(&refiner), _numVertices(0), _numPatches(0) {
// Sanity check: the mesh must be adaptively refined
@ -61,8 +64,14 @@ EndCapBSplineBasisPatchFactory::EndCapBSplineBasisPatchFactory(
// finest level.
int numMaxLevelFaces = refiner.GetLevel(refiner.GetMaxLevel()).GetNumFaces();
_vertexStencils.reserve(numMaxLevelFaces*16);
_varyingStencils.reserve(numMaxLevelFaces*16);
// we typically use 7 patch points for each bspline endcap.
int numPatchPointsExpected = numMaxLevelFaces * 7;
// limits to 100M (=800M bytes) entries for the reserved size.
int numStencilsExpected = std::min(numPatchPointsExpected * 16,
100*1024*1024);
_vertexStencils->reserve(numPatchPointsExpected, numStencilsExpected);
// varying stencils use only 1 index with weight=1.0
_varyingStencils->reserve(numPatchPointsExpected, numPatchPointsExpected);
}
ConstIndexArray
@ -169,7 +178,7 @@ EndCapBSplineBasisPatchFactory::getPatchPointsFromGregoryBasis(
p.AddWithWeight(H[i*4+k], Q[j][k]);
}
}
_vertexStencils.push_back(p);
GregoryBasis::AppendToStencilTable(p, _vertexStencils);
}
}
int varyingIndices[] = { 0, 0, 1, 1,
@ -177,12 +186,12 @@ EndCapBSplineBasisPatchFactory::getPatchPointsFromGregoryBasis(
3, 3, 2, 2,
3, 3, 2, 2,};
for (int i = 0; i < 16; ++i) {
GregoryBasis::Point p(1);
p.AddWithWeight(facePoints[varyingIndices[i]] + levelVertOffset, 1.0f);
_varyingStencils.push_back(p);
int varyingIndex = facePoints[varyingIndices[i]] + levelVertOffset;
_varyingStencils->_sizes.push_back(1);
_varyingStencils->_indices.push_back(varyingIndex);
_varyingStencils->_weights.push_back(1.0f);
}
++_numPatches;
return ConstIndexArray(&_patchPoints[(_numPatches-1)*16], 16);
}
@ -455,39 +464,38 @@ EndCapBSplineBasisPatchFactory::getPatchPoints(
int offset = _refiner->GetNumVerticesTotal();
GregoryBasis::Point V0, V1, V3;
V0.AddWithWeight(facePoints[vid] + levelVertOffset, 1.0f);
V1.AddWithWeight(facePoints[(vid+1)&3] + levelVertOffset, 1.0f);
V3.AddWithWeight(facePoints[(vid+3)&3] + levelVertOffset, 1.0f);
int varyingIndex0 = facePoints[vid] + levelVertOffset;
int varyingIndex1 = facePoints[(vid+1)&3] + levelVertOffset;
int varyingIndex3 = facePoints[(vid+3)&3] + levelVertOffset;
// push back to stencils;
patchPoints[3* vid + 6] = (_numVertices++) + offset;
_vertexStencils.push_back(X6);
_varyingStencils.push_back(V0);
GregoryBasis::AppendToStencilTable(X6, _vertexStencils);
GregoryBasis::AppendToStencilTable(varyingIndex0, _varyingStencils);
patchPoints[3*((vid+1)%4) + 4] = (_numVertices++) + offset;
_vertexStencils.push_back(X7);
_varyingStencils.push_back(V1);
GregoryBasis::AppendToStencilTable(X7, _vertexStencils);
GregoryBasis::AppendToStencilTable(varyingIndex1, _varyingStencils);
patchPoints[3*((vid+1)%4) + 5] = (_numVertices++) + offset;
_vertexStencils.push_back(X8);
_varyingStencils.push_back(V1);
GregoryBasis::AppendToStencilTable(X8, _vertexStencils);
GregoryBasis::AppendToStencilTable(varyingIndex1, _varyingStencils);
patchPoints[3* vid + 4] = (_numVertices++) + offset;
_vertexStencils.push_back(X4);
_varyingStencils.push_back(V0);
GregoryBasis::AppendToStencilTable(X4, _vertexStencils);
GregoryBasis::AppendToStencilTable(varyingIndex0, _varyingStencils);
patchPoints[3*((vid+3)%4) + 6] = (_numVertices++) + offset;
_vertexStencils.push_back(X15);
_varyingStencils.push_back(V3);
GregoryBasis::AppendToStencilTable(X15, _vertexStencils);
GregoryBasis::AppendToStencilTable(varyingIndex3, _varyingStencils);
patchPoints[3*((vid+3)%4) + 5] = (_numVertices++) + offset;
_vertexStencils.push_back(X14);
_varyingStencils.push_back(V3);
GregoryBasis::AppendToStencilTable(X14, _vertexStencils);
GregoryBasis::AppendToStencilTable(varyingIndex3, _varyingStencils);
patchPoints[3*vid + 5] = (_numVertices++) + offset;
_vertexStencils.push_back(X5);
_varyingStencils.push_back(V0);
GregoryBasis::AppendToStencilTable(X5, _vertexStencils);
GregoryBasis::AppendToStencilTable(varyingIndex0, _varyingStencils);
// reorder into UV row-column
static int const permuteRegular[16] =

View File

@ -51,11 +51,19 @@ public:
///
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param vertexStencils Output stencil table for the patch points
/// (vertex interpolation)
///
/// @param varyingStencils Output stencil table for the patch points
/// (varying interpolation)
///
/// @param shareBoundaryVertices Use same boundary vertices for neighboring
/// patches. It reduces the number of stencils
/// to be used.
///
EndCapBSplineBasisPatchFactory(TopologyRefiner const & refiner);
EndCapBSplineBasisPatchFactory(TopologyRefiner const & refiner,
StencilTable * vertexStencils,
StencilTable * varyingStencils);
/// \brief Returns end patch point indices for \a faceIndex of \a level.
/// Note that end patch points are not included in the vertices in
@ -75,21 +83,6 @@ public:
PatchTableFactory::PatchFaceTag const * levelPatchTags,
int levelVertOffset);
/// \brief Create a StencilTable for end patch points, relative to the max
/// subdivision level.
///
StencilTable* CreateVertexStencilTable() const {
return GregoryBasis::CreateStencilTable(_vertexStencils);
}
/// \brief Create a StencilTable for end patch varying primvar.
/// This table is used as a convenient way to get varying primvars
/// populated on end patch points along with positions.
///
StencilTable* CreateVaryingStencilTable() const {
return GregoryBasis::CreateStencilTable(_varyingStencils);
}
private:
ConstIndexArray getPatchPointsFromGregoryBasis(
Vtr::internal::Level const * level, Index thisFace,
@ -106,10 +99,10 @@ private:
ConstIndexArray facePoints, int vid,
GregoryBasis::Point *P, GregoryBasis::Point *Ep, GregoryBasis::Point *Em);
StencilTable * _vertexStencils;
StencilTable * _varyingStencils;
TopologyRefiner const *_refiner;
GregoryBasis::PointsVector _vertexStencils;
GregoryBasis::PointsVector _varyingStencils;
int _numVertices;
int _numPatches;
std::vector<Index> _patchPoints;

View File

@ -41,7 +41,11 @@ namespace Far {
// EndCapGregoryBasisPatchFactory for Vertex StencilTable
//
EndCapGregoryBasisPatchFactory::EndCapGregoryBasisPatchFactory(
TopologyRefiner const & refiner, bool shareBoundaryVertices) :
TopologyRefiner const & refiner,
StencilTable * vertexStencils,
StencilTable * varyingStencils,
bool shareBoundaryVertices) :
_vertexStencils(vertexStencils), _varyingStencils(varyingStencils),
_refiner(&refiner), _shareBoundaryVertices(shareBoundaryVertices),
_numGregoryBasisVertices(0), _numGregoryBasisPatches(0) {
@ -54,8 +58,13 @@ EndCapGregoryBasisPatchFactory::EndCapGregoryBasisPatchFactory(
// finest level.
int numMaxLevelFaces = refiner.GetLevel(refiner.GetMaxLevel()).GetNumFaces();
_vertexStencils.reserve(numMaxLevelFaces*20);
_varyingStencils.reserve(numMaxLevelFaces*20);
int numPatchPointsExpected = numMaxLevelFaces * 20;
// limits to 100M (=800M bytes) entries for the reserved size.
int numStencilsExpected = std::min(numPatchPointsExpected * 16,
100*1024*1024);
_vertexStencils->reserve(numPatchPointsExpected, numStencilsExpected);
// varying stencils use only 1 index with weight=1.0
_varyingStencils->reserve(numPatchPointsExpected, numPatchPointsExpected);
}
//
@ -90,24 +99,24 @@ EndCapGregoryBasisPatchFactory::addPatchBasis(Index faceIndex,
for (int i = 0; i < 4; ++i) {
if (verticesMask[i][0]) {
_vertexStencils.push_back(basis.P[i]);
_varyingStencils.push_back(basis.V[i]);
GregoryBasis::AppendToStencilTable(basis.P[i], _vertexStencils);
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
if (verticesMask[i][1]) {
_vertexStencils.push_back(basis.Ep[i]);
_varyingStencils.push_back(basis.V[i]);
GregoryBasis::AppendToStencilTable(basis.Ep[i], _vertexStencils);
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
if (verticesMask[i][2]) {
_vertexStencils.push_back(basis.Em[i]);
_varyingStencils.push_back(basis.V[i]);
GregoryBasis::AppendToStencilTable(basis.Em[i], _vertexStencils);
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
if (verticesMask[i][3]) {
_vertexStencils.push_back(basis.Fp[i]);
_varyingStencils.push_back(basis.V[i]);
GregoryBasis::AppendToStencilTable(basis.Fp[i], _vertexStencils);
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
if (verticesMask[i][4]) {
_vertexStencils.push_back(basis.Fm[i]);
_varyingStencils.push_back(basis.V[i]);
GregoryBasis::AppendToStencilTable(basis.Fm[i], _vertexStencils);
GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils);
}
}
return true;

View File

@ -27,6 +27,7 @@
#include "../far/patchTableFactory.h"
#include "../far/gregoryBasis.h"
#include "../far/stencilTable.h"
#include "../vtr/level.h"
namespace OpenSubdiv {
@ -74,11 +75,19 @@ public:
///
/// @param refiner TopologyRefiner from which to generate patches
///
/// @param vertexStencils Output stencil table for the patch points
/// (vertex interpolation)
///
/// @param varyingStencils Output stencil table for the patch points
/// (varying interpolation)
///
/// @param shareBoundaryVertices Use same boundary vertices for neighboring
/// patches. It reduces the number of stencils
/// to be used.
///
EndCapGregoryBasisPatchFactory(TopologyRefiner const & refiner,
StencilTable *vertexStencils,
StencilTable *varyingStencils,
bool shareBoundaryVertices=true);
/// \brief Returns end patch point indices for \a faceIndex of \a level.
@ -99,21 +108,6 @@ public:
PatchTableFactory::PatchFaceTag const * levelPatchTags,
int levelVertOffset);
/// \brief Create a StencilTable for end patch points, relative to the max
/// subdivision level.
///
StencilTable* CreateVertexStencilTable() const {
return GregoryBasis::CreateStencilTable(_vertexStencils);
}
/// \brief Create a StencilTable for end patch varying primvar.
/// This table is used as a convenient way to get varying primvars
/// populated on end patch points along with positions.
///
StencilTable* CreateVaryingStencilTable() const {
return GregoryBasis::CreateStencilTable(_varyingStencils);
}
private:
/// Creates a basis for the vertices specified in mask on the face and
@ -121,8 +115,8 @@ private:
bool addPatchBasis(Index faceIndex, bool newVerticesMask[4][5],
int levelVertOffset);
GregoryBasis::PointsVector _vertexStencils;
GregoryBasis::PointsVector _varyingStencils;
StencilTable *_vertexStencils;
StencilTable *_varyingStencils;
TopologyRefiner const *_refiner;
bool _shareBoundaryVertices;

View File

@ -126,7 +126,6 @@ GregoryBasis::ProtoBasis::ProtoBasis(
P[i].Clear(stencilCapacity);
e0[i].Clear(stencilCapacity);
e1[i].Clear(stencilCapacity);
V[i].Clear(1);
}
Vtr::internal::StackBuffer<Index, 40> manifoldRings[4];
@ -142,7 +141,7 @@ GregoryBasis::ProtoBasis::ProtoBasis(
for (int vid=0; vid<4; ++vid) {
// save for varying stencils
V[vid].AddWithWeight(facePoints[vid], 1.0f);
varyingIndex[vid] = facePoints[vid] + levelVertOffset;
int ringSize =
level.gatherQuadRegularRingAroundVertex(
@ -445,41 +444,9 @@ GregoryBasis::ProtoBasis::ProtoBasis(
Em[i].OffsetIndices(levelVertOffset);
Fp[i].OffsetIndices(levelVertOffset);
Fm[i].OffsetIndices(levelVertOffset);
V[i].OffsetIndices(levelVertOffset);
}
}
/*static*/
StencilTable *
GregoryBasis::CreateStencilTable(PointsVector const &stencils) {
int nStencils = (int)stencils.size();
if (nStencils == 0) return NULL;
int nElements = 0;
for (int i = 0; i < nStencils; ++i) {
nElements += stencils[i].GetSize();
}
// allocate destination
StencilTable *stencilTable = new StencilTable();
// XXX: do we need numControlVertices in stencilTable?
stencilTable->_numControlVertices = 0;
stencilTable->resize(nStencils, nElements);
int * sizes = &stencilTable->_sizes[0];
Index * indices = &stencilTable->_indices[0];
float * weights = &stencilTable->_weights[0];
for (int i = 0; i < nStencils; ++i) {
stencils[i].Copy(&sizes, &indices, &weights);
}
stencilTable->generateOffsets();
return stencilTable;
}
} // end namespace Far
} // end namespace OPENSUBDIV_VERSION

View File

@ -161,8 +161,14 @@ public:
++(*size);
}
private:
Vtr::Index GetStencilIndex(int index) const {
return _stencils[index].index;
}
float GetStencilWeight(int index) const {
return _stencils[index].weight;
}
private:
int _size;
struct Stencil {
@ -219,12 +225,28 @@ public:
Point P[4], Ep[4], Em[4], Fp[4], Fm[4];
// for varying interpolation
Point V[4];
Vtr::Index varyingIndex[4];
};
typedef std::vector<GregoryBasis::Point> PointsVector;
static StencilTable *CreateStencilTable(PointsVector const &stencils);
// for basis point stencil
static void AppendToStencilTable(GregoryBasis::Point const &p,
StencilTable *table) {
int size = p.GetSize();
table->_sizes.push_back(size);
for (int i = 0; i < size; ++i) {
table->_indices.push_back(p.GetStencilIndex(i));
table->_weights.push_back(p.GetStencilWeight(i));
}
}
// for varying stencil (just copy)
static void AppendToStencilTable(int index, StencilTable *table) {
table->_sizes.push_back(1);
table->_indices.push_back(index);
table->_weights.push_back(1.f);
}
private:

View File

@ -1122,14 +1122,26 @@ PatchTableFactory::populateAdaptivePatches(
EndCapBSplineBasisPatchFactory *endCapBSpline = NULL;
EndCapGregoryBasisPatchFactory *endCapGregoryBasis = NULL;
EndCapLegacyGregoryPatchFactory *endCapLegacyGregory = NULL;
StencilTable *localPointStencils = NULL;
StencilTable *localPointVaryingStencils = NULL;
switch(context.options.GetEndCapType()) {
case Options::ENDCAP_GREGORY_BASIS:
localPointStencils = new StencilTable(0);
localPointVaryingStencils = new StencilTable(0);
endCapGregoryBasis = new EndCapGregoryBasisPatchFactory(
refiner, context.options.shareEndCapPatchPoints);
refiner,
localPointStencils,
localPointVaryingStencils,
context.options.shareEndCapPatchPoints);
break;
case Options::ENDCAP_BSPLINE_BASIS:
endCapBSpline = new EndCapBSplineBasisPatchFactory(refiner);
localPointStencils = new StencilTable(0);
localPointVaryingStencils = new StencilTable(0);
endCapBSpline = new EndCapBSplineBasisPatchFactory(
refiner,
localPointStencils,
localPointVaryingStencils);
break;
case Options::ENDCAP_LEGACY_GREGORY:
endCapLegacyGregory = new EndCapLegacyGregoryPatchFactory(refiner);
@ -1291,19 +1303,29 @@ PatchTableFactory::populateAdaptivePatches(
}
// finalize end patches
if (localPointStencils and localPointStencils->GetNumStencils() > 0) {
localPointStencils->finalize();
} else {
delete localPointStencils;
localPointStencils = NULL;
}
if (localPointVaryingStencils and localPointVaryingStencils->GetNumStencils() > 0) {
localPointVaryingStencils->finalize();
} else {
delete localPointVaryingStencils;
localPointVaryingStencils = NULL;
}
switch(context.options.GetEndCapType()) {
case Options::ENDCAP_GREGORY_BASIS:
table->_localPointStencils =
endCapGregoryBasis->CreateVertexStencilTable();
table->_localPointVaryingStencils =
endCapGregoryBasis->CreateVaryingStencilTable();
table->_localPointStencils = localPointStencils;
table->_localPointVaryingStencils = localPointVaryingStencils;
delete endCapGregoryBasis;
break;
case Options::ENDCAP_BSPLINE_BASIS:
table->_localPointStencils =
endCapBSpline->CreateVertexStencilTable();
table->_localPointVaryingStencils =
endCapBSpline->CreateVaryingStencilTable();
table->_localPointStencils = localPointStencils;
table->_localPointVaryingStencils = localPointVaryingStencils;
delete endCapBSpline;
break;
case Options::ENDCAP_LEGACY_GREGORY:

View File

@ -205,6 +205,15 @@ protected:
// Resize the table arrays (factory helper)
void resize(int nstencils, int nelems);
// Reserves the table arrays (factory helper)
void reserve(int nstencils, int nelems);
// Reallocates the table arrays to remove excess capacity (factory helper)
void shrinkToFit();
// Performs any final operations on internal tables (factory helper)
void finalize();
protected:
StencilTable() : _numControlVertices(0) {}
StencilTable(int numControlVerts)
@ -212,8 +221,12 @@ protected:
{ }
friend class StencilTableFactory;
friend class PatchTableFactory;
// XXX: temporarily, GregoryBasis class will go away.
friend class GregoryBasis;
// XXX: needed to call reserve().
friend class EndCapBSplineBasisPatchFactory;
friend class EndCapGregoryBasisPatchFactory;
int _numControlVertices; // number of control vertices
@ -297,6 +310,12 @@ class LimitStencilTable : public StencilTable {
public:
/// \brief Returns a LimitStencil at index i in the table
LimitStencil GetLimitStencil(Index i) const;
/// \brief Returns the limit stencil at index i in the table
LimitStencil operator[] (Index index) const;
/// \brief Returns the 'u' derivative stencil interpolation weights
std::vector<float> const & GetDuWeights() const {
return _duWeights;
@ -399,6 +418,26 @@ StencilTable::resize(int nstencils, int nelems) {
_weights.resize(nelems);
}
inline void
StencilTable::reserve(int nstencils, int nelems) {
_sizes.reserve(nstencils);
_indices.reserve(nelems);
_weights.reserve(nelems);
}
inline void
StencilTable::shrinkToFit() {
std::vector<int>(_sizes).swap(_sizes);
std::vector<Index>(_indices).swap(_indices);
std::vector<float>(_weights).swap(_weights);
}
inline void
StencilTable::finalize() {
shrinkToFit();
generateOffsets();
}
// Returns a Stencil at index i in the table
inline Stencil
StencilTable::GetStencil(Index i) const {
@ -423,6 +462,25 @@ LimitStencilTable::resize(int nstencils, int nelems) {
_dvWeights.resize(nelems);
}
// Returns a LimitStencil at index i in the table
inline LimitStencil
LimitStencilTable::GetLimitStencil(Index i) const {
assert((not GetOffsets().empty()) and i<(int)GetOffsets().size());
Index ofs = GetOffsets()[i];
return LimitStencil( const_cast<int *>(&GetSizes()[i]),
const_cast<Index *>(&GetControlIndices()[ofs]),
const_cast<float *>(&GetWeights()[ofs]),
const_cast<float *>(&GetDuWeights()[ofs]),
const_cast<float *>(&GetDvWeights()[ofs]) );
}
inline LimitStencil
LimitStencilTable::operator[] (Index index) const {
return GetLimitStencil(index);
}
} // end namespace Far

View File

@ -212,7 +212,8 @@ StencilTableFactory::AppendLocalPointStencilTable(
// factorize and append.
if (baseStencilTable == NULL or
localPointStencilTable == NULL) return NULL;
localPointStencilTable == NULL or
localPointStencilTable->GetNumStencils() == 0) return NULL;
// baseStencilTable can be built with or without singular stencils
// (single weight of 1.0f) as place-holders for coarse mesh vertices.

View File

@ -66,7 +66,7 @@ public:
bool IsUniform() const { return _isUniform; }
/// \brief Returns the number of refinement levels
int GetNumLevels() const { return (int)_levels.size(); }
int GetNumLevels() const { return (int)_farLevels.size(); }
/// \brief Returns the highest level of refinement
int GetMaxLevel() const { return _maxLevel; }

View File

@ -204,8 +204,11 @@ D3D11ComputeEvaluator::Compile(BufferDescriptor const &srcDesc,
return false;
}
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS
| D3D10_SHADER_RESOURCES_MAY_ALIAS;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined(D3D10_SHADER_RESOURCES_MAY_ALIAS)
dwShaderFlags |= D3D10_SHADER_RESOURCES_MAY_ALIAS;
#endif
#ifdef _DEBUG
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif

View File

@ -75,7 +75,7 @@ D3D11VertexBuffer::UpdateData(const float *src, int startVertex, int numVertices
return;
}
int size = GetNumElements() * numVertices * sizeof(float);
unsigned int size = GetNumElements() * numVertices * sizeof(float);
memcpy((float*)resource.pData + startVertex * _numElements, src, size);

View File

@ -72,14 +72,16 @@
// mix(input[c].var, input[d].var, UV.x), UV.y)
#endif
// XXXdyu-patch-drawing support for fractional spacing
#undef OSD_FRACTIONAL_ODD_SPACING
// For now, fractional spacing is supported only with screen space tessellation
#ifndef OSD_ENABLE_SCREENSPACE_TESSELLATION
#undef OSD_FRACTIONAL_EVEN_SPACING
#undef OSD_FRACTIONAL_ODD_SPACING
#endif
#if defined OSD_FRACTIONAL_ODD_SPACING
#define OSD_SPACING fractional_odd_spacing
#elif defined OSD_FRACTIONAL_EVEN_SPACING
#if defined OSD_FRACTIONAL_EVEN_SPACING
#define OSD_SPACING fractional_even_spacing
#elif defined OSD_FRACTIONAL_ODD_SPACING
#define OSD_SPACING fractional_odd_spacing
#else
#define OSD_SPACING equal_spacing
#endif
@ -621,7 +623,7 @@ float OsdComputeTessLevel(vec3 p0, vec3 p1)
vec3 center = (p0 + p1) / 2.0;
float diameter = distance(p0, p1);
float projLength = OsdComputePostProjectionSphereExtent(center, diameter);
float tessLevel = round(max(1.0, OsdTessLevel() * projLength));
float tessLevel = max(1.0, OsdTessLevel() * projLength);
// We restrict adaptive tessellation levels to half of the device
// supported maximum because transition edges are split into two
@ -799,6 +801,97 @@ OsdGetTessLevelsLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
#endif
}
// Round up to the nearest even integer
float OsdRoundUpEven(float x) {
return 2*ceil(x/2);
}
// Round up to the nearest odd integer
float OsdRoundUpOdd(float x) {
return 2*ceil((x+1)/2)-1;
}
// Compute outer and inner tessellation levels taking into account the
// current tessellation spacing mode.
void
OsdComputeTessLevels(inout vec4 tessOuterLo, inout vec4 tessOuterHi,
out vec4 tessLevelOuter, out vec2 tessLevelInner)
{
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have lengths of zero for non-transition edges.
#if defined OSD_FRACTIONAL_EVEN_SPACING
// Combine fractional outer transition edge levels before rounding.
vec4 combinedOuter = tessOuterLo + tessOuterHi;
// Round the segments of transition edges separately. We will recover the
// fractional parameterization of transition edges after tessellation.
tessLevelOuter = combinedOuter;
if (tessOuterHi[0] > 0) {
tessLevelOuter[0] =
OsdRoundUpEven(tessOuterLo[0]) + OsdRoundUpEven(tessOuterHi[0]);
}
if (tessOuterHi[1] > 0) {
tessLevelOuter[1] =
OsdRoundUpEven(tessOuterLo[1]) + OsdRoundUpEven(tessOuterHi[1]);
}
if (tessOuterHi[2] > 0) {
tessLevelOuter[2] =
OsdRoundUpEven(tessOuterLo[2]) + OsdRoundUpEven(tessOuterHi[2]);
}
if (tessOuterHi[3] > 0) {
tessLevelOuter[3] =
OsdRoundUpEven(tessOuterLo[3]) + OsdRoundUpEven(tessOuterHi[3]);
}
#elif defined OSD_FRACTIONAL_ODD_SPACING
// Combine fractional outer transition edge levels before rounding.
vec4 combinedOuter = tessOuterLo + tessOuterHi;
// Round the segments of transition edges separately. We will recover the
// fractional parameterization of transition edges after tessellation.
//
// The sum of the two outer odd segment lengths will be an even number
// which the tessellator will increase by +1 so that there will be a
// total odd number of segments. We clamp the combinedOuter tess levels
// (used to compute the inner tess levels) so that the outer transition
// edges will be sampled without degenerate triangles.
tessLevelOuter = combinedOuter;
if (tessOuterHi[0] > 0) {
tessLevelOuter[0] =
OsdRoundUpOdd(tessOuterLo[0]) + OsdRoundUpOdd(tessOuterHi[0]);
combinedOuter = max(vec4(3), combinedOuter);
}
if (tessOuterHi[1] > 0) {
tessLevelOuter[1] =
OsdRoundUpOdd(tessOuterLo[1]) + OsdRoundUpOdd(tessOuterHi[1]);
combinedOuter = max(vec4(3), combinedOuter);
}
if (tessOuterHi[2] > 0) {
tessLevelOuter[2] =
OsdRoundUpOdd(tessOuterLo[2]) + OsdRoundUpOdd(tessOuterHi[2]);
combinedOuter = max(vec4(3), combinedOuter);
}
if (tessOuterHi[3] > 0) {
tessLevelOuter[3] =
OsdRoundUpOdd(tessOuterLo[3]) + OsdRoundUpOdd(tessOuterHi[3]);
combinedOuter = max(vec4(3), combinedOuter);
}
#else
// Round equally spaced transition edge levels before combining.
tessOuterLo = round(tessOuterLo);
tessOuterHi = round(tessOuterHi);
vec4 combinedOuter = tessOuterLo + tessOuterHi;
tessLevelOuter = combinedOuter;
#endif
// Inner levels are the averages the corresponding outer levels.
tessLevelInner[0] = (combinedOuter[1] + combinedOuter[3]) * 0.5;
tessLevelInner[1] = (combinedOuter[0] + combinedOuter[2]) * 0.5;
}
void
OsdGetTessLevelsUniform(ivec3 patchParam,
out vec4 tessLevelOuter, out vec2 tessLevelInner,
@ -807,13 +900,8 @@ OsdGetTessLevelsUniform(ivec3 patchParam,
// uniform tessellation
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
tessLevelOuter = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
tessLevelInner[0] = (tessLevelOuter[1] + tessLevelOuter[3]) * 0.5;
tessLevelInner[1] = (tessLevelOuter[0] + tessLevelOuter[2]) * 0.5;
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
tessLevelOuter, tessLevelInner);
}
void
@ -821,15 +909,11 @@ OsdGetTessLevelsAdaptiveRefinedPoints(vec3 cpRefined[16], ivec3 patchParam,
out vec4 tessLevelOuter, out vec2 tessLevelInner,
out vec4 tessOuterLo, out vec4 tessOuterHi)
{
OsdGetTessLevelsRefinedPoints(cpRefined, patchParam, tessOuterLo, tessOuterHi);
OsdGetTessLevelsRefinedPoints(cpRefined, patchParam,
tessOuterLo, tessOuterHi);
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
tessLevelOuter = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
tessLevelInner[0] = (tessLevelOuter[1] + tessLevelOuter[3]) * 0.5;
tessLevelInner[1] = (tessLevelOuter[0] + tessLevelOuter[2]) * 0.5;
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
tessLevelOuter, tessLevelInner);
}
void
@ -838,15 +922,11 @@ OsdGetTessLevelsAdaptiveLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
out vec4 tessLevelOuter, out vec2 tessLevelInner,
out vec4 tessOuterLo, out vec4 tessOuterHi)
{
OsdGetTessLevelsLimitPoints(cpBezier, patchParam, tessOuterLo, tessOuterHi);
OsdGetTessLevelsLimitPoints(cpBezier, patchParam,
tessOuterLo, tessOuterHi);
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
tessLevelOuter = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
tessLevelInner[0] = (tessLevelOuter[1] + tessLevelOuter[3]) * 0.5;
tessLevelInner[1] = (tessLevelOuter[0] + tessLevelOuter[2]) * 0.5;
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
tessLevelOuter, tessLevelInner);
}
void
@ -867,26 +947,97 @@ OsdGetTessLevels(vec3 cp0, vec3 cp1, vec3 cp2, vec3 cp3,
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
#endif
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
tessLevelOuter = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
tessLevelInner[0] = (tessLevelOuter[1] + tessLevelOuter[3]) * 0.5;
tessLevelInner[1] = (tessLevelOuter[0] + tessLevelOuter[2]) * 0.5;
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
tessLevelOuter, tessLevelInner);
}
#if defined OSD_FRACTIONAL_EVEN_SPACING || defined OSD_FRACTIONAL_ODD_SPACING
float
OsdGetTessTransitionSplit(float t, float n0, float n1)
OsdGetTessFractionalSplit(float t, float level, float levelUp)
{
float ti = round(t * (n0 + n1));
// Fractional tessellation of an edge will produce n segments where n
// is the tessellation level of the edge (level) rounded up to the
// nearest even or odd integer (levelUp). There will be n-2 segments of
// equal length (dx1) and two additional segments of equal length (dx0)
// that are typically shorter than the other segments. The two additional
// segments should be placed symmetrically on opposite sides of the
// edge (offset).
if (ti <= n0) {
return 0.5 * (ti / n0);
#if defined OSD_FRACTIONAL_EVEN_SPACING
if (level <= 2) return t;
float base = pow(2.0,floor(log2(levelUp)));
float offset = 1.0/(int(2*base-levelUp)/2 & int(base/2-1));
#elif defined OSD_FRACTIONAL_ODD_SPACING
if (level <= 1) return t;
float base = pow(2.0,floor(log2(levelUp)));
float offset = 1.0/(((int(2*base-levelUp)/2+1) & int(base/2-1))+1);
#endif
float dx0 = (1.0 - (levelUp-level)/2) / levelUp;
float dx1 = (1.0 - 2.0*dx0) / (levelUp - 2.0*ceil(dx0));
if (t < 0.5) {
float x = levelUp/2 - round(t*levelUp);
return 0.5 - (x*dx1 + int(x*offset > 1) * (dx0 - dx1));
} else if (t > 0.5) {
float x = round(t*levelUp) - levelUp/2;
return 0.5 + (x*dx1 + int(x*offset > 1) * (dx0 - dx1));
} else {
return 0.5 * ((ti - n0) / n1) + 0.5;
return t;
}
}
#endif
float
OsdGetTessTransitionSplit(float t, float lo, float hi)
{
#if defined OSD_FRACTIONAL_EVEN_SPACING
float loRoundUp = OsdRoundUpEven(lo);
float hiRoundUp = OsdRoundUpEven(hi);
// Convert the parametric t into a segment index along the combined edge.
float ti = round(t * (loRoundUp + hiRoundUp));
if (ti <= loRoundUp) {
float t0 = ti / loRoundUp;
return OsdGetTessFractionalSplit(t0, lo, loRoundUp) * 0.5;
} else {
float t1 = (ti - loRoundUp) / hiRoundUp;
return OsdGetTessFractionalSplit(t1, hi, hiRoundUp) * 0.5 + 0.5;
}
#elif defined OSD_FRACTIONAL_ODD_SPACING
float loRoundUp = OsdRoundUpOdd(lo);
float hiRoundUp = OsdRoundUpOdd(hi);
// Convert the parametric t into a segment index along the combined edge.
// The +1 below is to account for the extra segment produced by the
// tessellator since the sum of two odd tess levels will be rounded
// up by one to the next odd integer tess level.
float ti = round(t * (loRoundUp + hiRoundUp + 1));
if (ti <= loRoundUp) {
float t0 = ti / loRoundUp;
return OsdGetTessFractionalSplit(t0, lo, loRoundUp) * 0.5;
} else if (ti > (loRoundUp+1)) {
float t1 = (ti - (loRoundUp+1)) / hiRoundUp;
return OsdGetTessFractionalSplit(t1, hi, hiRoundUp) * 0.5 + 0.5;
} else {
return 0.5;
}
#else
// Convert the parametric t into a segment index along the combined edge.
float ti = round(t * (lo + hi));
if (ti <= lo) {
return (ti / lo) * 0.5;
} else {
return ((ti - lo) / hi) * 0.5 + 0.5;
}
#endif
}
vec2
OsdGetTessParameterization(vec2 uv, vec4 tessOuterLo, vec4 tessOuterHi)
@ -941,19 +1092,27 @@ OsdFlipMatrix(mat4 m)
m[0][3], m[0][2], m[0][1], m[0][0]);
}
// Regular BSpline to Bezier
uniform mat4 Q = 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, 1.f/6.f, 4.f/6.f, 1.f/6.f
);
// Infinitely Sharp (boundary)
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
);
// convert BSpline cv to Bezier cv
void
OsdComputePerPatchVertexBSpline(ivec3 patchParam, int ID, vec3 cv[16],
out OsdPerPatchVertexBezier result)
{
// Regular BSpline to Bezier
mat4 Q = 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, 1.f/6.f, 4.f/6.f, 1.f/6.f
);
result.patchParam = patchParam;
int i = ID%4;
@ -961,15 +1120,10 @@ OsdComputePerPatchVertexBSpline(ivec3 patchParam, int ID, vec3 cv[16],
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// Infinitely Sharp (boundary)
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
);
vec3 P = vec3(0); // 0 to 1-2^(-Sf)
vec3 P1 = vec3(0); // 1-2^(-Sf) to 1-2^(-Sc)
vec3 P2 = vec3(0); // 1-2^(-Sc) to 1
mat4 Mj, Ms;
float sharpness = OsdGetPatchSharpness(patchParam);
if (sharpness > 0) {
float Sf = floor(sharpness);
@ -977,59 +1131,74 @@ OsdComputePerPatchVertexBSpline(ivec3 patchParam, int ID, vec3 cv[16],
float Sr = fract(sharpness);
mat4 Mf = OsdComputeMs(Sf);
mat4 Mc = OsdComputeMs(Sc);
Mj = (1-Sr) * Mf + Sr * Mi;
Ms = (1-Sr) * Mf + Sr * Mc;
mat4 Mj = (1-Sr) * Mf + Sr * Mi;
mat4 Ms = (1-Sr) * Mf + Sr * Mc;
float s0 = 1 - pow(2, -floor(sharpness));
float s1 = 1 - pow(2, -ceil(sharpness));
result.vSegments = vec2(s0, s1);
} else {
Mj = Ms = Mi;
result.vSegments = vec2(0);
}
result.P = vec3(0); // 0 to 1-2^(-Sf)
result.P1 = vec3(0); // 1-2^(-Sf) to 1-2^(-Sc)
result.P2 = vec3(0); // 1-2^(-Sc) to 1
mat4 MUi, MUj, MUs;
mat4 MVi, MVj, MVs;
MUi = MUj = MUs = Q;
MVi = MVj = MVs = Q;
mat4 MUi = Q, MUj = Q, MUs = Q;
mat4 MVi = Q, MVj = Q, MVs = Q;
int boundaryMask = OsdGetPatchBoundaryMask(patchParam);
if ((boundaryMask & 1) != 0) {
MVi = OsdFlipMatrix(Mi);
MVj = OsdFlipMatrix(Mj);
MVs = OsdFlipMatrix(Ms);
}
if ((boundaryMask & 2) != 0) {
MUi = Mi;
MUj = Mj;
MUs = Ms;
}
if ((boundaryMask & 4) != 0) {
MVi = Mi;
MVj = Mj;
MVs = Ms;
}
if ((boundaryMask & 8) != 0) {
MUi = OsdFlipMatrix(Mi);
MUj = OsdFlipMatrix(Mj);
MUs = OsdFlipMatrix(Ms);
}
vec3 Hi[4], Hj[4], Hs[4];
for (int l=0; l<4; ++l) {
Hi[l] = Hj[l] = Hs[l] = vec3(0);
for (int k=0; k<4; ++k) {
Hi[l] += MUi[i][k] * cv[l*4 + k];
Hj[l] += MUj[i][k] * cv[l*4 + k];
Hs[l] += MUs[i][k] * cv[l*4 + k];
int boundaryMask = OsdGetPatchBoundaryMask(patchParam);
if ((boundaryMask & 1) != 0) {
MVi = OsdFlipMatrix(Mi);
MVj = OsdFlipMatrix(Mj);
MVs = OsdFlipMatrix(Ms);
}
}
for (int k=0; k<4; ++k) {
result.P += MVi[j][k]*Hi[k];
result.P1 += MVj[j][k]*Hj[k];
result.P2 += MVs[j][k]*Hs[k];
if ((boundaryMask & 2) != 0) {
MUi = Mi;
MUj = Mj;
MUs = Ms;
}
if ((boundaryMask & 4) != 0) {
MVi = Mi;
MVj = Mj;
MVs = Ms;
}
if ((boundaryMask & 8) != 0) {
MUi = OsdFlipMatrix(Mi);
MUj = OsdFlipMatrix(Mj);
MUs = OsdFlipMatrix(Ms);
}
vec3 Hi[4], Hj[4], Hs[4];
for (int l=0; l<4; ++l) {
Hi[l] = Hj[l] = Hs[l] = vec3(0);
for (int k=0; k<4; ++k) {
Hi[l] += MUi[i][k] * cv[l*4 + k];
Hj[l] += MUj[i][k] * cv[l*4 + k];
Hs[l] += MUs[i][k] * cv[l*4 + k];
}
}
for (int k=0; k<4; ++k) {
P += MVi[j][k]*Hi[k];
P1 += MVj[j][k]*Hj[k];
P2 += MVs[j][k]*Hs[k];
}
result.P = P;
result.P1 = P1;
result.P2 = P2;
} else {
result.vSegments = vec2(0);
OsdComputeBSplineBoundaryPoints(cv, patchParam);
vec3 Hi[4];
for (int l=0; l<4; ++l) {
Hi[l] = vec3(0);
for (int k=0; k<4; ++k) {
Hi[l] += Q[i][k] * cv[l*4 + k];
}
}
for (int k=0; k<4; ++k) {
P += Q[j][k]*Hi[k];
}
result.P = P;
result.P1 = P;
result.P2 = P;
}
#else
OsdComputeBSplineBoundaryPoints(cv, patchParam);

View File

@ -26,14 +26,16 @@
// Patches.Common
//----------------------------------------------------------
// XXXdyu-patch-drawing support for fractional spacing
#undef OSD_FRACTIONAL_ODD_SPACING
// For now, fractional spacing is supported only with screen space tessellation
#ifndef OSD_ENABLE_SCREENSPACE_TESSELLATION
#undef OSD_FRACTIONAL_EVEN_SPACING
#undef OSD_FRACTIONAL_ODD_SPACING
#endif
#if defined OSD_FRACTIONAL_ODD_SPACING
#define OSD_PARTITIONING "fractional_odd"
#elif defined OSD_FRACTIONAL_EVEN_SPACING
#if defined OSD_FRACTIONAL_EVEN_SPACING
#define OSD_PARTITIONING "fractional_even"
#elif defined OSD_FRACTIONAL_ODD_SPACING
#define OSD_PARTITIONING "fractional_odd"
#else
#define OSD_PARTITIONING "integer"
#endif
@ -494,7 +496,7 @@ float OsdComputeTessLevel(float3 p0, float3 p1)
float3 center = (p0 + p1) / 2.0;
float diameter = distance(p0, p1);
float projLength = OsdComputePostProjectionSphereExtent(center, diameter);
float tessLevel = round(max(1.0, OsdTessLevel() * projLength));
float tessLevel = max(1.0, OsdTessLevel() * projLength);
// We restrict adaptive tessellation levels to half of the device
// supported maximum because transition edges are split into two
@ -674,6 +676,97 @@ OsdGetTessLevelsLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
#endif
}
// Round up to the nearest even integer
float OsdRoundUpEven(float x) {
return 2*ceil(x/2);
}
// Round up to the nearest odd integer
float OsdRoundUpOdd(float x) {
return 2*ceil((x+1)/2)-1;
}
// Compute outer and inner tessellation levels taking into account the
// current tessellation spacing mode.
void
OsdComputeTessLevels(inout float4 tessOuterLo, inout float4 tessOuterHi,
out float4 tessLevelOuter, out float2 tessLevelInner)
{
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have lengths of zero for non-transition edges.
#if defined OSD_FRACTIONAL_EVEN_SPACING
// Combine fractional outer transition edge levels before rounding.
float4 combinedOuter = tessOuterLo + tessOuterHi;
// Round the segments of transition edges separately. We will recover the
// fractional parameterization of transition edges after tessellation.
tessLevelOuter = combinedOuter;
if (tessOuterHi[0] > 0) {
tessLevelOuter[0] =
OsdRoundUpEven(tessOuterLo[0]) + OsdRoundUpEven(tessOuterHi[0]);
}
if (tessOuterHi[1] > 0) {
tessLevelOuter[1] =
OsdRoundUpEven(tessOuterLo[1]) + OsdRoundUpEven(tessOuterHi[1]);
}
if (tessOuterHi[2] > 0) {
tessLevelOuter[2] =
OsdRoundUpEven(tessOuterLo[2]) + OsdRoundUpEven(tessOuterHi[2]);
}
if (tessOuterHi[3] > 0) {
tessLevelOuter[3] =
OsdRoundUpEven(tessOuterLo[3]) + OsdRoundUpEven(tessOuterHi[3]);
}
#elif defined OSD_FRACTIONAL_ODD_SPACING
// Combine fractional outer transition edge levels before rounding.
float4 combinedOuter = tessOuterLo + tessOuterHi;
// Round the segments of transition edges separately. We will recover the
// fractional parameterization of transition edges after tessellation.
//
// The sum of the two outer odd segment lengths will be an even number
// which the tessellator will increase by +1 so that there will be a
// total odd number of segments. We clamp the combinedOuter tess levels
// (used to compute the inner tess levels) so that the outer transition
// edges will be sampled without degenerate triangles.
tessLevelOuter = combinedOuter;
if (tessOuterHi[0] > 0) {
tessLevelOuter[0] =
OsdRoundUpOdd(tessOuterLo[0]) + OsdRoundUpOdd(tessOuterHi[0]);
combinedOuter = max(float4(3,3,3,3), combinedOuter);
}
if (tessOuterHi[1] > 0) {
tessLevelOuter[1] =
OsdRoundUpOdd(tessOuterLo[1]) + OsdRoundUpOdd(tessOuterHi[1]);
combinedOuter = max(float4(3,3,3,3), combinedOuter);
}
if (tessOuterHi[2] > 0) {
tessLevelOuter[2] =
OsdRoundUpOdd(tessOuterLo[2]) + OsdRoundUpOdd(tessOuterHi[2]);
combinedOuter = max(float4(3,3,3,3), combinedOuter);
}
if (tessOuterHi[3] > 0) {
tessLevelOuter[3] =
OsdRoundUpOdd(tessOuterLo[3]) + OsdRoundUpOdd(tessOuterHi[3]);
combinedOuter = max(float4(3,3,3,3), combinedOuter);
}
#else
// Round equally spaced transition edge levels before combining.
tessOuterLo = round(tessOuterLo);
tessOuterHi = round(tessOuterHi);
float4 combinedOuter = tessOuterLo + tessOuterHi;
tessLevelOuter = combinedOuter;
#endif
// Inner levels are the averages the corresponding outer levels.
tessLevelInner[0] = (combinedOuter[1] + combinedOuter[3]) * 0.5;
tessLevelInner[1] = (combinedOuter[0] + combinedOuter[2]) * 0.5;
}
void
OsdGetTessLevelsUniform(int3 patchParam,
out float4 tessLevelOuter, out float2 tessLevelInner,
@ -681,13 +774,8 @@ OsdGetTessLevelsUniform(int3 patchParam,
{
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
tessLevelOuter = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
tessLevelInner[0] = (tessLevelOuter[1] + tessLevelOuter[3]) * 0.5;
tessLevelInner[1] = (tessLevelOuter[0] + tessLevelOuter[2]) * 0.5;
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
tessLevelOuter, tessLevelInner);
}
void
@ -695,15 +783,11 @@ OsdGetTessLevelsAdaptiveRefinedPoints(float3 cpRefined[16], int3 patchParam,
out float4 tessLevelOuter, out float2 tessLevelInner,
out float4 tessOuterLo, out float4 tessOuterHi)
{
OsdGetTessLevelsRefinedPoints(cpRefined, patchParam, tessOuterLo, tessOuterHi);
OsdGetTessLevelsRefinedPoints(cpRefined, patchParam,
tessOuterLo, tessOuterHi);
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
tessLevelOuter = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
tessLevelInner[0] = (tessLevelOuter[1] + tessLevelOuter[3]) * 0.5;
tessLevelInner[1] = (tessLevelOuter[0] + tessLevelOuter[2]) * 0.5;
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
tessLevelOuter, tessLevelInner);
}
void
@ -712,15 +796,11 @@ OsdGetTessLevelsAdaptiveLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
out float4 tessLevelOuter, out float2 tessLevelInner,
out float4 tessOuterLo, out float4 tessOuterHi)
{
OsdGetTessLevelsLimitPoints(cpBezier, patchParam, tessOuterLo, tessOuterHi);
OsdGetTessLevelsLimitPoints(cpBezier, patchParam,
tessOuterLo, tessOuterHi);
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
tessLevelOuter = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
tessLevelInner[0] = (tessLevelOuter[1] + tessLevelOuter[3]) * 0.5;
tessLevelInner[1] = (tessLevelOuter[0] + tessLevelOuter[2]) * 0.5;
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
tessLevelOuter, tessLevelInner);
}
void
@ -741,26 +821,97 @@ OsdGetTessLevels(float3 cp0, float3 cp1, float3 cp2, float3 cp3,
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
#endif
// Outer levels are the sum of the Lo and Hi segments where the Hi
// segments will have a length of zero for non-transition edges.
tessLevelOuter = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
tessLevelInner[0] = (tessLevelOuter[1] + tessLevelOuter[3]) * 0.5;
tessLevelInner[1] = (tessLevelOuter[0] + tessLevelOuter[2]) * 0.5;
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
tessLevelOuter, tessLevelInner);
}
#if defined OSD_FRACTIONAL_EVEN_SPACING || defined OSD_FRACTIONAL_ODD_SPACING
float
OsdGetTessTransitionSplit(float t, float n0, float n1)
OsdGetTessFractionalSplit(float t, float level, float levelUp)
{
float ti = round(t * (n0 + n1));
// Fractional tessellation of an edge will produce n segments where n
// is the tessellation level of the edge (level) rounded up to the
// nearest even or odd integer (levelUp). There will be n-2 segments of
// equal length (dx1) and two additional segments of equal length (dx0)
// that are typically shorter than the other segments. The two additional
// segments should be placed symmetrically on opposite sides of the
// edge (offset).
if (ti <= n0) {
return 0.5 * (ti / n0);
#if defined OSD_FRACTIONAL_EVEN_SPACING
if (level <= 2) return t;
float base = pow(2.0,floor(log2(levelUp)));
float offset = 1.0/(int(2*base-levelUp)/2 & int(base/2-1));
#elif defined OSD_FRACTIONAL_ODD_SPACING
if (level <= 1) return t;
float base = pow(2.0,floor(log2(levelUp)));
float offset = 1.0/(((int(2*base-levelUp)/2+1) & int(base/2-1))+1);
#endif
float dx0 = (1.0 - (levelUp-level)/2) / levelUp;
float dx1 = (1.0 - 2.0*dx0) / (levelUp - 2.0*ceil(dx0));
if (t < 0.5) {
float x = levelUp/2 - round(t*levelUp);
return 0.5 - (x*dx1 + int(x*offset > 1) * (dx0 - dx1));
} else if (t > 0.5) {
float x = round(t*levelUp) - levelUp/2;
return 0.5 + (x*dx1 + int(x*offset > 1) * (dx0 - dx1));
} else {
return 0.5 * ((ti - n0) / n1) + 0.5;
return t;
}
}
#endif
float
OsdGetTessTransitionSplit(float t, float lo, float hi)
{
#if defined OSD_FRACTIONAL_EVEN_SPACING
float loRoundUp = OsdRoundUpEven(lo);
float hiRoundUp = OsdRoundUpEven(hi);
// Convert the parametric t into a segment index along the combined edge.
float ti = round(t * (loRoundUp + hiRoundUp));
if (ti <= loRoundUp) {
float t0 = ti / loRoundUp;
return OsdGetTessFractionalSplit(t0, lo, loRoundUp) * 0.5;
} else {
float t1 = (ti - loRoundUp) / hiRoundUp;
return OsdGetTessFractionalSplit(t1, hi, hiRoundUp) * 0.5 + 0.5;
}
#elif defined OSD_FRACTIONAL_ODD_SPACING
float loRoundUp = OsdRoundUpOdd(lo);
float hiRoundUp = OsdRoundUpOdd(hi);
// Convert the parametric t into a segment index along the combined edge.
// The +1 below is to account for the extra segment produced by the
// tessellator since the sum of two odd tess levels will be rounded
// up by one to the next odd integer tess level.
float ti = round(t * (loRoundUp + hiRoundUp + 1));
if (ti <= loRoundUp) {
float t0 = ti / loRoundUp;
return OsdGetTessFractionalSplit(t0, lo, loRoundUp) * 0.5;
} else if (ti > (loRoundUp+1)) {
float t1 = (ti - (loRoundUp+1)) / hiRoundUp;
return OsdGetTessFractionalSplit(t1, hi, hiRoundUp) * 0.5 + 0.5;
} else {
return 0.5;
}
#else
// Convert the parametric t into a segment index along the combined edge.
float ti = round(t * (lo + hi));
if (ti <= lo) {
return (ti / lo) * 0.5;
} else {
return ((ti - lo) / hi) * 0.5 + 0.5;
}
#endif
}
float2
OsdGetTessParameterization(float2 uv, float4 tessOuterLo, float4 tessOuterHi)
@ -815,19 +966,27 @@ OsdFlipMatrix(float4x4 m)
m[0][3], m[0][2], m[0][1], m[0][0]);
}
// Regular BSpline to Bezier
static float4x4 Q = {
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, 1.f/6.f, 4.f/6.f, 1.f/6.f
};
// Infinitely Sharp (boundary)
static float4x4 Mi = {
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
};
// convert BSpline cv to Bezier cv
void
OsdComputePerPatchVertexBSpline(int3 patchParam, int ID, float3 cv[16],
out OsdPerPatchVertexBezier result)
{
// Regular BSpline to Bezier
float4x4 Q = {
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, 1.f/6.f, 4.f/6.f, 1.f/6.f
};
result.patchParam = patchParam;
int i = ID%4;
@ -835,15 +994,10 @@ OsdComputePerPatchVertexBSpline(int3 patchParam, int ID, float3 cv[16],
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// Infinitely Sharp (boundary)
float4x4 Mi = {
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
};
float3 P = float3(0,0,0); // 0 to 1-2^(-Sf)
float3 P1 = float3(0,0,0); // 1-2^(-Sf) to 1-2^(-Sc)
float3 P2 = float3(0,0,0); // 1-2^(-Sc) to 1
float4x4 Mj, Ms;
float sharpness = OsdGetPatchSharpness(patchParam);
if (sharpness > 0) {
float Sf = floor(sharpness);
@ -851,60 +1005,74 @@ OsdComputePerPatchVertexBSpline(int3 patchParam, int ID, float3 cv[16],
float Sr = frac(sharpness);
float4x4 Mf = OsdComputeMs(Sf);
float4x4 Mc = OsdComputeMs(Sc);
Mj = (1-Sr) * Mf + Sr * Mi;
Ms = (1-Sr) * Mf + Sr * Mc;
float4x4 Mj = (1-Sr) * Mf + Sr * Mi;
float4x4 Ms = (1-Sr) * Mf + Sr * Mc;
float s0 = 1 - pow(2, -floor(sharpness));
float s1 = 1 - pow(2, -ceil(sharpness));
result.vSegments = float2(s0, s1);
} else {
Mj = Ms = Mi;
result.vSegments = float2(0, 0);
}
result.P = float3(0,0,0); // 0 to 1-2^(-Sf)
result.P1 = float3(0,0,0); // 1-2^(-Sf) to 1-2^(-Sc)
result.P2 = float3(0,0,0); // 1-2^(-Sc) to 1
float4x4 MUi = Q, MUj = Q, MUs = Q;
float4x4 MVi = Q, MVj = Q, MVs = Q;
float4x4 MUi, MUj, MUs;
float4x4 MVi, MVj, MVs;
MUi = MUj = MUs = Q;
MVi = MVj = MVs = Q;
int boundaryMask = OsdGetPatchBoundaryMask(patchParam);
if ((boundaryMask & 1) != 0) {
MVi = OsdFlipMatrix(Mi);
MVj = OsdFlipMatrix(Mj);
MVs = OsdFlipMatrix(Ms);
}
if ((boundaryMask & 2) != 0) {
MUi = Mi;
MUj = Mj;
MUs = Ms;
}
if ((boundaryMask & 4) != 0) {
MVi = Mi;
MVj = Mj;
MVs = Ms;
}
if ((boundaryMask & 8) != 0) {
MUi = OsdFlipMatrix(Mi);
MUj = OsdFlipMatrix(Mj);
MUs = OsdFlipMatrix(Ms);
}
float3 Hi[4], Hj[4], Hs[4];
for (int l=0; l<4; ++l) {
Hi[l] = Hj[l] = Hs[l] = float3(0,0,0);
for (int k=0; k<4; ++k) {
Hi[l] += MUi[i][k] * cv[l*4 + k];
Hj[l] += MUj[i][k] * cv[l*4 + k];
Hs[l] += MUs[i][k] * cv[l*4 + k];
int boundaryMask = OsdGetPatchBoundaryMask(patchParam);
if ((boundaryMask & 1) != 0) {
MVi = OsdFlipMatrix(Mi);
MVj = OsdFlipMatrix(Mj);
MVs = OsdFlipMatrix(Ms);
}
}
for (int k=0; k<4; ++k) {
result.P += MVi[j][k]*Hi[k];
result.P1 += MVj[j][k]*Hj[k];
result.P2 += MVs[j][k]*Hs[k];
if ((boundaryMask & 2) != 0) {
MUi = Mi;
MUj = Mj;
MUs = Ms;
}
if ((boundaryMask & 4) != 0) {
MVi = Mi;
MVj = Mj;
MVs = Ms;
}
if ((boundaryMask & 8) != 0) {
MUi = OsdFlipMatrix(Mi);
MUj = OsdFlipMatrix(Mj);
MUs = OsdFlipMatrix(Ms);
}
float3 Hi[4], Hj[4], Hs[4];
for (int l=0; l<4; ++l) {
Hi[l] = Hj[l] = Hs[l] = float3(0,0,0);
for (int k=0; k<4; ++k) {
Hi[l] += MUi[i][k] * cv[l*4 + k];
Hj[l] += MUj[i][k] * cv[l*4 + k];
Hs[l] += MUs[i][k] * cv[l*4 + k];
}
}
for (int k=0; k<4; ++k) {
P += MVi[j][k]*Hi[k];
P1 += MVj[j][k]*Hj[k];
P2 += MVs[j][k]*Hs[k];
}
result.P = P;
result.P1 = P1;
result.P2 = P2;
} else {
result.vSegments = float2(0, 0);
OsdComputeBSplineBoundaryPoints(cv, patchParam);
float3 Hi[4];
for (int l=0; l<4; ++l) {
Hi[l] = float3(0,0,0);
for (int k=0; k<4; ++k) {
Hi[l] += Q[i][k] * cv[l*4 + k];
}
}
for (int k=0; k<4; ++k) {
P += Q[j][k]*Hi[k];
}
result.P = P;
result.P1 = P;
result.P2 = P;
}
#else
OsdComputeBSplineBoundaryPoints(cv, patchParam);

View File

@ -25,7 +25,7 @@
#ifndef OPENSUBDIV3_VERSION_H
#define OPENSUBDIV3_VERSION_H
#define OPENSUBDIV_VERSION v3_0_3
#define OPENSUBDIV_VERSION v3_0_5
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {

View File

@ -163,10 +163,13 @@ int main(int, char **) {
std::vector<Vertex> verts(nRefinerVertices + nLocalPoints);
memcpy(&verts[0], g_verts, g_nverts*3*sizeof(float));
// Adaptive refinement may result in fewer levels than maxIsolation.
int nRefinedLevels = refiner->GetNumLevels();
// Interpolate vertex primvar data : they are the control vertices
// of the limit patches (see far_tutorial_0 for details)
Vertex * src = &verts[0];
for (int level = 1; level <= maxIsolation; ++level) {
for (int level = 1; level < nRefinedLevels; ++level) {
Vertex * dst = src + refiner->GetLevel(level-1).GetNumVertices();
Far::PrimvarRefiner(*refiner).Interpolate(level, src, dst);
src = dst;