mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2025-01-09 08:10:07 +00:00
Restored support for fractional tessellation
This change includes support for both fractional_even_spacing and fractional_odd_spacing. The implementation follows the existing pattern of re-parameterizing the tessellation domain only along transition boundary edges. This allows for crack-free tessellation, but it might be better to consistently re-parameterize all of the outer edges of all patches, which also would be required for numerically watertight tessellation. This is implemented in a way that requires no changes to the client shader API. It should be more efficient to move some computations to the control/hull shaders and reduce divergence in the execution of eval/domain shaders.
This commit is contained in:
parent
c8a538cd43
commit
8987e09102
@ -72,14 +72,10 @@
|
|||||||
// mix(input[c].var, input[d].var, UV.x), UV.y)
|
// mix(input[c].var, input[d].var, UV.x), UV.y)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// XXXdyu-patch-drawing support for fractional spacing
|
#if defined OSD_FRACTIONAL_EVEN_SPACING
|
||||||
#undef OSD_FRACTIONAL_ODD_SPACING
|
|
||||||
#undef OSD_FRACTIONAL_EVEN_SPACING
|
|
||||||
|
|
||||||
#if defined OSD_FRACTIONAL_ODD_SPACING
|
|
||||||
#define OSD_SPACING fractional_odd_spacing
|
|
||||||
#elif defined OSD_FRACTIONAL_EVEN_SPACING
|
|
||||||
#define OSD_SPACING fractional_even_spacing
|
#define OSD_SPACING fractional_even_spacing
|
||||||
|
#elif defined OSD_FRACTIONAL_ODD_SPACING
|
||||||
|
#define OSD_SPACING fractional_odd_spacing
|
||||||
#else
|
#else
|
||||||
#define OSD_SPACING equal_spacing
|
#define OSD_SPACING equal_spacing
|
||||||
#endif
|
#endif
|
||||||
@ -621,7 +617,7 @@ float OsdComputeTessLevel(vec3 p0, vec3 p1)
|
|||||||
vec3 center = (p0 + p1) / 2.0;
|
vec3 center = (p0 + p1) / 2.0;
|
||||||
float diameter = distance(p0, p1);
|
float diameter = distance(p0, p1);
|
||||||
float projLength = OsdComputePostProjectionSphereExtent(center, diameter);
|
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
|
// We restrict adaptive tessellation levels to half of the device
|
||||||
// supported maximum because transition edges are split into two
|
// supported maximum because transition edges are split into two
|
||||||
@ -799,6 +795,97 @@ OsdGetTessLevelsLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
|
|||||||
#endif
|
#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
|
void
|
||||||
OsdGetTessLevelsUniform(ivec3 patchParam,
|
OsdGetTessLevelsUniform(ivec3 patchParam,
|
||||||
out vec4 tessLevelOuter, out vec2 tessLevelInner,
|
out vec4 tessLevelOuter, out vec2 tessLevelInner,
|
||||||
@ -807,13 +894,8 @@ OsdGetTessLevelsUniform(ivec3 patchParam,
|
|||||||
// uniform tessellation
|
// uniform tessellation
|
||||||
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
|
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
|
||||||
|
|
||||||
// Outer levels are the sum of the Lo and Hi segments where the Hi
|
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
|
||||||
// segments will have a length of zero for non-transition edges.
|
tessLevelOuter, tessLevelInner);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -821,15 +903,11 @@ OsdGetTessLevelsAdaptiveRefinedPoints(vec3 cpRefined[16], ivec3 patchParam,
|
|||||||
out vec4 tessLevelOuter, out vec2 tessLevelInner,
|
out vec4 tessLevelOuter, out vec2 tessLevelInner,
|
||||||
out vec4 tessOuterLo, out vec4 tessOuterHi)
|
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
|
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
|
||||||
// segments will have a length of zero for non-transition edges.
|
tessLevelOuter, tessLevelInner);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -838,15 +916,11 @@ OsdGetTessLevelsAdaptiveLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
|
|||||||
out vec4 tessLevelOuter, out vec2 tessLevelInner,
|
out vec4 tessLevelOuter, out vec2 tessLevelInner,
|
||||||
out vec4 tessOuterLo, out vec4 tessOuterHi)
|
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
|
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
|
||||||
// segments will have a length of zero for non-transition edges.
|
tessLevelOuter, tessLevelInner);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -867,25 +941,96 @@ OsdGetTessLevels(vec3 cp0, vec3 cp1, vec3 cp2, vec3 cp3,
|
|||||||
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
|
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Outer levels are the sum of the Lo and Hi segments where the Hi
|
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
|
||||||
// segments will have a length of zero for non-transition edges.
|
tessLevelOuter, tessLevelInner);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined OSD_FRACTIONAL_EVEN_SPACING || defined OSD_FRACTIONAL_ODD_SPACING
|
||||||
|
float
|
||||||
|
OsdGetTessFractionalSplit(float t, float level, float levelUp)
|
||||||
|
{
|
||||||
|
// 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 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 t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
float
|
float
|
||||||
OsdGetTessTransitionSplit(float t, float n0, float n1)
|
OsdGetTessTransitionSplit(float t, float lo, float hi)
|
||||||
{
|
{
|
||||||
float ti = round(t * (n0 + n1));
|
#if defined OSD_FRACTIONAL_EVEN_SPACING
|
||||||
|
float loRoundUp = OsdRoundUpEven(lo);
|
||||||
|
float hiRoundUp = OsdRoundUpEven(hi);
|
||||||
|
|
||||||
if (ti <= n0) {
|
// Convert the parametric t into a segment index along the combined edge.
|
||||||
return 0.5 * (ti / n0);
|
float ti = round(t * (loRoundUp + hiRoundUp));
|
||||||
|
|
||||||
|
if (ti <= loRoundUp) {
|
||||||
|
float t0 = ti / loRoundUp;
|
||||||
|
return OsdGetTessFractionalSplit(t0, lo, loRoundUp) * 0.5;
|
||||||
} else {
|
} else {
|
||||||
return 0.5 * ((ti - n0) / n1) + 0.5;
|
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
|
vec2
|
||||||
|
@ -26,14 +26,10 @@
|
|||||||
// Patches.Common
|
// Patches.Common
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
|
||||||
// XXXdyu-patch-drawing support for fractional spacing
|
#if defined OSD_FRACTIONAL_EVEN_SPACING
|
||||||
#undef OSD_FRACTIONAL_ODD_SPACING
|
|
||||||
#undef OSD_FRACTIONAL_EVEN_SPACING
|
|
||||||
|
|
||||||
#if defined OSD_FRACTIONAL_ODD_SPACING
|
|
||||||
#define OSD_PARTITIONING "fractional_odd"
|
|
||||||
#elif defined OSD_FRACTIONAL_EVEN_SPACING
|
|
||||||
#define OSD_PARTITIONING "fractional_even"
|
#define OSD_PARTITIONING "fractional_even"
|
||||||
|
#elif defined OSD_FRACTIONAL_ODD_SPACING
|
||||||
|
#define OSD_PARTITIONING "fractional_odd"
|
||||||
#else
|
#else
|
||||||
#define OSD_PARTITIONING "integer"
|
#define OSD_PARTITIONING "integer"
|
||||||
#endif
|
#endif
|
||||||
@ -494,7 +490,7 @@ float OsdComputeTessLevel(float3 p0, float3 p1)
|
|||||||
float3 center = (p0 + p1) / 2.0;
|
float3 center = (p0 + p1) / 2.0;
|
||||||
float diameter = distance(p0, p1);
|
float diameter = distance(p0, p1);
|
||||||
float projLength = OsdComputePostProjectionSphereExtent(center, diameter);
|
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
|
// We restrict adaptive tessellation levels to half of the device
|
||||||
// supported maximum because transition edges are split into two
|
// supported maximum because transition edges are split into two
|
||||||
@ -674,6 +670,97 @@ OsdGetTessLevelsLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
|
|||||||
#endif
|
#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
|
void
|
||||||
OsdGetTessLevelsUniform(int3 patchParam,
|
OsdGetTessLevelsUniform(int3 patchParam,
|
||||||
out float4 tessLevelOuter, out float2 tessLevelInner,
|
out float4 tessLevelOuter, out float2 tessLevelInner,
|
||||||
@ -681,13 +768,8 @@ OsdGetTessLevelsUniform(int3 patchParam,
|
|||||||
{
|
{
|
||||||
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
|
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
|
||||||
|
|
||||||
// Outer levels are the sum of the Lo and Hi segments where the Hi
|
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
|
||||||
// segments will have a length of zero for non-transition edges.
|
tessLevelOuter, tessLevelInner);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -695,15 +777,11 @@ OsdGetTessLevelsAdaptiveRefinedPoints(float3 cpRefined[16], int3 patchParam,
|
|||||||
out float4 tessLevelOuter, out float2 tessLevelInner,
|
out float4 tessLevelOuter, out float2 tessLevelInner,
|
||||||
out float4 tessOuterLo, out float4 tessOuterHi)
|
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
|
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
|
||||||
// segments will have a length of zero for non-transition edges.
|
tessLevelOuter, tessLevelInner);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -712,15 +790,11 @@ OsdGetTessLevelsAdaptiveLimitPoints(OsdPerPatchVertexBezier cpBezier[16],
|
|||||||
out float4 tessLevelOuter, out float2 tessLevelInner,
|
out float4 tessLevelOuter, out float2 tessLevelInner,
|
||||||
out float4 tessOuterLo, out float4 tessOuterHi)
|
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
|
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
|
||||||
// segments will have a length of zero for non-transition edges.
|
tessLevelOuter, tessLevelInner);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -741,25 +815,96 @@ OsdGetTessLevels(float3 cp0, float3 cp1, float3 cp2, float3 cp3,
|
|||||||
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
|
OsdGetTessLevelsUniform(patchParam, tessOuterLo, tessOuterHi);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Outer levels are the sum of the Lo and Hi segments where the Hi
|
OsdComputeTessLevels(tessOuterLo, tessOuterHi,
|
||||||
// segments will have a length of zero for non-transition edges.
|
tessLevelOuter, tessLevelInner);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined OSD_FRACTIONAL_EVEN_SPACING || defined OSD_FRACTIONAL_ODD_SPACING
|
||||||
|
float
|
||||||
|
OsdGetTessFractionalSplit(float t, float level, float levelUp)
|
||||||
|
{
|
||||||
|
// 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 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 t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
float
|
float
|
||||||
OsdGetTessTransitionSplit(float t, float n0, float n1)
|
OsdGetTessTransitionSplit(float t, float lo, float hi)
|
||||||
{
|
{
|
||||||
float ti = round(t * (n0 + n1));
|
#if defined OSD_FRACTIONAL_EVEN_SPACING
|
||||||
|
float loRoundUp = OsdRoundUpEven(lo);
|
||||||
|
float hiRoundUp = OsdRoundUpEven(hi);
|
||||||
|
|
||||||
if (ti <= n0) {
|
// Convert the parametric t into a segment index along the combined edge.
|
||||||
return 0.5 * (ti / n0);
|
float ti = round(t * (loRoundUp + hiRoundUp));
|
||||||
|
|
||||||
|
if (ti <= loRoundUp) {
|
||||||
|
float t0 = ti / loRoundUp;
|
||||||
|
return OsdGetTessFractionalSplit(t0, lo, loRoundUp) * 0.5;
|
||||||
} else {
|
} else {
|
||||||
return 0.5 * ((ti - n0) / n1) + 0.5;
|
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
|
float2
|
||||||
|
Loading…
Reference in New Issue
Block a user