Updated handling of patchParam and patchCoord

Each patch has a corresponding patchParam. This is a set of three values
specifying additional information about the patch:

   faceId    -- topological face identifier (e.g. Ptex FaceId)
   bitfield  -- refinement-level, non-quad, boundary, transition, uv-offset
   sharpness -- crease sharpness for a single-crease patch

These are stored in OsdPatchParamBuffer indexed by the value returned
from OsdGetPatchIndex() which is a function of the current PrimitiveID
along with an optional client provided offset.

Accessors are provided to extract values from a patchParam. These are
all named OsdGetPatch*().

While drawing patches, the patchParam is condensed into a patchCoord which
has four values (u, v, faceLevel, faceId). These patchCoords are treated
as int values during per-prim processing but are converted to float values
during per-vertex processing where the values are interpolated.

Also, cleaned up more of the shader namespace by giving an Osd prefix
to public functions, and consolidated boundary and transition handling
code into the PatchCommon shader files. The functions determining
tessellation levels are now all named OsdGetTessLevel*().
This commit is contained in:
David G Yu 2015-05-01 17:52:37 -07:00 committed by David G. Yu
parent efb010557d
commit 8b4ef28116
15 changed files with 941 additions and 945 deletions

View File

@ -114,19 +114,10 @@ float4 displacement(float4 position, float3 normal, float4 patchCoord)
}
#endif
#line 20117
float4 GeneratePatchCoord(float2 localUV, int primitiveID) // for non-adpative
float4 GeneratePatchCoord(float2 uv, int primitiveID) // for non-adaptive
{
int2 ptexIndex = OsdPatchParamBuffer[GetPrimitiveID(primitiveID)].xy;
int faceID = ptexIndex.x;
int lv = 1 << ((ptexIndex.y & 0xf) - ((ptexIndex.y >> 4) & 1));
int u = (ptexIndex.y >> 17) & 0x3ff;
int v = (ptexIndex.y >> 7) & 0x3ff;
float2 uv = localUV;
uv = (uv * float2(1, 1)/lv) + float2(u, v)/lv;
return float4(uv.x, uv.y, lv+0.5, faceID+0.5);
int3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(primitiveID));
return OsdInterpolatePatchCoord(uv, OsdGetPatchCoord(patchParam));
}
// ---------------------------------------------------------------------------
@ -139,6 +130,11 @@ void vs_main( in InputVertex input,
output.positionOut = mul(ModelViewProjectionMatrix, input.position);
output.position = mul(ModelViewMatrix, input.position);
output.normal = mul(ModelViewMatrix,float4(input.normal, 0)).xyz;
output.patchCoord = float4(0,0,0,0);
output.tangent = float3(0,0,0);
output.bitangent = float3(0,0,0);
output.edgeDistance = float4(0,0,0,0);
}
// ---------------------------------------------------------------------------

View File

@ -21,7 +21,6 @@
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#line 25
//--------------------------------------------------------------
// Common
@ -30,17 +29,10 @@
uniform float displacementScale = 1.0;
uniform float mipmapBias = 0;
vec4 GeneratePatchCoord(vec2 localUV, int primitiveID) // for non-adpative
vec4 GeneratePatchCoord(vec2 uv, int primitiveID) // for non-adaptive
{
ivec2 ptexIndex = texelFetch(OsdPatchParamBuffer, primitiveID).xy;
int faceID = ptexIndex.x;
int lv = 1 << ((ptexIndex.y & 0xf) - ((ptexIndex.y >> 4) & 1));
int u = (ptexIndex.y >> 17) & 0x3ff;
int v = (ptexIndex.y >> 7) & 0x3ff;
vec2 uv = localUV;
uv = (uv * vec2(1.0)/lv) + vec2(u, v)/lv;
return vec4(uv.x, uv.y, lv+0.5, faceID+0.5);
ivec3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(primitiveID));
return OsdInterpolatePatchCoord(uv, OsdGetPatchCoord(patchParam));
}
#if defined(DISPLACEMENT_HW_BILINEAR) \
@ -490,14 +482,14 @@ GetOverrideColor(int patchParam)
#elif defined OSD_PATCH_GREGORY_BASIS
patchType = 6;
#endif
int edgeCount = bitCount((patchParam >> 4) & 0xf);
int edgeCount = bitCount(OsdGetPatchBoundaryMask(patchParam));
if (edgeCount == 1) {
patchType = 2; // BOUNDARY
}
if (edgeCount == 2) {
patchType = 3; // CORNER
}
int pattern = bitCount((patchParam >> 8) & 0xf);
int pattern = bitCount(OsdGetPatchTransitionMask(patchParam));
int offset = 7*patchType + pattern;
return patchColors[offset];
}
@ -675,7 +667,7 @@ main()
textureImage_Data,
textureImage_Packing);
#elif defined COLOR_PATCHTYPE
vec4 texColor = edgeColor(lighting(GetOverrideColor(GetPatchParam()), inpt.v.position.xyz, normal, 1, 0));
vec4 texColor = edgeColor(lighting(GetOverrideColor(OsdGetPatchParam(OsdGetPatchIndex(gl_PrimitiveID))), inpt.v.position.xyz, normal, 1, 0));
outColor = texColor;
return;
#elif defined COLOR_PATCHCOORD

View File

@ -388,7 +388,7 @@ edgeColor(vec4 Cfill, vec4 edgeDistance)
}
vec4
getAdaptivePatchColor(int patchParam)
getAdaptivePatchColor(ivec3 patchParam)
{
const vec4 patchColors[7*6] = vec4[7*6](
vec4(1.0f, 1.0f, 1.0f, 1.0f), // regular
@ -450,7 +450,7 @@ getAdaptivePatchColor(int patchParam)
patchType = 6;
#endif
int edgeCount = bitCount((patchParam >> 4) & 0xf);
int edgeCount = bitCount(OsdGetPatchBoundaryMask(patchParam));
if (edgeCount == 1) {
patchType = 2; // BOUNDARY
}
@ -458,7 +458,7 @@ getAdaptivePatchColor(int patchParam)
patchType = 3; // CORNER
}
int pattern = bitCount((patchParam >> 8) & 0xf);
int pattern = bitCount(OsdGetPatchTransitionMask(patchParam));
#ifdef OSD_PATCH_ENABLE_SINGLE_CREASE
if (inpt.sharpness > 0) pattern += 6;
#endif
@ -480,7 +480,7 @@ main()
int(floor(20*inpt.color.r)+floor(20*inpt.color.g))&1, 1);
#else
//vec4 color = diffuseColor;
vec4 color = getAdaptivePatchColor(GetPatchParam());
vec4 color = getAdaptivePatchColor(OsdGetPatchParam(OsdGetPatchIndex(gl_PrimitiveID)));
#endif
vec4 Cf = lighting(color, inpt.v.position.xyz, N);

View File

