mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-12-22 16:00: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)
|
||||
#endif
|
||||
|
||||
// XXXdyu-patch-drawing support for fractional 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
|
||||
#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 +617,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 +795,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 +894,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 +903,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 +916,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 +941,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)
|
||||
|
@ -26,14 +26,10 @@
|
||||
// Patches.Common
|
||||
//----------------------------------------------------------
|
||||
|
||||
// XXXdyu-patch-drawing support for fractional 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
|
||||
#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 +490,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 +670,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 +768,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 +777,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 +790,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 +815,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)
|
||||
|
Loading…
Reference in New Issue
Block a user