@ -201,7 +201,6 @@ if( OPENGL_FOUND OR OPENGLES_FOUND )
glslPatchBSpline.glsl
glslPatchGregory.glsl
glslPatchGregoryBasis.glsl
glslPatchTransition.glsl
glslPtexCommon.glsl
)
endif()
@ -284,7 +283,6 @@ if( DXSDK_FOUND )
hlslPatchCommon.hlsl
hlslPatchBSpline.hlsl
hlslPatchGregory.hlsl
hlslPatchTransition.hlsl
hlslPtexCommon.hlsl
)
list(APPEND PLATFORM_GPU_LIBRARIES

View File

@ -56,9 +56,6 @@ static const char *bsplineShaderSource =
static const char *gregoryShaderSource =
#include "hlslPatchGregory.gen.h"
;
static const char *transitionShaderSource =
#include "hlslPatchTransition.gen.h"
;
D3D11DrawRegistryBase::~D3D11DrawRegistryBase() {}
@ -89,16 +86,13 @@ D3D11DrawRegistryBase::_CreateDrawSourceConfig(
case Far::PatchDescriptor::CORNER:
sconfig->commonShader.AddDefine("OSD_PATCH_BSPLINE");
sconfig->commonShader.AddDefine("OSD_PATCH_ENABLE_SINGLE_CREASE");
sconfig->vertexShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.target = "vs_5_0";
sconfig->vertexShader.entry = "vs_main_patches";
sconfig->hullShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->hullShader.source = bsplineShaderSource;
sconfig->hullShader.target = "hs_5_0";
sconfig->hullShader.entry = "hs_main_patches";
sconfig->domainShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->domainShader.source = bsplineShaderSource;
sconfig->domainShader.target = "ds_5_0";
sconfig->domainShader.entry = "ds_main_patches";
break;

View File

@ -55,9 +55,6 @@ static const char *gregoryShaderSource =
static const char *gregoryBasisShaderSource =
#include "glslPatchGregoryBasis.gen.h"
;
static const char *transitionShaderSource =
#include "glslPatchTransition.gen.h"
;
#endif
GLDrawRegistryBase::~GLDrawRegistryBase() {}
@ -93,12 +90,10 @@ GLDrawRegistryBase::_CreateDrawSourceConfig(
sconfig->vertexShader.source = bsplineShaderSource;
sconfig->vertexShader.version = "#version 410\n";
sconfig->vertexShader.AddDefine("OSD_PATCH_VERTEX_BSPLINE_SHADER");
sconfig->tessControlShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->tessControlShader.source = bsplineShaderSource;
sconfig->tessControlShader.version = "#version 410\n";
sconfig->tessControlShader.AddDefine("OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER");
sconfig->tessEvalShader.source =
std::string(transitionShaderSource) + bsplineShaderSource;
sconfig->tessEvalShader.source = bsplineShaderSource;
sconfig->tessEvalShader.version = "#version 410\n";
sconfig->tessEvalShader.AddDefine("OSD_PATCH_TESS_EVAL_BSPLINE_SHADER");
break;

View File

@ -82,36 +82,9 @@ out block {
OSD_USER_VARYING_DECLARE
} outpt[];
#define ID gl_InvocationID
patch out vec4 tessOuterLo, tessOuterHi;
void
reflectBoundaryEdges(inout vec3 cpt[16], int patchParam)
{
if (((patchParam >> 4) & 1) != 0) {
cpt[0] = 2*cpt[4] - cpt[8];
cpt[1] = 2*cpt[5] - cpt[9];
cpt[2] = 2*cpt[6] - cpt[10];
cpt[3] = 2*cpt[7] - cpt[11];
}
if (((patchParam >> 4) & 2) != 0) {
cpt[3] = 2*cpt[2] - cpt[1];
cpt[7] = 2*cpt[6] - cpt[5];
cpt[11] = 2*cpt[10] - cpt[9];
cpt[15] = 2*cpt[14] - cpt[13];
}
if (((patchParam >> 4) & 4) != 0) {
cpt[12] = 2*cpt[8] - cpt[4];
cpt[13] = 2*cpt[9] - cpt[5];
cpt[14] = 2*cpt[10] - cpt[6];
cpt[15] = 2*cpt[11] - cpt[7];
}
if (((patchParam >> 4) & 8) != 0) {
cpt[0] = 2*cpt[1] - cpt[2];
cpt[4] = 2*cpt[5] - cpt[6];
cpt[8] = 2*cpt[9] - cpt[10];
cpt[12] = 2*cpt[13] - cpt[14];
}
}
#define ID gl_InvocationID
// compute single-crease patch matrix
mat4
@ -143,9 +116,9 @@ void main()
position[i] = inpt[i].v.position.xyz;
}
int patchParam = GetPatchParam();
ivec3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(gl_PrimitiveID));
reflectBoundaryEdges(position, patchParam);
OsdComputeBSplineBoundaryPoints(position, patchParam);
vec3 H[4];
for (int l=0; l<4; ++l) {
@ -156,7 +129,7 @@ void main()
}
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness = GetSharpness();
float sharpness = OsdGetPatchSharpness(patchParam);
if (sharpness > 0) {
float Sf = floor(sharpness);
float Sc = ceil(sharpness);
@ -200,14 +173,7 @@ void main()
OSD_USER_VARYING_PER_CONTROL_POINT(ID, ID);
int patchLevel = GetPatchLevel();
// +0.5 to avoid interpolation error of integer value
outpt[ID].v.patchCoord = vec4(0, 0,
patchLevel+0.5,
GetPrimitiveID()+0.5);
OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER;
outpt[ID].v.patchCoord = OsdGetPatchCoord(patchParam);
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
// Wait for all basis conversion to be finished
@ -216,26 +182,27 @@ void main()
if (ID == 0) {
OSD_PATCH_CULL(OSD_PATCH_INPUT_SIZE);
vec4 outerLevel = vec4(0);
vec2 innerLevel = vec2(0);
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
// Gather bezier control points to compute limit surface tess levels
vec3 cpBezier[16];
for (int i=0; i<16; ++i) {
cpBezier[i] = outpt[i].v.position.xyz;
position[i] = outpt[i].v.position.xyz;
}
GetTransitionTessLevels(cpBezier, patchParam, outerLevel, innerLevel);
#else
GetTransitionTessLevels(position, patchParam, outerLevel, innerLevel);
#endif
gl_TessLevelOuter[0] = outerLevel[0];
gl_TessLevelOuter[1] = outerLevel[1];
gl_TessLevelOuter[2] = outerLevel[2];
gl_TessLevelOuter[3] = outerLevel[3];
vec4 tessLevelOuter = vec4(0);
vec2 tessLevelInner = vec2(0);
gl_TessLevelInner[0] = innerLevel[0];
gl_TessLevelInner[1] = innerLevel[1];
OsdGetTessLevels(position, patchParam,
tessLevelOuter, tessLevelInner,
tessOuterLo, tessOuterHi);
gl_TessLevelOuter[0] = tessLevelOuter[0];
gl_TessLevelOuter[1] = tessLevelOuter[1];
gl_TessLevelOuter[2] = tessLevelOuter[2];
gl_TessLevelOuter[3] = tessLevelOuter[3];
gl_TessLevelInner[0] = tessLevelInner[0];
gl_TessLevelInner[1] = tessLevelInner[1];
}
}
@ -246,19 +213,13 @@ void main()
//----------------------------------------------------------
#ifdef OSD_PATCH_TESS_EVAL_BSPLINE_SHADER
#ifdef OSD_TRANSITION_TRIANGLE_SUBPATCH
layout(triangles) in;
#else
layout(quads) in;
#endif
layout(quads) in;
/* XXXdyu-patch-drawing support for frational spacing
#if defined OSD_FRACTIONAL_ODD_SPACING
layout(fractional_odd_spacing) in;
#elif defined OSD_FRACTIONAL_EVEN_SPACING
layout(fractional_even_spacing) in;
#endif
*/
in block {
ControlVertex v;
@ -278,9 +239,13 @@ out block {
OSD_USER_VARYING_DECLARE
} outpt;
patch in vec4 tessOuterLo, tessOuterHi;
void main()
{
vec2 UV = GetTransitionParameterization();
vec2 UV = OsdGetTessParameterization(gl_TessCoord.xy,
tessOuterLo,
tessOuterHi);
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
float B[4], D[4], C[4];
@ -372,7 +337,7 @@ void main()
dUV += D[k] * DUCP[k];
}
int level = int(inpt[0].v.ptexInfo.z);
int level = inpt[0].v.patchCoord.z;
Tangent *= 3 * level;
BiTangent *= 3 * level;
dUU *= 6 * level;
@ -407,7 +372,7 @@ void main()
Tangent += B[k] * DUCP[k];
BiTangent += D[k] * BUCP[k];
}
int level = int(inpt[0].v.ptexInfo.z);
int level = inpt[0].v.patchCoord.z;
Tangent *= 3 * level;
BiTangent *= 3 * level;
@ -422,11 +387,8 @@ void main()
OSD_USER_VARYING_PER_EVAL_POINT(UV, 5, 6, 9, 10);
outpt.v.patchCoord = inpt[0].v.patchCoord;
outpt.v.patchCoord.xy = vec2(UV.x, UV.y);
OSD_COMPUTE_PTEX_COORD_TESSEVAL_SHADER;
outpt.v.tessCoord = UV;
outpt.v.patchCoord = OsdInterpolatePatchCoord(UV, inpt[0].v.patchCoord);
OSD_DISPLACEMENT_CALLBACK;

View File

@ -71,17 +71,11 @@
// mix(input[c].var, input[d].var, UV.x), UV.y)
#endif
#ifndef OSD_TRANSITION_ROTATE
#define OSD_TRANSITION_ROTATE 0
#endif
// XXXdyu-patch-drawing support for fractional spacing
#undef OSD_FRACTIONAL_ODD_SPACING
#undef OSD_FRACTIONAL_EVEN_SPACING
#if defined OSD_PATCH_BOUNDARY
#define OSD_PATCH_INPUT_SIZE 12
#elif defined OSD_PATCH_CORNER
#define OSD_PATCH_INPUT_SIZE 9
#else
#define OSD_PATCH_INPUT_SIZE 16
#endif
#define OSD_PATCH_INPUT_SIZE 16
#define M_PI 3.14159265359f
@ -91,8 +85,7 @@
struct ControlVertex {
vec4 position;
centroid vec4 patchCoord; // u, v, level, faceID
ivec4 ptexInfo; // U offset, V offset, 2^ptexlevel', rotation
ivec4 patchCoord; // U offset, V offset, faceLevel, faceId
#ifdef OSD_ENABLE_PATCH_CULL
ivec3 clipFlag;
#endif
@ -101,10 +94,10 @@ struct ControlVertex {
struct OutputVertex {
vec4 position;
vec3 normal;
centroid vec4 patchCoord; // u, v, level, faceID
centroid vec2 tessCoord; // tesscoord.st
vec3 tangent;
vec3 bitangent;
centroid vec4 patchCoord; // u, v, faceLevel, faceId
centroid vec2 tessCoord; // tesscoord.st
#if defined OSD_COMPUTE_NORMAL_DERIVATIVES
vec3 Nu;
vec3 Nv;
@ -131,8 +124,7 @@ struct GregEvalVertex {
vec3 Em;
vec3 Fp;
vec3 Fm;
centroid vec4 patchCoord;
ivec4 ptexInfo;
ivec4 patchCoord;
};
// osd shaders need following functions defined
@ -144,74 +136,93 @@ int OsdGregoryQuadOffsetBase();
int OsdPrimitiveIdBase();
int OsdBaseVertex();
float GetTessLevel(int patchLevel)
{
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
return OsdTessLevel();
#else
return OsdTessLevel() / pow(2, patchLevel-1);
#endif
}
#ifndef GetPrimitiveID
#define GetPrimitiveID() (gl_PrimitiveID + OsdPrimitiveIdBase())
#endif
float GetPostProjectionSphereExtent(vec3 center, float diameter)
{
vec4 p = OsdProjectionMatrix() * vec4(center, 1.0);
return abs(diameter * OsdProjectionMatrix()[1][1] / p.w);
}
float TessAdaptive(vec3 p0, vec3 p1)
{
// Adaptive factor can be any computation that depends only on arg values.
// Project the diameter of the edge's bounding sphere instead of using the
// length of the projected edge itself to avoid problems near silhouettes.
vec3 center = (p0 + p1) / 2.0;
float diameter = distance(p0, p1);
return round(max(1.0, OsdTessLevel() * GetPostProjectionSphereExtent(center, diameter)));
}
#ifndef OSD_DISPLACEMENT_CALLBACK
#define OSD_DISPLACEMENT_CALLBACK
#endif
// ----------------------------------------------------------------------------
// ptex coordinates
// Patch Parameters
// ----------------------------------------------------------------------------
//
// Each patch has a corresponding patchParam. This is a set of three values
// specifying additional information about the patch:
//
// faceId -- topological face identifier (e.g. Ptex FaceId)
// bitfield -- refinement-level, non-quad, boundary, transition, uv-offset
// sharpness -- crease sharpness for single-crease patches
//
// These are stored in OsdPatchParamBuffer indexed by the value returned
// from OsdGetPatchIndex() which is a function of the current PrimitiveID
// along with an optional client provided offset.
//
uniform isamplerBuffer OsdPatchParamBuffer;
#define GetPatchParam() \
(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).y)
int OsdGetPatchIndex(int primitiveId)
{
return (primitiveId + OsdPrimitiveIdBase());
}
#define GetPatchLevel() \
(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).y & 0xf)
ivec3 OsdGetPatchParam(int patchIndex)
{
return texelFetch(OsdPatchParamBuffer, patchIndex).xyz;
}
#define GetSharpness() \
(intBitsToFloat(texelFetch(OsdPatchParamBuffer, GetPrimitiveID()).z))
int OsdGetPatchFaceId(ivec3 patchParam)
{
return patchParam.x;
}
#define OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER \
{ \
ivec2 ptexIndex = texelFetch(OsdPatchParamBuffer, \
GetPrimitiveID()).xy; \
int faceID = ptexIndex.x; \
int lv = 1 << ((ptexIndex.y & 0x7) - ((ptexIndex.y >> 3) & 1)); \
int u = (ptexIndex.y >> 22) & 0x3ff; \
int v = (ptexIndex.y >> 12) & 0x3ff; \
outpt[ID].v.patchCoord.w = faceID+0.5; \
outpt[ID].v.ptexInfo = ivec4(u, v, lv, 0); \
}
int OsdGetPatchFaceLevel(ivec3 patchParam)
{
return (1 << ((patchParam.y & 0x7) - ((patchParam.y >> 3) & 1)));
}
#define OSD_COMPUTE_PTEX_COORD_TESSEVAL_SHADER \
{ \
vec2 uv = outpt.v.patchCoord.xy; \
ivec2 p = inpt[0].v.ptexInfo.xy; \
int lv = inpt[0].v.ptexInfo.z; \
outpt.v.tessCoord.xy = uv; \
outpt.v.patchCoord.xy = (uv * vec2(1.0)/lv) + vec2(p.x, p.y)/lv;\
}
int OsdGetPatchRefinementLevel(ivec3 patchParam)
{
return (patchParam.y & 0x7);
}
int OsdGetPatchBoundaryMask(ivec3 patchParam)
{
return ((patchParam.y >> 4) & 0xf);
}
int OsdGetPatchTransitionMask(ivec3 patchParam)
{
return ((patchParam.y >> 8) & 0xf);
}
ivec2 OsdGetPatchFaceUV(ivec3 patchParam)
{
int u = (patchParam.y >> 22) & 0x3ff;
int v = (patchParam.y >> 12) & 0x3ff;
return ivec2(u,v);
}
float OsdGetPatchSharpness(ivec3 patchParam)
{
return intBitsToFloat(patchParam.z);
}
ivec4 OsdGetPatchCoord(ivec3 patchParam)
{
int faceId = OsdGetPatchFaceId(patchParam);
int faceLevel = OsdGetPatchFaceLevel(patchParam);
ivec2 faceUV = OsdGetPatchFaceUV(patchParam);
return ivec4(faceUV.x, faceUV.y, faceLevel, faceId);
}
vec4 OsdInterpolatePatchCoord(vec2 localUV, ivec4 perPrimPatchCoord)
{
int faceId = perPrimPatchCoord.w;
int faceLevel = perPrimPatchCoord.z;
vec2 faceUV = vec2(perPrimPatchCoord.x, perPrimPatchCoord.y);
vec2 uv = localUV/faceLevel + faceUV/faceLevel;
// add 0.5 to integer values for more robust interpolation
return vec4(uv.x, uv.y, faceLevel+0.5f, faceId+0.5f);
}
// ----------------------------------------------------------------------------
// face varyings
@ -229,7 +240,7 @@ uniform samplerBuffer OsdFVarDataBuffer;
#define OSD_COMPUTE_FACE_VARYING_1(result, fvarOffset, tessCoord) \
{ \
float v[4]; \
int primOffset = GetPrimitiveID() * 4; \
int primOffset = OsdGetPatchIndex(gl_PrimitiveID) * 4; \
for (int i = 0; i < 4; ++i) { \
int index = (primOffset+i)*OSD_FVAR_WIDTH + fvarOffset; \
v[i] = texelFetch(OsdFVarDataBuffer, index).s \
@ -242,7 +253,7 @@ uniform samplerBuffer OsdFVarDataBuffer;
#define OSD_COMPUTE_FACE_VARYING_2(result, fvarOffset, tessCoord) \
{ \
vec2 v[4]; \
int primOffset = GetPrimitiveID() * 4; \
int primOffset = OsdGetPatchIndex(gl_PrimitiveID) * 4; \
for (int i = 0; i < 4; ++i) { \
int index = (primOffset+i)*OSD_FVAR_WIDTH + fvarOffset; \
v[i] = vec2(texelFetch(OsdFVarDataBuffer, index).s, \
@ -256,7 +267,7 @@ uniform samplerBuffer OsdFVarDataBuffer;
#define OSD_COMPUTE_FACE_VARYING_3(result, fvarOffset, tessCoord) \
{ \
vec3 v[4]; \
int primOffset = GetPrimitiveID() * 4; \
int primOffset = OsdGetPatchIndex(gl_PrimitiveID) * 4; \
for (int i = 0; i < 4; ++i) { \
int index = (primOffset+i)*OSD_FVAR_WIDTH + fvarOffset; \
v[i] = vec3(texelFetch(OsdFVarDataBuffer, index).s, \
@ -271,7 +282,7 @@ uniform samplerBuffer OsdFVarDataBuffer;
#define OSD_COMPUTE_FACE_VARYING_4(result, fvarOffset, tessCoord) \
{ \
vec4 v[4]; \
int primOffset = GetPrimitiveID() * 4; \
int primOffset = OsdGetPatchIndex(gl_PrimitiveID) * 4; \
for (int i = 0; i < 4; ++i) { \
int index = (primOffset+i)*OSD_FVAR_WIDTH + fvarOffset; \
v[i] = vec4(texelFetch(OsdFVarDataBuffer, index).s, \
@ -289,14 +300,14 @@ uniform samplerBuffer OsdFVarDataBuffer;
#define OSD_COMPUTE_FACE_VARYING_TRI_1(result, fvarOffset, triVert) \
{ \
int primOffset = GetPrimitiveID() * 3; \
int primOffset = OsdGetPatchIndex(gl_PrimitiveID) * 3; \
int index = (primOffset+triVert)*OSD_FVAR_WIDTH + fvarOffset; \
result = texelFetch(OsdFVarDataBuffer, index).s; \
}
#define OSD_COMPUTE_FACE_VARYING_TRI_2(result, fvarOffset, triVert) \
{ \
int primOffset = GetPrimitiveID() * 3; \
int primOffset = OsdGetPatchIndex(gl_PrimitiveID) * 3; \
int index = (primOffset+triVert)*OSD_FVAR_WIDTH + fvarOffset; \
result = vec2(texelFetch(OsdFVarDataBuffer, index).s, \
texelFetch(OsdFVarDataBuffer, index + 1).s); \
@ -304,7 +315,7 @@ uniform samplerBuffer OsdFVarDataBuffer;
#define OSD_COMPUTE_FACE_VARYING_TRI_3(result, fvarOffset, triVert) \
{ \
int primOffset = GetPrimitiveID() * 3; \
int primOffset = OsdGetPatchIndex(gl_PrimitiveID) * 3; \
int index = (primOffset+triVert)*OSD_FVAR_WIDTH + fvarOffset; \
result = vec3(texelFetch(OsdFVarDataBuffer, index).s, \
texelFetch(OsdFVarDataBuffer, index + 1).s, \
@ -313,7 +324,7 @@ uniform samplerBuffer OsdFVarDataBuffer;
#define OSD_COMPUTE_FACE_VARYING_TRI_4(result, fvarOffset, triVert) \
{ \
int primOffset = GetPrimitiveID() * 3; \
int primOffset = OsdGetPatchIndex(gl_PrimitiveID) * 3; \
int index = (primOffset+triVert)*OSD_FVAR_WIDTH + fvarOffset; \
result = vec4(texelFetch(OsdFVarDataBuffer, index).s, \
texelFetch(OsdFVarDataBuffer, index + 1).s, \
@ -409,7 +420,7 @@ Univar4x4(in float u, out float B[4], out float D[4], out float C[4])
// ----------------------------------------------------------------------------
vec3
EvalBezier(vec3 cp[16], vec2 uv)
OsdEvalBezier(vec3 cp[16], vec2 uv)
{
vec3 BUCP[4] = vec3[4](vec3(0,0,0), vec3(0,0,0), vec3(0,0,0), vec3(0,0,0));
@ -434,3 +445,304 @@ EvalBezier(vec3 cp[16], vec2 uv)
}
// ----------------------------------------------------------------------------
// Boundary Interpolation
// ----------------------------------------------------------------------------
void
OsdComputeBSplineBoundaryPoints(inout vec3 cpt[16], ivec3 patchParam)
{
int boundaryMask = OsdGetPatchBoundaryMask(patchParam);
if ((boundaryMask & 1) != 0) {
cpt[0] = 2*cpt[4] - cpt[8];
cpt[1] = 2*cpt[5] - cpt[9];
cpt[2] = 2*cpt[6] - cpt[10];
cpt[3] = 2*cpt[7] - cpt[11];
}
if ((boundaryMask & 2) != 0) {
cpt[3] = 2*cpt[2] - cpt[1];
cpt[7] = 2*cpt[6] - cpt[5];
cpt[11] = 2*cpt[10] - cpt[9];
cpt[15] = 2*cpt[14] - cpt[13];
}
if ((boundaryMask & 4) != 0) {
cpt[12] = 2*cpt[8] - cpt[4];
cpt[13] = 2*cpt[9] - cpt[5];
cpt[14] = 2*cpt[10] - cpt[6];
cpt[15] = 2*cpt[11] - cpt[7];
}
if ((boundaryMask & 8) != 0) {
cpt[0] = 2*cpt[1] - cpt[2];
cpt[4] = 2*cpt[5] - cpt[6];
cpt[8] = 2*cpt[9] - cpt[10];
cpt[12] = 2*cpt[13] - cpt[14];
}
}
// ----------------------------------------------------------------------------
// Tessellation
// ----------------------------------------------------------------------------
//
// Organization of B-spline and Bezier control points.
//
// Each patch is defined by 16 control points (labeled 0-15).
//
// The patch will be evaluated across the domain from (0,0) at
// the lower-left to (1,1) at the upper-right. When computing
// adaptive tessellation metrics, we consider refined vertex-vertex
// and edge-vertex points along the transition edges of the patch
// (labeled vv* and ev* respectively).
//
// The two segments of each transition edge are labeled Lo and Hi,
// with the Lo segment occuring before the Hi segment along the
// transition edge's domain parameterization. These Lo and Hi segment
// tessellation levels determine how domain evaluation coordinates
// are remapped along transition edges. The Hi segment value will
// be zero for a non-transition edge.
//
// (0,1) (1,1)
//
// vv3 ev23 vv2
// | Lo3 | Hi3 |
// --O-----------O-----+-----O-----------O--
// | 12 | 13 14 | 15 |
// | | | |
// | | | |
// Hi0 | | | | Hi2
// | | | |
// O-----------O-----------O-----------O
// | 8 | 9 10 | 11 |
// | | | |
// ev03 --+ | | +-- ev12
// | | | |
// | 4 | 5 6 | 7 |
// O-----------O-----------O-----------O
// | | | |
// Lo0 | | | | Lo2
// | | | |
// | | | |
// | 0 | 1 2 | 3 |
// --O-----------O-----+-----O-----------O--
// | Lo1 | Hi1 |
// vv0 ev01 vv1
//
// (0,0) (1,0)
//
float OsdComputePostProjectionSphereExtent(vec3 center, float diameter)
{
vec4 p = OsdProjectionMatrix() * vec4(center, 1.0);
return abs(diameter * OsdProjectionMatrix()[1][1] / p.w);
}
float OsdComputeTessLevel(vec3 p0, vec3 p1)
{
// Adaptive factor can be any computation that depends only on arg values.
// Project the diameter of the edge's bounding sphere instead of using the
// length of the projected edge itself to avoid problems near silhouettes.
vec3 center = (p0 + p1) / 2.0;
float diameter = distance(p0, p1);
float projLength = OsdComputePostProjectionSphereExtent(center, diameter);
return round(max(1.0, OsdTessLevel() * projLength));
}
void
OsdGetTessLevelsUniform(ivec3 patchParam,
inout vec4 tessOuterLo, inout vec4 tessOuterHi)
{
int refinementLevel = OsdGetPatchRefinementLevel(patchParam);
float tessLevel = OsdTessLevel() / pow(2, refinementLevel-1);
tessOuterLo = vec4(tessLevel);
tessOuterHi = vec4(0);
}
void
OsdGetTessLevelsRefinedPoints(vec3 cp[16], ivec3 patchParam,
inout vec4 tessOuterLo, inout vec4 tessOuterHi)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. We compute the corresponding
// vertex-vertex and edge-vertex refined points along the edges of the
// patch using Catmull-Clark subdivision stencil weights.
// For simplicity, we let the optimizer discard unused computation.
vec3 vv0 = (cp[0] + cp[2] + cp[8] + cp[10]) * 0.015625 +
(cp[1] + cp[4] + cp[6] + cp[9]) * 0.09375 + cp[5] * 0.5625;
vec3 ev01 = (cp[1] + cp[2] + cp[9] + cp[10]) * 0.0625 +
(cp[5] + cp[6]) * 0.375;
vec3 vv1 = (cp[1] + cp[3] + cp[9] + cp[11]) * 0.015625 +
(cp[2] + cp[5] + cp[7] + cp[10]) * 0.09375 + cp[6] * 0.5625;
vec3 ev12 = (cp[5] + cp[7] + cp[9] + cp[11]) * 0.0625 +
(cp[6] + cp[10]) * 0.375;
vec3 vv2 = (cp[5] + cp[7] + cp[13] + cp[15]) * 0.015625 +
(cp[6] + cp[9] + cp[11] + cp[14]) * 0.09375 + cp[10] * 0.5625;
vec3 ev23 = (cp[5] + cp[6] + cp[13] + cp[14]) * 0.0625 +
(cp[9] + cp[10]) * 0.375;
vec3 vv3 = (cp[4] + cp[6] + cp[12] + cp[14]) * 0.015625 +
(cp[5] + cp[8] + cp[10] + cp[13]) * 0.09375 + cp[9] * 0.5625;
vec3 ev03 = (cp[4] + cp[6] + cp[8] + cp[10]) * 0.0625 +
(cp[5] + cp[9]) * 0.375;
tessOuterLo = vec4(0);
tessOuterHi = vec4(0);
int transitionMask = OsdGetPatchTransitionMask(patchParam);
if ((transitionMask & 8) != 0) {
tessOuterLo[0] = OsdComputeTessLevel(vv0, ev03);
tessOuterHi[0] = OsdComputeTessLevel(vv3, ev03);
} else {
tessOuterLo[0] = OsdComputeTessLevel(cp[5], cp[9]);
}
if ((transitionMask & 1) != 0) {
tessOuterLo[1] = OsdComputeTessLevel(vv0, ev01);
tessOuterHi[1] = OsdComputeTessLevel(vv1, ev01);
} else {
tessOuterLo[1] = OsdComputeTessLevel(cp[5], cp[6]);
}
if ((transitionMask & 2) != 0) {
tessOuterLo[2] = OsdComputeTessLevel(vv1, ev12);
tessOuterHi[2] = OsdComputeTessLevel(vv2, ev12);
} else {
tessOuterLo[2] = OsdComputeTessLevel(cp[6], cp[10]);
}
if ((transitionMask & 4) != 0) {
tessOuterLo[3] = OsdComputeTessLevel(vv3, ev23);
tessOuterHi[3] = OsdComputeTessLevel(vv2, ev23);
} else {
tessOuterLo[3] = OsdComputeTessLevel(cp[9], cp[10]);
}
}
void
OsdGetTessLevelsLimitPoints(vec3 cpBezier[16], ivec3 patchParam,
inout vec4 tessOuterLo, inout vec4 tessOuterHi)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. When the patch control
// points have been converted to the Bezier basis, the control points
// at the four corners are on the limit surface (since a Bezier patch
// interpolates its corner control points). We can compute an adaptive
// tessellation level for transition edges on the limit surface by
// evaluating a limit position at the mid point of each transition edge.
tessOuterLo = vec4(0);
tessOuterHi = vec4(0);
int transitionMask = OsdGetPatchTransitionMask(patchParam);
if ((transitionMask & 8) != 0) {
vec3 ev03 = OsdEvalBezier(cpBezier, vec2(0.0, 0.5));
tessOuterLo[0] = OsdComputeTessLevel(cpBezier[0], ev03);
tessOuterHi[0] = OsdComputeTessLevel(cpBezier[12], ev03);
} else {
tessOuterLo[0] = OsdComputeTessLevel(cpBezier[0], cpBezier[12]);
}
if ((transitionMask & 1) != 0) {
vec3 ev01 = OsdEvalBezier(cpBezier, vec2(0.5, 0.0));
tessOuterLo[1] = OsdComputeTessLevel(cpBezier[0], ev01);
tessOuterHi[1] = OsdComputeTessLevel(cpBezier[3], ev01);
} else {
tessOuterLo[1] = OsdComputeTessLevel(cpBezier[0], cpBezier[3]);
}
if ((transitionMask & 2) != 0) {
vec3 ev12 = OsdEvalBezier(cpBezier, vec2(1.0, 0.5));
tessOuterLo[2] = OsdComputeTessLevel(cpBezier[3], ev12);
tessOuterHi[2] = OsdComputeTessLevel(cpBezier[15], ev12);
} else {
tessOuterLo[2] = OsdComputeTessLevel(cpBezier[3], cpBezier[15]);
}
if ((transitionMask & 4) != 0) {
vec3 ev23 = OsdEvalBezier(cpBezier, vec2(0.5, 1.0));
tessOuterLo[3] = OsdComputeTessLevel(cpBezier[12], ev23);
tessOuterHi[3] = OsdComputeTessLevel(cpBezier[15], ev23);
} else {
tessOuterLo[3] = OsdComputeTessLevel(cpBezier[12], cpBezier[15]);
}
}
void
OsdGetTessLevels(vec3 cp[16], ivec3 patchParam,
inout vec4 tessLevelOuter, inout vec2 tessLevelInner,
inout vec4 tessOuterLo, inout vec4 tessOuterHi)
{
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
OsdGetTessLevelsLimitPoints(cp, patchParam, tessOuterLo, tessOuterHi);
#elif defined OSD_ENABLE_SCREENSPACE_TESSELLATION_REFINED
OsdGetTessLevelsRefinedPoints(cp, patchParam, tessOuterLo, tessOuterHi);
#else
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;
}
void
OsdGetTessLevels(vec3 cp0, vec3 cp1, vec3 cp2, vec3 cp3,
ivec3 patchParam,
inout vec4 tessLevelOuter, inout vec2 tessLevelInner)
{
vec4 tessOuterLo = vec4(0);
vec4 tessOuterHi = vec4(0);
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
tessOuterLo[0] = OsdComputeTessLevel(cp0, cp1);
tessOuterLo[1] = OsdComputeTessLevel(cp0, cp3);
tessOuterLo[2] = OsdComputeTessLevel(cp2, cp3);
tessOuterLo[3] = OsdComputeTessLevel(cp1, cp2);
tessOuterHi = vec4(0);
#else
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;
}
float
OsdGetTessTransitionSplit(float t, float n0, float n1)
{
float ti = round(t * (n0 + n1));
if (ti <= n0) {
return 0.5 * (ti / n0);
} else {
return 0.5 * ((ti - n0) / n1) + 0.5;
}
}
vec2
OsdGetTessParameterization(vec2 uv, vec4 tessOuterLo, vec4 tessOuterHi)
{
vec2 UV = uv;
if (UV.x == 0 && tessOuterHi[0] > 0) {
UV.y = OsdGetTessTransitionSplit(UV.y, tessOuterLo[0], tessOuterHi[0]);
} else
if (UV.y == 0 && tessOuterHi[1] > 0) {
UV.x = OsdGetTessTransitionSplit(UV.x, tessOuterLo[1], tessOuterHi[1]);
} else
if (UV.x == 1 && tessOuterHi[2] > 0) {
UV.y = OsdGetTessTransitionSplit(UV.y, tessOuterLo[2], tessOuterHi[2]);
} else
if (UV.y == 1 && tessOuterHi[3] > 0) {
UV.x = OsdGetTessTransitionSplit(UV.x, tessOuterLo[3], tessOuterHi[3]);
}
return UV;
}

View File

@ -397,37 +397,28 @@ void main()
OSD_USER_VARYING_PER_CONTROL_POINT(ID, ID);
int patchLevel = GetPatchLevel();
outpt[ID].v.patchCoord = vec4(0, 0,
patchLevel+0.5f,
GetPrimitiveID()+0.5f);
ivec3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(gl_PrimitiveID));
OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER;
outpt[ID].v.patchCoord = OsdGetPatchCoord(patchParam);
if (ID == 0) {
OSD_PATCH_CULL(4);
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
gl_TessLevelOuter[0] =
TessAdaptive(inpt[0].v.hullPosition.xyz, inpt[1].v.hullPosition.xyz);
gl_TessLevelOuter[1] =
TessAdaptive(inpt[0].v.hullPosition.xyz, inpt[3].v.hullPosition.xyz);
gl_TessLevelOuter[2] =
TessAdaptive(inpt[2].v.hullPosition.xyz, inpt[3].v.hullPosition.xyz);
gl_TessLevelOuter[3] =
TessAdaptive(inpt[1].v.hullPosition.xyz, inpt[2].v.hullPosition.xyz);
gl_TessLevelInner[0] =
max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] =
max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#else
gl_TessLevelInner[0] = GetTessLevel(patchLevel);
gl_TessLevelInner[1] = GetTessLevel(patchLevel);
gl_TessLevelOuter[0] = GetTessLevel(patchLevel);
gl_TessLevelOuter[1] = GetTessLevel(patchLevel);
gl_TessLevelOuter[2] = GetTessLevel(patchLevel);
gl_TessLevelOuter[3] = GetTessLevel(patchLevel);
#endif
vec4 tessLevelOuter = vec4(0);
vec2 tessLevelInner = vec2(0);
OsdGetTessLevels(
inpt[0].v.hullPosition.xyz, inpt[1].v.hullPosition.xyz,
inpt[2].v.hullPosition.xyz, inpt[3].v.hullPosition.xyz,
patchParam, tessLevelOuter, tessLevelInner);
gl_TessLevelOuter[0] = tessLevelOuter[0];
gl_TessLevelOuter[1] = tessLevelOuter[1];
gl_TessLevelOuter[2] = tessLevelOuter[2];
gl_TessLevelOuter[3] = tessLevelOuter[3];
gl_TessLevelInner[0] = tessLevelInner[0];
gl_TessLevelInner[1] = tessLevelInner[1];
}
}
@ -441,13 +432,11 @@ void main()
layout(quads) in;
layout(cw) in;
/* XXXdyu-patch-drawing support for frational spacing
#if defined OSD_FRACTIONAL_ODD_SPACING
layout(fractional_odd_spacing) in;
#elif defined OSD_FRACTIONAL_EVEN_SPACING
layout(fractional_even_spacing) in;
#endif
*/
in block {
GregEvalVertex v;
@ -554,7 +543,7 @@ void main()
dUV += D[i] * DUCP[i];
}
int level = int(inpt[0].v.ptexInfo.z);
int level = inpt[0].v.patchCoord.z;
BiTangent *= 3 * level;
Tangent *= 3 * level;
dUU *= 6 * level;
@ -609,7 +598,7 @@ void main()
Tangent += B[i] * DUCP[i];
BiTangent += D[i] * BUCP[i];
}
int level = int(inpt[0].v.ptexInfo.z);
int level = inpt[0].v.patchCoord.z;
BiTangent *= 3 * level;
Tangent *= 3 * level;
@ -627,10 +616,9 @@ void main()
OSD_USER_VARYING_PER_EVAL_POINT(vec2(u,v), 0, 3, 1, 2);
outpt.v.patchCoord = inpt[0].v.patchCoord;
outpt.v.patchCoord.xy = vec2(v, u);
OSD_COMPUTE_PTEX_COORD_TESSEVAL_SHADER;
vec2 UV = vec2(v, u);
outpt.v.tessCoord = UV;
outpt.v.patchCoord = OsdInterpolatePatchCoord(UV, inpt[0].v.patchCoord);
OSD_DISPLACEMENT_CALLBACK;

View File

@ -38,8 +38,7 @@ out block {
void main()
{
outpt.v.position = OsdModelViewMatrix() * position;
outpt.v.patchCoord = vec4(0);
outpt.v.ptexInfo = ivec4(0);
outpt.v.patchCoord = ivec4(0);
OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(position);
OSD_USER_VARYING_PER_VERTEX();
}
@ -70,42 +69,27 @@ void main()
outpt[ID].v = inpt[ID].v;
OSD_USER_VARYING_PER_CONTROL_POINT(ID, ID);
int patchLevel = GetPatchLevel();
ivec3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(gl_PrimitiveID));
// +0.5 to avoid interpolation error of integer value
outpt[ID].v.patchCoord = vec4(0, 0,
patchLevel+0.5,
GetPrimitiveID()+0.5);
OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER;
outpt[ID].v.patchCoord = OsdGetPatchCoord(patchParam);
if (ID == 0) {
OSD_PATCH_CULL(OSD_PATCH_INPUT_SIZE);
// XXX: this metric is not consistent.
// we will 1) compute the cage length as before
// or 2) compute limit length for all patches.
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
gl_TessLevelOuter[0] =
TessAdaptive(inpt[0].v.position.xyz, inpt[5].v.position.xyz);
gl_TessLevelOuter[1] =
TessAdaptive(inpt[0].v.position.xyz, inpt[15].v.position.xyz);
gl_TessLevelOuter[2] =
TessAdaptive(inpt[10].v.position.xyz, inpt[15].v.position.xyz);
gl_TessLevelOuter[3] =
TessAdaptive(inpt[5].v.position.xyz, inpt[10].v.position.xyz);
vec4 tessLevelOuter = vec4(0);
vec2 tessLevelInner = vec2(0);
gl_TessLevelInner[0] =
max(gl_TessLevelOuter[1], gl_TessLevelOuter[3]);
gl_TessLevelInner[1] =
max(gl_TessLevelOuter[0], gl_TessLevelOuter[2]);
#else
gl_TessLevelInner[0] = GetTessLevel(patchLevel);
gl_TessLevelInner[1] = GetTessLevel(patchLevel);
gl_TessLevelOuter[0] = GetTessLevel(patchLevel);
gl_TessLevelOuter[1] = GetTessLevel(patchLevel);
gl_TessLevelOuter[2] = GetTessLevel(patchLevel);
gl_TessLevelOuter[3] = GetTessLevel(patchLevel);
#endif
OsdGetTessLevels(inpt[0].v.position.xyz, inpt[5].v.position.xyz,
inpt[10].v.position.xyz, inpt[15].v.position.xyz,
patchParam, tessLevelOuter, tessLevelInner);
gl_TessLevelOuter[0] = tessLevelOuter[0];
gl_TessLevelOuter[1] = tessLevelOuter[1];
gl_TessLevelOuter[2] = tessLevelOuter[2];
gl_TessLevelOuter[3] = tessLevelOuter[3];
gl_TessLevelInner[0] = tessLevelInner[0];
gl_TessLevelInner[1] = tessLevelInner[1];
}
}
@ -119,13 +103,11 @@ void main()
layout(quads) in;
layout(cw) in;
/* XXXdyu-patch-drawing support for frational spacing
#if defined OSD_FRACTIONAL_ODD_SPACING
layout(fractional_odd_spacing) in;
#elif defined OSD_FRACTIONAL_EVEN_SPACING
layout(fractional_even_spacing) in;
#endif
*/
in block {
ControlVertex v;
@ -218,7 +200,7 @@ void main()
dUV += D[i] * DUCP[i];
}
int level = int(inpt[0].v.ptexInfo.z);
int level = inpt[0].v.patchCoord.z;
BiTangent *= 3 * level;
Tangent *= 3 * level;
dUU *= 6 * level;
@ -268,7 +250,7 @@ void main()
Tangent += B[i] * DUCP[i];
BiTangent += D[i] * BUCP[i];
}
int level = int(inpt[0].v.ptexInfo.z);
int level = inpt[0].v.patchCoord.z;
BiTangent *= 3 * level;
Tangent *= 3 * level;
@ -283,10 +265,9 @@ void main()
//OSD_USER_VARYING_PER_EVAL_POINT(vec2(u,v), 0, 3, 1, 2);
OSD_USER_VARYING_PER_EVAL_POINT(vec2(u,v), 0, 15, 5, 10);
outpt.v.patchCoord = inpt[0].v.patchCoord;
outpt.v.patchCoord.xy = vec2(v, u);
OSD_COMPUTE_PTEX_COORD_TESSEVAL_SHADER;
vec2 UV = vec2(v, u);
outpt.v.tessCoord = UV;
outpt.v.patchCoord = OsdInterpolatePatchCoord(UV, inpt[0].v.patchCoord);
OSD_DISPLACEMENT_CALLBACK;

View File

@ -1,251 +0,0 @@
//
// Copyright 2013 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
//----------------------------------------------------------
// Patches.TessControlTransition
//----------------------------------------------------------
#ifdef OSD_PATCH_TESS_CONTROL_BSPLINE_SHADER
patch out vec4 tessOuterLo, tessOuterHi;
void
GetTessLevelsUniform(vec3 cp[16], int patchParam)
{
float tessAmount = GetTessLevel(GetPatchLevel());
tessOuterLo = vec4(tessAmount);
tessOuterHi = vec4(0);
}
//
// Organization of B-spline and Bezier control points.
//
// Each patch is defined by 16 control points (labeled 0-15).
//
// The patch will be evaluated across the domain from (0,0) at
// the lower-left to (1,1) at the upper-right. When computing
// adaptive tessellation metrics, we consider refined vertex-vertex
// and edge-vertex points along the transition edges of the patch
// (labeled vv* and ev* respectively).
//
// The two segments of each transition edge are labeled Lo and Hi,
// with the Lo segment occuring before the Hi segment along the
// transition edge's domain parameterization. These Lo and Hi segment
// tessellation levels determine how domain evaluation coordinates
// are remapped along transition edges. The Hi segment value will
// be zero for a non-transition edge.
//
// (0,1) (1,1)
//
// vv3 ev23 vv2
// | Lo3 | Hi3 |
// --O-----------O-----+-----O-----------O--
// | 12 | 13 14 | 15 |
// | | | |
// | | | |
// Hi0 | | | | Hi2
// | | | |
// O-----------O-----------O-----------O
// | 8 | 9 10 | 11 |
// | | | |
// ev03 --+ | | +-- ev12
// | | | |
// | 4 | 5 6 | 7 |
// O-----------O-----------O-----------O
// | | | |
// Lo0 | | | | Lo2
// | | | |
// | | | |
// | 0 | 1 2 | 3 |
// --O-----------O-----+-----O-----------O--
// | Lo1 | Hi1 |
// vv0 ev01 vv1
//
// (0,0) (1,0)
//
void
GetTessLevelsRefinedPoints(vec3 cp[16], int patchParam)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. We compute the corresponding
// vertex-vertex and edge-vertex refined points along the edges of the
// patch using Catmull-Clark subdivision stencil weights.
// For simplicity, we let the optimizer discard unused computation.
vec3 vv0 = (cp[0] + cp[2] + cp[8] + cp[10]) * 0.015625 +
(cp[1] + cp[4] + cp[6] + cp[9]) * 0.09375 + cp[5] * 0.5625;
vec3 ev01 = (cp[1] + cp[2] + cp[9] + cp[10]) * 0.0625 +
(cp[5] + cp[6]) * 0.375;
vec3 vv1 = (cp[1] + cp[3] + cp[9] + cp[11]) * 0.015625 +
(cp[2] + cp[5] + cp[7] + cp[10]) * 0.09375 + cp[6] * 0.5625;
vec3 ev12 = (cp[5] + cp[7] + cp[9] + cp[11]) * 0.0625 +
(cp[6] + cp[10]) * 0.375;
vec3 vv2 = (cp[5] + cp[7] + cp[13] + cp[15]) * 0.015625 +
(cp[6] + cp[9] + cp[11] + cp[14]) * 0.09375 + cp[10] * 0.5625;
vec3 ev23 = (cp[5] + cp[6] + cp[13] + cp[14]) * 0.0625 +
(cp[9] + cp[10]) * 0.375;
vec3 vv3 = (cp[4] + cp[6] + cp[12] + cp[14]) * 0.015625 +
(cp[5] + cp[8] + cp[10] + cp[13]) * 0.09375 + cp[9] * 0.5625;
vec3 ev03 = (cp[4] + cp[6] + cp[8] + cp[10]) * 0.0625 +
(cp[5] + cp[9]) * 0.375;
tessOuterLo = vec4(1);
tessOuterHi = vec4(0);
if (((patchParam >> 11) & 1) != 0) {
tessOuterLo[0] = TessAdaptive(vv0, ev03);
tessOuterHi[0] = TessAdaptive(vv3, ev03);
} else {
tessOuterLo[0] = TessAdaptive(cp[5], cp[9]);
}
if (((patchParam >> 8) & 1) != 0) {
tessOuterLo[1] = TessAdaptive(vv0, ev01);
tessOuterHi[1] = TessAdaptive(vv1, ev01);
} else {
tessOuterLo[1] = TessAdaptive(cp[5], cp[6]);
}
if (((patchParam >> 9) & 1) != 0) {
tessOuterLo[2] = TessAdaptive(vv1, ev12);
tessOuterHi[2] = TessAdaptive(vv2, ev12);
} else {
tessOuterLo[2] = TessAdaptive(cp[6], cp[10]);
}
if (((patchParam >> 10) & 1) != 0) {
tessOuterLo[3] = TessAdaptive(vv3, ev23);
tessOuterHi[3] = TessAdaptive(vv2, ev23);
} else {
tessOuterLo[3] = TessAdaptive(cp[9], cp[10]);
}
}
void
GetTessLevelsLimitPoints(vec3 cpBezier[16], int patchParam)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. When the patch control
// points have been converted to the Bezier basis, the control points
// at the four corners are on the limit surface (since a Bezier patch
// interpolates its corner control points). We can compute an adaptive
// tessellation level for transition edges on the limit surface by
// evaluating a limit position at the mid point of each transition edge.
tessOuterLo = vec4(1);
tessOuterHi = vec4(0);
if (((patchParam >> 11) & 1) != 0) {
vec3 ev03 = EvalBezier(cpBezier, vec2(0.0, 0.5));
tessOuterLo[0] = TessAdaptive(cpBezier[0], ev03);
tessOuterHi[0] = TessAdaptive(cpBezier[12], ev03);
} else {
tessOuterLo[0] = TessAdaptive(cpBezier[0], cpBezier[12]);
}
if (((patchParam >> 8) & 1) != 0) {
vec3 ev01 = EvalBezier(cpBezier, vec2(0.5, 0.0));
tessOuterLo[1] = TessAdaptive(cpBezier[0], ev01);
tessOuterHi[1] = TessAdaptive(cpBezier[3], ev01);
} else {
tessOuterLo[1] = TessAdaptive(cpBezier[0], cpBezier[3]);
}
if (((patchParam >> 9) & 1) != 0) {
vec3 ev12 = EvalBezier(cpBezier, vec2(1.0, 0.5));
tessOuterLo[2] = TessAdaptive(cpBezier[3], ev12);
tessOuterHi[2] = TessAdaptive(cpBezier[15], ev12);
} else {
tessOuterLo[2] = TessAdaptive(cpBezier[3], cpBezier[15]);
}
if (((patchParam >> 10) & 1) != 0) {
vec3 ev23 = EvalBezier(cpBezier, vec2(0.5, 1.0));
tessOuterLo[3] = TessAdaptive(cpBezier[12], ev23);
tessOuterHi[3] = TessAdaptive(cpBezier[15], ev23);
} else {
tessOuterLo[3] = TessAdaptive(cpBezier[12], cpBezier[15]);
}
}
void
GetTransitionTessLevels(vec3 cp[16], int patchParam,
inout vec4 outerLevel, inout vec2 innerLevel)
{
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
GetTessLevelsLimitPoints(cp, patchParam);
#elif defined OSD_ENABLE_SCREENSPACE_TESSELLATION_REFINED
GetTessLevelsRefinedPoints(cp, patchParam);
#else
GetTessLevelsUniform(cp, patchParam);
#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.
outerLevel = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
innerLevel[0] = (outerLevel[1] + outerLevel[3]) * 0.5;
innerLevel[1] = (outerLevel[0] + outerLevel[2]) * 0.5;
}
#endif
//----------------------------------------------------------
// Patches.TessEvalTransition
//----------------------------------------------------------
#ifdef OSD_PATCH_TESS_EVAL_BSPLINE_SHADER
patch in vec4 tessOuterLo, tessOuterHi;
float
GetTransitionSplit(float t, float n0, float n1)
{
float ti = round(t * (n0 + n1));
if (ti <= n0) {
return 0.5 * (ti / n0);
} else {
return 0.5 * ((ti - n0) / n1) + 0.5;
}
}
vec2
GetTransitionParameterization()
{
vec2 UV = gl_TessCoord.xy;
if (UV.x == 0 && tessOuterHi[0] > 0) {
UV.y = GetTransitionSplit(UV.y, tessOuterLo[0], tessOuterHi[0]);
} else
if (UV.y == 0 && tessOuterHi[1] > 0) {
UV.x = GetTransitionSplit(UV.x, tessOuterLo[1], tessOuterHi[1]);
} else
if (UV.x == 1 && tessOuterHi[2] > 0) {
UV.y = GetTransitionSplit(UV.y, tessOuterLo[2], tessOuterHi[2]);
} else
if (UV.y == 1 && tessOuterHi[3] > 0) {
UV.x = GetTransitionSplit(UV.x, tessOuterLo[3], tessOuterHi[3]);
}
return UV;
}
#endif

View File

@ -61,35 +61,6 @@ static float4x4 Mi = {
0.f, 0.f, 1.f, 0.f
};
void
reflectBoundaryEdges(inout float3 cpt[16], int patchParam)
{
if (((patchParam >> 4) & 1) != 0) {
cpt[0] = 2*cpt[4] - cpt[8];
cpt[1] = 2*cpt[5] - cpt[9];
cpt[2] = 2*cpt[6] - cpt[10];
cpt[3] = 2*cpt[7] - cpt[11];
}
if (((patchParam >> 4) & 2) != 0) {
cpt[3] = 2*cpt[2] - cpt[1];
cpt[7] = 2*cpt[6] - cpt[5];
cpt[11] = 2*cpt[10] - cpt[9];
cpt[15] = 2*cpt[14] - cpt[13];
}
if (((patchParam >> 4) & 4) != 0) {
cpt[12] = 2*cpt[8] - cpt[4];
cpt[13] = 2*cpt[9] - cpt[5];
cpt[14] = 2*cpt[10] - cpt[6];
cpt[15] = 2*cpt[11] - cpt[7];
}
if (((patchParam >> 4) & 8) != 0) {
cpt[0] = 2*cpt[1] - cpt[2];
cpt[4] = 2*cpt[5] - cpt[6];
cpt[8] = 2*cpt[9] - cpt[10];
cpt[12] = 2*cpt[13] - cpt[14];
}
}
// compute single-crease patch matrix
float4x4
ComputeMatrixSimplified(float sharpness)
@ -118,33 +89,34 @@ HSConstFunc(
uint primitiveID : SV_PrimitiveID)
{
HS_CONSTANT_FUNC_OUT output;
int patchParam = GetPatchParam(primitiveID);
int patchLevel = GetPatchLevel(primitiveID);
float3 position[16];
for (int p=0; p<16; ++p) {
position[p] = bezierPatch[p].position.xyz;
}
reflectBoundaryEdges(position, patchParam);
int3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(primitiveID));
OsdComputeBSplineBoundaryPoints(position, patchParam);
OSD_PATCH_CULL(OSD_PATCH_INPUT_SIZE);
float4 outerLevel = float4(0,0,0,0);
float4 innerLevel = float4(0,0,0,0);
float4 tessLevelOuter = float4(0,0,0,0);
float4 tessLevelInner = float4(0,0,0,0);
float4 tessOuterLo = float4(0,0,0,0);
float4 tessOuterHi = float4(0,0,0,0);
GetTransitionTessLevels(position, patchParam, patchLevel,
outerLevel, innerLevel,
tessOuterLo, tessOuterHi);
output.tessLevelOuter[0] = outerLevel[0];
output.tessLevelOuter[1] = outerLevel[1];
output.tessLevelOuter[2] = outerLevel[2];
output.tessLevelOuter[3] = outerLevel[3];
OsdGetTessLevels(position, patchParam,
tessLevelOuter, tessLevelInner,
tessOuterLo, tessOuterHi);
output.tessLevelInner[0] = innerLevel[0];
output.tessLevelInner[1] = innerLevel[1];
output.tessLevelOuter[0] = tessLevelOuter[0];
output.tessLevelOuter[1] = tessLevelOuter[1];
output.tessLevelOuter[2] = tessLevelOuter[2];
output.tessLevelOuter[3] = tessLevelOuter[3];
output.tessLevelInner[0] = tessLevelInner[0];
output.tessLevelInner[1] = tessLevelInner[1];
output.tessOuterLo = tessOuterLo;
output.tessOuterHi = tessOuterHi;
@ -170,9 +142,9 @@ HullVertex hs_main_patches(
position[p] = patch[p].position.xyz;
}
int patchParam = GetPatchParam(primitiveID);
int3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(primitiveID));
reflectBoundaryEdges(position, patchParam);
OsdComputeBSplineBoundaryPoints(position, patchParam);
float3 H[4];
for (int l=0; l<4; ++l) {
@ -184,7 +156,7 @@ HullVertex hs_main_patches(
HullVertex output;
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
float sharpness = GetSharpness(primitiveID);
float sharpness = OsdGetPatchSharpness(patchParam);
if (sharpness > 0) {
float Sf = floor(sharpness);
float Sc = ceil(sharpness);
@ -222,14 +194,7 @@ HullVertex hs_main_patches(
output.position = float4(pos, 1.0);
#endif
int patchLevel = GetPatchLevel(primitiveID);
// +0.5 to avoid interpolation error of integer value
output.patchCoord = float4(0, 0,
patchLevel+0.5,
GetPrimitiveID(primitiveID)+0.5);
OSD_COMPUTE_PTEX_COORD_HULL_SHADER;
output.patchCoord = OsdGetPatchCoord(patchParam);
return output;
}
@ -245,7 +210,9 @@ void ds_main_patches(
in float2 domainCoord : SV_DomainLocation,
out OutputVertex output )
{
float2 UV = GetTransitionParameterization(input, domainCoord);
float2 UV = OsdGetTessParameterization(domainCoord,
input.tessOuterLo,
input.tessOuterHi);
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
float B[4], D[4], C[4];
@ -337,7 +304,7 @@ void ds_main_patches(
dUV += D[k] * DUCP[k];
}
int level = int(patch[0].ptexInfo.z);
int level = patch[0].patchCoord.z;
Tangent *= 3 * level;
BiTangent *= 3 * level;
dUU *= 6 * level;
@ -372,7 +339,7 @@ void ds_main_patches(
Tangent += B[k] * DUCP[k];
BiTangent += D[k] * BUCP[k];
}
int level = int(patch[0].ptexInfo.z);
int level = patch[0].patchCoord.z;
Tangent *= 3 * level;
BiTangent *= 3 * level;
@ -385,11 +352,7 @@ void ds_main_patches(
output.position = float4(WorldPos, 1.0f);
output.normal = normal;
output.patchCoord = patch[0].patchCoord;
output.patchCoord.xy = float2(UV.x, UV.y);
OSD_COMPUTE_PTEX_COORD_DOMAIN_SHADER;
output.patchCoord = OsdInterpolatePatchCoord(UV, patch[0].patchCoord);
OSD_DISPLACEMENT_CALLBACK;

View File

@ -41,9 +41,10 @@ struct InputVertex {
struct HullVertex {
float4 position : POSITION;
float4 patchCoord : PATCHCOORD; // u, v, level, faceID
int4 ptexInfo : PTEXINFO; // u offset, v offset, 2^ptexlevel, rotation
int4 patchCoord : PATCHCOORD; // U offset, V offset, faceLevel, faceId
#ifdef OSD_ENABLE_PATCH_CULL
int3 clipFlag : CLIPFLAG;
#endif
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
float4 P1 : POSITION1;
float4 P2 : POSITION2;
@ -55,9 +56,9 @@ struct OutputVertex {
float4 positionOut : SV_Position;
float4 position : POSITION1;
float3 normal : NORMAL;
float3 tangent : TANGENT0;
float3 tangent : TANGENT;
float3 bitangent : TANGENT1;
float4 patchCoord : PATCHCOORD; // u, v, level, faceID
float4 patchCoord : PATCHCOORD; // u, v, faceLevel, faceId
noperspective float4 edgeDistance : EDGEDISTANCE;
#if defined(OSD_COMPUTE_NORMAL_DERIVATIVES)
float3 Nu : TANGENT2;
@ -88,8 +89,7 @@ struct GregDomainVertex {
float3 Em : POSITION2;
float3 Fp : POSITION3;
float3 Fm : POSITION4;
float4 patchCoord: TEXTURE0;
float4 ptexInfo: TEXTURE1;
int4 patchCoord: PATCHCOORD;
};
struct HS_CONSTANT_FUNC_OUT {
@ -107,74 +107,105 @@ float OsdTessLevel();
int OsdGregoryQuadOffsetBase();
int OsdPrimitiveIdBase();
float GetTessLevel(int patchLevel)
{
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
return OsdTessLevel();
#else
return OsdTessLevel() / pow(2, patchLevel-1);
#endif
}
#ifndef GetPrimitiveID
#define GetPrimitiveID(x) (x + OsdPrimitiveIdBase())
#endif
float GetPostProjectionSphereExtent(float3 center, float diameter)
{
float4 p = mul(OsdProjectionMatrix(), float4(center, 1.0));
return abs(diameter * OsdProjectionMatrix()[1][1] / p.w);
}
float TessAdaptive(float3 p0, float3 p1)
{
// Adaptive factor can be any computation that depends only on arg values.
// Project the diameter of the edge's bounding sphere instead of using the
// length of the projected edge itself to avoid problems near silhouettes.
float3 center = (p0 + p1) / 2.0;
float diameter = distance(p0, p1);
return round(max(1.0, OsdTessLevel() * GetPostProjectionSphereExtent(center, diameter)));
}
#ifndef OSD_DISPLACEMENT_CALLBACK
#define OSD_DISPLACEMENT_CALLBACK
#endif
// ----------------------------------------------------------------------------
// Patch Parameters
// ----------------------------------------------------------------------------
//
// Each patch has a corresponding patchParam. This is a set of three values
// specifying additional information about the patch:
//
// faceId -- topological face identifier (e.g. Ptex FaceId)
// bitfield -- refinement-level, non-quad, boundary, transition, uv-offset
// sharpness -- crease sharpness for single-crease patches
//
// These are stored in OsdPatchParamBuffer indexed by the value returned
// from OsdGetPatchIndex() which is a function of the current PrimitiveID
// along with an optional client provided offset.
//
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
Buffer<uint3> OsdPatchParamBuffer : register( t3 );
#else
Buffer<uint2> OsdPatchParamBuffer : register( t3 );
#endif
#define GetPatchParam(primitiveID) \
(OsdPatchParamBuffer[GetPrimitiveID(primitiveID)].y)
int OsdGetPatchIndex(int primitiveId)
{
return (primitiveId + OsdPrimitiveIdBase());
}
#define GetPatchLevel(primitiveID) \
(OsdPatchParamBuffer[GetPrimitiveID(primitiveID)].y & 0xf)
int3 OsdGetPatchParam(int patchIndex)
{
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
return OsdPatchParamBuffer[patchIndex].xyz;
#else
uint2 p = OsdPatchParamBuffer[patchIndex].xy;
return int3(p.x, p.y, 0);
#endif
}
#define GetSharpness(primitiveID) \
(asfloat(OsdPatchParamBuffer[GetPrimitiveID(primitiveID)].z))
int OsdGetPatchFaceId(int3 patchParam)
{
return patchParam.x;
}
#define OSD_COMPUTE_PTEX_COORD_HULL_SHADER \
{ \
int2 ptexIndex = OsdPatchParamBuffer[GetPrimitiveID(primitiveID)].xy; \
int faceID = ptexIndex.x; \
int lv = 1 << ((ptexIndex.y & 0x7) - ((ptexIndex.y >> 3) & 1)); \
int u = (ptexIndex.y >> 22) & 0x3ff; \
int v = (ptexIndex.y >> 12) & 0x3ff; \
output.patchCoord.w = faceID+0.5; \
output.ptexInfo = int4(u, v, lv, 0); \
}
int OsdGetPatchFaceLevel(int3 patchParam)
{
return (1 << ((patchParam.y & 0x7) - ((patchParam.y >> 3) & 1)));
}
#define OSD_COMPUTE_PTEX_COORD_DOMAIN_SHADER \
{ \
float2 uv = output.patchCoord.xy; \
int2 p = patch[0].ptexInfo.xy; \
int lv = patch[0].ptexInfo.z; \
int rot = patch[0].ptexInfo.w; \
output.patchCoord.xy = (uv * float2(1.0,1.0)/lv) + float2(p.x, p.y)/lv; \
}
int OsdGetPatchRefinementLevel(int3 patchParam)
{
return (patchParam.y & 0x7);
}
int OsdGetPatchBoundaryMask(int3 patchParam)
{
return ((patchParam.y >> 4) & 0xf);
}
int OsdGetPatchTransitionMask(int3 patchParam)
{
return ((patchParam.y >> 8) & 0xf);
}
int2 OsdGetPatchFaceUV(int3 patchParam)
{
int u = (patchParam.y >> 22) & 0x3ff;
int v = (patchParam.y >> 12) & 0x3ff;
return int2(u,v);
}
float OsdGetPatchSharpness(int3 patchParam)
{
return asfloat(patchParam.z);
}
int4 OsdGetPatchCoord(int3 patchParam)
{
int faceId = OsdGetPatchFaceId(patchParam);
int faceLevel = OsdGetPatchFaceLevel(patchParam);
int2 faceUV = OsdGetPatchFaceUV(patchParam);
return int4(faceUV.x, faceUV.y, faceLevel, faceId);
}
float4 OsdInterpolatePatchCoord(float2 localUV, int4 perPrimPatchCoord)
{
int faceId = perPrimPatchCoord.w;
int faceLevel = perPrimPatchCoord.z;
float2 faceUV = float2(perPrimPatchCoord.x, perPrimPatchCoord.y);
float2 uv = localUV/faceLevel + faceUV/faceLevel;
return float4(uv.x, uv.y, faceLevel+0.5, faceId+0.5);
}
// ----------------------------------------------------------------------------
// patch culling
// ----------------------------------------------------------------------------
#ifdef OSD_ENABLE_PATCH_CULL
@ -203,35 +234,24 @@ float TessAdaptive(float3 p0, float3 p1)
return output; \
}
#define OSD_PATCH_CULL_TRIANGLE(N) \
int3 clipFlag = int3(0,0,0); \
for(int i = 0; i < N; ++i) { \
clipFlag |= patch[i].clipFlag; \
} \
if (any(clipFlag != int3(3,3,3))) { \
output.tessLevelInner = 0; \
output.tessLevelOuter[0] = 0; \
output.tessLevelOuter[1] = 0; \
output.tessLevelOuter[2] = 0; \
return output; \
}
#else
#define OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(P)
#define OSD_PATCH_CULL(N)
#define OSD_PATCH_CULL_TRIANGLE(N)
#endif
void Univar4x4(in float u, out float B[4], out float D[4])
// ----------------------------------------------------------------------------
void
Univar4x4(in float u, out float B[4], out float D[4])
{
float t = u;
float s = 1.0f - u;
float A0 = s * s;
float A0 = s * s;
float A1 = 2 * s * t;
float A2 = t * t;
B[0] = s * A0;
B[0] = s * A0;
B[1] = t * A0 + s * A1;
B[2] = t * A1 + s * A2;
B[3] = t * A2;
@ -275,9 +295,11 @@ Univar4x4(in float u, out float B[4], out float D[4], out float C[4])
// ----------------------------------------------------------------------------
float3
EvalBezier(float3 cp[16], float2 uv)
OsdEvalBezier(float3 cp[16], float2 uv)
{
float3 BUCP[4] = { float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,0,0) };
float3 BUCP[4] = {
float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,0,0)
};
float B[4], D[4];
@ -300,3 +322,304 @@ EvalBezier(float3 cp[16], float2 uv)
}
// ----------------------------------------------------------------------------
// Boundary Interpolation
// ----------------------------------------------------------------------------
void
OsdComputeBSplineBoundaryPoints(inout float3 cpt[16], int3 patchParam)
{
int boundaryMask = OsdGetPatchBoundaryMask(patchParam);
if ((boundaryMask & 1) != 0) {
cpt[0] = 2*cpt[4] - cpt[8];
cpt[1] = 2*cpt[5] - cpt[9];
cpt[2] = 2*cpt[6] - cpt[10];
cpt[3] = 2*cpt[7] - cpt[11];
}
if ((boundaryMask & 2) != 0) {
cpt[3] = 2*cpt[2] - cpt[1];
cpt[7] = 2*cpt[6] - cpt[5];
cpt[11] = 2*cpt[10] - cpt[9];
cpt[15] = 2*cpt[14] - cpt[13];
}
if ((boundaryMask & 4) != 0) {
cpt[12] = 2*cpt[8] - cpt[4];
cpt[13] = 2*cpt[9] - cpt[5];
cpt[14] = 2*cpt[10] - cpt[6];
cpt[15] = 2*cpt[11] - cpt[7];
}
if ((boundaryMask & 8) != 0) {
cpt[0] = 2*cpt[1] - cpt[2];
cpt[4] = 2*cpt[5] - cpt[6];
cpt[8] = 2*cpt[9] - cpt[10];
cpt[12] = 2*cpt[13] - cpt[14];
}
}
// ----------------------------------------------------------------------------
// Tessellation
// ----------------------------------------------------------------------------
//
// Organization of B-spline and Bezier control points.
//
// Each patch is defined by 16 control points (labeled 0-15).
//
// The patch will be evaluated across the domain from (0,0) at
// the lower-left to (1,1) at the upper-right. When computing
// adaptive tessellation metrics, we consider refined vertex-vertex
// and edge-vertex points along the transition edges of the patch
// (labeled vv* and ev* respectively).
//
// The two segments of each transition edge are labeled Lo and Hi,
// with the Lo segment occuring before the Hi segment along the
// transition edge's domain parameterization. These Lo and Hi segment
// tessellation levels determine how domain evaluation coordinates
// are remapped along transition edges. The Hi segment value will
// be zero for a non-transition edge.
//
// (0,1) (1,1)
//
// vv3 ev23 vv2
// | Lo3 | Hi3 |
// --O-----------O-----+-----O-----------O--
// | 12 | 13 14 | 15 |
// | | | |
// | | | |
// Hi0 | | | | Hi2
// | | | |
// O-----------O-----------O-----------O
// | 8 | 9 10 | 11 |
// | | | |
// ev03 --+ | | +-- ev12
// | | | |
// | 4 | 5 6 | 7 |
// O-----------O-----------O-----------O
// | | | |
// Lo0 | | | | Lo2
// | | | |
// | | | |
// | 0 | 1 2 | 3 |
// --O-----------O-----+-----O-----------O--
// | Lo1 | Hi1 |
// vv0 ev01 vv1
//
// (0,0) (1,0)
//
float OsdComputePostProjectionSphereExtent(float3 center, float diameter)
{
float4 p = mul(OsdProjectionMatrix(), float4(center, 1.0));
return abs(diameter * OsdProjectionMatrix()[1][1] / p.w);
}
float OsdComputeTessLevel(float3 p0, float3 p1)
{
// Adaptive factor can be any computation that depends only on arg values.
// Project the diameter of the edge's bounding sphere instead of using the
// length of the projected edge itself to avoid problems near silhouettes.
float3 center = (p0 + p1) / 2.0;
float diameter = distance(p0, p1);
float projLength = OsdComputePostProjectionSphereExtent(center, diameter);
return round(max(1.0, OsdTessLevel() * projLength));
}
void
OsdGetTessLevelsUniform(int3 patchParam,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
int refinementLevel = OsdGetPatchRefinementLevel(patchParam);
float tessLevel = OsdTessLevel() / pow(2, refinementLevel-1);
tessOuterLo = float4(tessLevel,tessLevel,tessLevel,tessLevel);
tessOuterHi = float4(0,0,0,0);
}
void
OsdGetTessLevelsRefinedPoints(float3 cp[16], int3 patchParam,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. We compute the corresponding
// vertex-vertex and edge-vertex refined points along the edges of the
// patch using Catmull-Clark subdivision stencil weights.
// For simplicity, we let the optimizer discard unused computation.
float3 vv0 = (cp[0] + cp[2] + cp[8] + cp[10]) * 0.015625 +
(cp[1] + cp[4] + cp[6] + cp[9]) * 0.09375 + cp[5] * 0.5625;
float3 ev01 = (cp[1] + cp[2] + cp[9] + cp[10]) * 0.0625 +
(cp[5] + cp[6]) * 0.375;
float3 vv1 = (cp[1] + cp[3] + cp[9] + cp[11]) * 0.015625 +
(cp[2] + cp[5] + cp[7] + cp[10]) * 0.09375 + cp[6] * 0.5625;
float3 ev12 = (cp[5] + cp[7] + cp[9] + cp[11]) * 0.0625 +
(cp[6] + cp[10]) * 0.375;
float3 vv2 = (cp[5] + cp[7] + cp[13] + cp[15]) * 0.015625 +
(cp[6] + cp[9] + cp[11] + cp[14]) * 0.09375 + cp[10] * 0.5625;
float3 ev23 = (cp[5] + cp[6] + cp[13] + cp[14]) * 0.0625 +
(cp[9] + cp[10]) * 0.375;
float3 vv3 = (cp[4] + cp[6] + cp[12] + cp[14]) * 0.015625 +
(cp[5] + cp[8] + cp[10] + cp[13]) * 0.09375 + cp[9] * 0.5625;
float3 ev03 = (cp[4] + cp[6] + cp[8] + cp[10]) * 0.0625 +
(cp[5] + cp[9]) * 0.375;
tessOuterLo = float4(0,0,0,0);
tessOuterHi = float4(0,0,0,0);
int transitionMask = OsdGetPatchTransitionMask(patchParam);
if ((transitionMask & 8) != 0) {
tessOuterLo[0] = OsdComputeTessLevel(vv0, ev03);
tessOuterHi[0] = OsdComputeTessLevel(vv3, ev03);
} else {
tessOuterLo[0] = OsdComputeTessLevel(cp[5], cp[9]);
}
if ((transitionMask & 1) != 0) {
tessOuterLo[1] = OsdComputeTessLevel(vv0, ev01);
tessOuterHi[1] = OsdComputeTessLevel(vv1, ev01);
} else {
tessOuterLo[1] = OsdComputeTessLevel(cp[5], cp[6]);
}
if ((transitionMask & 2) != 0) {
tessOuterLo[2] = OsdComputeTessLevel(vv1, ev12);
tessOuterHi[2] = OsdComputeTessLevel(vv2, ev12);
} else {
tessOuterLo[2] = OsdComputeTessLevel(cp[6], cp[10]);
}
if ((transitionMask & 4) != 0) {
tessOuterLo[3] = OsdComputeTessLevel(vv3, ev23);
tessOuterHi[3] = OsdComputeTessLevel(vv2, ev23);
} else {
tessOuterLo[3] = OsdComputeTessLevel(cp[9], cp[10]);
}
}
void
OsdGetTessLevelsLimitPoints(float3 cpBezier[16], int3 patchParam,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. When the patch control
// points have been converted to the Bezier basis, the control points
// at the four corners are on the limit surface (since a Bezier patch
// interpolates its corner control points). We can compute an adaptive
// tessellation level for transition edges on the limit surface by
// evaluating a limit position at the mid point of each transition edge.
tessOuterLo = float4(0,0,0,0);
tessOuterHi = float4(0,0,0,0);
int transitionMask = OsdGetPatchTransitionMask(patchParam);
if ((transitionMask & 8) != 0) {
float3 ev03 = OsdEvalBezier(cpBezier, float2(0.0, 0.5));
tessOuterLo[0] = OsdComputeTessLevel(cpBezier[0], ev03);
tessOuterHi[0] = OsdComputeTessLevel(cpBezier[12], ev03);
} else {
tessOuterLo[0] = OsdComputeTessLevel(cpBezier[0], cpBezier[12]);
}
if ((transitionMask & 1) != 0) {
float3 ev01 = OsdEvalBezier(cpBezier, float2(0.5, 0.0));
tessOuterLo[1] = OsdComputeTessLevel(cpBezier[0], ev01);
tessOuterHi[1] = OsdComputeTessLevel(cpBezier[3], ev01);
} else {
tessOuterLo[1] = OsdComputeTessLevel(cpBezier[0], cpBezier[3]);
}
if ((transitionMask & 2) != 0) {
float3 ev12 = OsdEvalBezier(cpBezier, float2(1.0, 0.5));
tessOuterLo[2] = OsdComputeTessLevel(cpBezier[3], ev12);
tessOuterHi[2] = OsdComputeTessLevel(cpBezier[15], ev12);
} else {
tessOuterLo[2] = OsdComputeTessLevel(cpBezier[3], cpBezier[15]);
}
if ((transitionMask & 4) != 0) {
float3 ev23 = OsdEvalBezier(cpBezier, float2(0.5, 1.0));
tessOuterLo[3] = OsdComputeTessLevel(cpBezier[12], ev23);
tessOuterHi[3] = OsdComputeTessLevel(cpBezier[15], ev23);
} else {
tessOuterLo[3] = OsdComputeTessLevel(cpBezier[12], cpBezier[15]);
}
}
void
OsdGetTessLevels(float3 cp[16], int3 patchParam,
inout float4 tessLevelOuter, inout float4 tessLevelInner,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
OsdGetTessLevelsLimitPoints(cp, patchParam, tessOuterLo, tessOuterHi);
#elif defined OSD_ENABLE_SCREENSPACE_TESSELLATION_REFINED
OsdGetTessLevelsRefinedPoints(cp, patchParam, tessOuterLo, tessOuterHi);
#else
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;
}
void
OsdGetTessLevels(float3 cp0, float3 cp1, float3 cp2, float3 cp3,
int3 patchParam,
inout float4 tessLevelOuter, inout float4 tessLevelInner)
{
float4 tessOuterLo = float4(0,0,0,0);
float4 tessOuterHi = float4(0,0,0,0);
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
tessOuterLo[0] = OsdComputeTessLevel(cp0, cp1);
tessOuterLo[1] = OsdComputeTessLevel(cp0, cp3);
tessOuterLo[2] = OsdComputeTessLevel(cp2, cp3);
tessOuterLo[3] = OsdComputeTessLevel(cp1, cp2);
tessOuterHi = float4(0,0,0,0);
#else
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;
}
float
OsdGetTessTransitionSplit(float t, float n0, float n1)
{
float ti = round(t * (n0 + n1));
if (ti <= n0) {
return 0.5 * (ti / n0);
} else {
return 0.5 * ((ti - n0) / n1) + 0.5;
}
}
float2
OsdGetTessParameterization(float2 uv, float4 tessOuterLo, float4 tessOuterHi)
{
float2 UV = uv;
if (UV.x == 0 && tessOuterHi[0] > 0) {
UV.y = OsdGetTessTransitionSplit(UV.y, tessOuterLo[0], tessOuterHi[0]);
} else
if (UV.y == 0 && tessOuterHi[1] > 0) {
UV.x = OsdGetTessTransitionSplit(UV.x, tessOuterLo[1], tessOuterHi[1]);
} else
if (UV.x == 1 && tessOuterHi[2] > 0) {
UV.y = OsdGetTessTransitionSplit(UV.y, tessOuterLo[2], tessOuterHi[2]);
} else
if (UV.y == 1 && tessOuterHi[3] > 0) {
UV.x = OsdGetTessTransitionSplit(UV.x, tessOuterLo[3], tessOuterHi[3]);
}
return UV;
}

View File

@ -267,31 +267,29 @@ HS_CONSTANT_FUNC_OUT HSConstFunc(
uint primitiveID : SV_PrimitiveID)
{
HS_CONSTANT_FUNC_OUT output;
int patchLevel = GetPatchLevel(primitiveID);
int3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(primitiveID));
OSD_PATCH_CULL(4);
#ifdef OSD_ENABLE_SCREENSPACE_TESSELLATION
output.tessLevelOuter[0] =
TessAdaptive(patch[0].hullPosition.xyz, patch[1].hullPosition.xyz);
output.tessLevelOuter[1] =
TessAdaptive(patch[0].hullPosition.xyz, patch[3].hullPosition.xyz);
output.tessLevelOuter[2] =
TessAdaptive(patch[2].hullPosition.xyz, patch[3].hullPosition.xyz);
output.tessLevelOuter[3] =
TessAdaptive(patch[1].hullPosition.xyz, patch[2].hullPosition.xyz);
output.tessLevelInner[0] =
max(output.tessLevelOuter[1], output.tessLevelOuter[3]);
output.tessLevelInner[1] =
max(output.tessLevelOuter[0], output.tessLevelOuter[2]);
#else
output.tessLevelInner[0] = GetTessLevel(patchLevel);
output.tessLevelInner[1] = GetTessLevel(patchLevel);
output.tessLevelOuter[0] = GetTessLevel(patchLevel);
output.tessLevelOuter[1] = GetTessLevel(patchLevel);
output.tessLevelOuter[2] = GetTessLevel(patchLevel);
output.tessLevelOuter[3] = GetTessLevel(patchLevel);
#endif
float4 tessLevelOuter = float4(0,0,0,0);
float4 tessLevelInner = float4(0,0,0,0);
OsdGetTessLevels(patch[0].hullPosition.xyz, patch[1].hullPosition.xyz,
patch[2].hullPosition.xyz, patch[3].hullPosition.xyz,
patchParam, tessLevelOuter, tessLevelInner);
output.tessLevelOuter[0] = tessLevelOuter[0];
output.tessLevelOuter[1] = tessLevelOuter[1];
output.tessLevelOuter[2] = tessLevelOuter[2];
output.tessLevelOuter[3] = tessLevelOuter[3];
output.tessLevelInner[0] = tessLevelInner[0];
output.tessLevelInner[1] = tessLevelInner[1];
output.tessOuterLo = float4(0,0,0,0);
output.tessOuterHi = float4(0,0,0,0);
return output;
}
@ -446,12 +444,9 @@ GregDomainVertex hs_main_patches(
output.Fp = Fp;
output.Fm = Fm;
int patchLevel = GetPatchLevel(primitiveID);
output.patchCoord = float4(0, 0,
patchLevel+0.5f,
GetPrimitiveID(primitiveID)+0.5f);
int3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(primitiveID));
OSD_COMPUTE_PTEX_COORD_HULL_SHADER;
output.patchCoord = OsdGetPatchCoord(patchParam);
return output;
}
@ -527,8 +522,6 @@ void ds_main_patches(
float3 Tangent = float3(0, 0, 0);
float3 BiTangent = float3(0, 0, 0);
#line 519
#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES
float B[4], D[4], C[4];
@ -564,7 +557,7 @@ void ds_main_patches(
dUV += D[i] * DUCP[i];
}
int level = int(patch[0].ptexInfo.z);
int level = patch[0].patchCoord.z;
BiTangent *= 3 * level;
Tangent *= 3 * level;
dUU *= 6 * level;
@ -619,7 +612,7 @@ void ds_main_patches(
Tangent += B[i] * DUCP[i];
BiTangent += D[i] * BUCP[i];
}
int level = int(patch[0].ptexInfo.z);
int level = patch[0].patchCoord.z;
BiTangent *= 3 * level;
Tangent *= 3 * level;
@ -635,12 +628,10 @@ void ds_main_patches(
output.tangent = BiTangent;
output.bitangent = Tangent;
output.patchCoord = patch[0].patchCoord;
output.patchCoord.xy = float2(v, u);
output.edgeDistance = 0;
output.edgeDistance = 0;
OSD_COMPUTE_PTEX_COORD_DOMAIN_SHADER;
float2 UV = float2(v, u);
output.patchCoord = OsdInterpolatePatchCoord(UV, patch[0].patchCoord);
OSD_DISPLACEMENT_CALLBACK;

View File

@ -1,248 +0,0 @@
//
// Copyright 2013 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
//----------------------------------------------------------
// Patches.HullTransition
//----------------------------------------------------------
void
GetTessLevelsUniform(float3 cp[16], int patchParam, int patchLevel,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
float tessAmount = GetTessLevel(patchLevel);
tessOuterLo = float4(tessAmount,tessAmount,tessAmount,tessAmount);
tessOuterHi = float4(0,0,0,0);
}
//
// Organization of B-spline and Bezier control points.
//
// Each patch is defined by 16 control points (labeled 0-15).
//
// The patch will be evaluated across the domain from (0,0) at
// the lower-left to (1,1) at the upper-right. When computing
// adaptive tessellation metrics, we consider refined vertex-vertex
// and edge-vertex points along the transition edges of the patch
// (labeled vv* and ev* respectively).
//
// The two segments of each transition edge are labeled Lo and Hi,
// with the Lo segment occuring before the Hi segment along the
// transition edge's domain parameterization. These Lo and Hi segment
// tessellation levels determine how domain evaluation coordinates
// are remapped along transition edges. The Hi segment value will
// be zero for a non-transition edge.
//
// (0,1) (1,1)
//
// vv3 ev23 vv2
// | Lo3 | Hi3 |
// --O-----------O-----+-----O-----------O--
// | 12 | 13 14 | 15 |
// | | | |
// | | | |
// Hi0 | | | | Hi2
// | | | |
// O-----------O-----------O-----------O
// | 8 | 9 10 | 11 |
// | | | |
// ev03 --+ | | +-- ev12
// | | | |
// | 4 | 5 6 | 7 |
// O-----------O-----------O-----------O
// | | | |
// Lo0 | | | | Lo2
// | | | |
// | | | |
// | 0 | 1 2 | 3 |
// --O-----------O-----+-----O-----------O--
// | Lo1 | Hi1 |
// vv0 ev01 vv1
//
// (0,0) (1,0)
//
void
GetTessLevelsRefinedPoints(float3 cp[16], int patchParam,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. We compute the corresponding
// vertex-vertex and edge-vertex refined points along the edges of the
// patch using Catmull-Clark subdivision stencil weights.
// For simplicity, we let the optimizer discard unused computation.
float3 vv0 = (cp[0] + cp[2] + cp[8] + cp[10]) * 0.015625 +
(cp[1] + cp[4] + cp[6] + cp[9]) * 0.09375 + cp[5] * 0.5625;
float3 ev01 = (cp[1] + cp[2] + cp[9] + cp[10]) * 0.0625 +
(cp[5] + cp[6]) * 0.375;
float3 vv1 = (cp[1] + cp[3] + cp[9] + cp[11]) * 0.015625 +
(cp[2] + cp[5] + cp[7] + cp[10]) * 0.09375 + cp[6] * 0.5625;
float3 ev12 = (cp[5] + cp[7] + cp[9] + cp[11]) * 0.0625 +
(cp[6] + cp[10]) * 0.375;
float3 vv2 = (cp[5] + cp[7] + cp[13] + cp[15]) * 0.015625 +
(cp[6] + cp[9] + cp[11] + cp[14]) * 0.09375 + cp[10] * 0.5625;
float3 ev23 = (cp[5] + cp[6] + cp[13] + cp[14]) * 0.0625 +
(cp[9] + cp[10]) * 0.375;
float3 vv3 = (cp[4] + cp[6] + cp[12] + cp[14]) * 0.015625 +
(cp[5] + cp[8] + cp[10] + cp[13]) * 0.09375 + cp[9] * 0.5625;
float3 ev03 = (cp[4] + cp[6] + cp[8] + cp[10]) * 0.0625 +
(cp[5] + cp[9]) * 0.375;
tessOuterLo = float4(1,1,1,1);
tessOuterHi = float4(0,0,0,0);
if (((patchParam >> 11) & 1) != 0) {
tessOuterLo[0] = TessAdaptive(vv0, ev03);
tessOuterHi[0] = TessAdaptive(vv3, ev03);
} else {
tessOuterLo[0] = TessAdaptive(cp[5], cp[9]);
}
if (((patchParam >> 8) & 1) != 0) {
tessOuterLo[1] = TessAdaptive(vv0, ev01);
tessOuterHi[1] = TessAdaptive(vv1, ev01);
} else {
tessOuterLo[1] = TessAdaptive(cp[5], cp[6]);
}
if (((patchParam >> 9) & 1) != 0) {
tessOuterLo[2] = TessAdaptive(vv1, ev12);
tessOuterHi[2] = TessAdaptive(vv2, ev12);
} else {
tessOuterLo[2] = TessAdaptive(cp[6], cp[10]);
}
if (((patchParam >> 10) & 1) != 0) {
tessOuterLo[3] = TessAdaptive(vv3, ev23);
tessOuterHi[3] = TessAdaptive(vv2, ev23);
} else {
tessOuterLo[3] = TessAdaptive(cp[9], cp[10]);
}
}
void
GetTessLevelsLimitPoints(float3 cpBezier[16], int patchParam,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
// Each edge of a transition patch is adjacent to one or two patches
// at the next refined level of subdivision. When the patch control
// points have been converted to the Bezier basis, the control points
// at the four corners are on the limit surface (since a Bezier patch
// interpolates its corner control points). We can compute an adaptive
// tessellation level for transition edges on the limit surface by
// evaluating a limit position at the mid point of each transition edge.
tessOuterLo = float4(1,1,1,1);
tessOuterHi = float4(0,0,0,0);
if (((patchParam >> 11) & 1) != 0) {
float3 ev03 = EvalBezier(cpBezier, float2(0.0, 0.5));
tessOuterLo[0] = TessAdaptive(cpBezier[0], ev03);
tessOuterHi[0] = TessAdaptive(cpBezier[12], ev03);
} else {
tessOuterLo[0] = TessAdaptive(cpBezier[0], cpBezier[12]);
}
if (((patchParam >> 8) & 1) != 0) {
float3 ev01 = EvalBezier(cpBezier, float2(0.5, 0.0));
tessOuterLo[1] = TessAdaptive(cpBezier[0], ev01);
tessOuterHi[1] = TessAdaptive(cpBezier[3], ev01);
} else {
tessOuterLo[1] = TessAdaptive(cpBezier[0], cpBezier[3]);
}
if (((patchParam >> 9) & 1) != 0) {
float3 ev12 = EvalBezier(cpBezier, float2(1.0, 0.5));
tessOuterLo[2] = TessAdaptive(cpBezier[3], ev12);
tessOuterHi[2] = TessAdaptive(cpBezier[15], ev12);
} else {
tessOuterLo[2] = TessAdaptive(cpBezier[3], cpBezier[15]);
}
if (((patchParam >> 10) & 1) != 0) {
float3 ev23 = EvalBezier(cpBezier, float2(0.5, 1.0));
tessOuterLo[3] = TessAdaptive(cpBezier[12], ev23);
tessOuterHi[3] = TessAdaptive(cpBezier[15], ev23);
} else {
tessOuterLo[3] = TessAdaptive(cpBezier[12], cpBezier[15]);
}
}
void
GetTransitionTessLevels(
float3 cp[16], int patchParam, int patchLevel,
inout float4 outerLevel, inout float4 innerLevel,
inout float4 tessOuterLo, inout float4 tessOuterHi)
{
#if defined OSD_ENABLE_SCREENSPACE_TESSELLATION
GetTessLevelsLimitPoints(cp, patchParam, tessOuterLo, tessOuterHi);
#elif defined OSD_ENABLE_SCREENSPACE_TESSELLATION_REFINED
GetTessLevelsRefinedPoints(cp, patchParam, tessOuterLo, tessOuterHi);
#else
GetTessLevelsUniform(cp, patchParam, patchLevel, 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.
outerLevel = tessOuterLo + tessOuterHi;
// Inner levels are the average the corresponding outer levels.
innerLevel[0] = (outerLevel[1] + outerLevel[3]) * 0.5;
innerLevel[1] = (outerLevel[0] + outerLevel[2]) * 0.5;
}
//----------------------------------------------------------
// Patches.DomainTransition
//----------------------------------------------------------
float
GetTransitionSplit(float t, float n0, float n1)
{
float ti = round(t * (n0 + n1));
if (ti <= n0) {
return 0.5 * (ti / n0);
} else {
return 0.5 * ((ti - n0) / n1) + 0.5;
}
}
float2
GetTransitionParameterization(
in HS_CONSTANT_FUNC_OUT input,
in float2 uv)
{
float2 UV = uv.xy;
if (UV.x == 0 && input.tessOuterHi[0] > 0) {
UV.y = GetTransitionSplit(UV.y, input.tessOuterLo[0], input.tessOuterHi[0]);
} else
if (UV.y == 0 && input.tessOuterHi[1] > 0) {
UV.x = GetTransitionSplit(UV.x, input.tessOuterLo[1], input.tessOuterHi[1]);
} else
if (UV.x == 1 && input.tessOuterHi[2] > 0) {
UV.y = GetTransitionSplit(UV.y, input.tessOuterLo[2], input.tessOuterHi[2]);
} else
if (UV.y == 1 && input.tessOuterHi[3] > 0) {
UV.x = GetTransitionSplit(UV.x, input.tessOuterLo[3], input.tessOuterHi[3]);
}
return UV;
}