diff --git a/examples/dxPtexViewer/shader.hlsl b/examples/dxPtexViewer/shader.hlsl index e0c19191..a4d601dc 100644 --- a/examples/dxPtexViewer/shader.hlsl +++ b/examples/dxPtexViewer/shader.hlsl @@ -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); } // --------------------------------------------------------------------------- diff --git a/examples/glPtexViewer/shader.glsl b/examples/glPtexViewer/shader.glsl index 6447803c..068e4f63 100644 --- a/examples/glPtexViewer/shader.glsl +++ b/examples/glPtexViewer/shader.glsl @@ -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 diff --git a/examples/glViewer/shader.glsl b/examples/glViewer/shader.glsl index 80fb805c..83fd90fa 100644 --- a/examples/glViewer/shader.glsl +++ b/examples/glViewer/shader.glsl @@ -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); diff --git a/opensubdiv/osd/CMakeLists.txt b/opensubdiv/osd/CMakeLists.txt index 943fbda8..53cb7f20 100644 --- a/opensubdiv/osd/CMakeLists.txt +++ b/opensubdiv/osd/CMakeLists.txt @@ -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 diff --git a/opensubdiv/osd/d3d11DrawRegistry.cpp b/opensubdiv/osd/d3d11DrawRegistry.cpp index b5e50247..cea0fc73 100644 --- a/opensubdiv/osd/d3d11DrawRegistry.cpp +++ b/opensubdiv/osd/d3d11DrawRegistry.cpp @@ -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; diff --git a/opensubdiv/osd/glDrawRegistry.cpp b/opensubdiv/osd/glDrawRegistry.cpp index 6e5d19ff..0c338d22 100644 --- a/opensubdiv/osd/glDrawRegistry.cpp +++ b/opensubdiv/osd/glDrawRegistry.cpp @@ -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; diff --git a/opensubdiv/osd/glslPatchBSpline.glsl b/opensubdiv/osd/glslPatchBSpline.glsl index d53f4f51..ccba7563 100644 --- a/opensubdiv/osd/glslPatchBSpline.glsl +++ b/opensubdiv/osd/glslPatchBSpline.glsl @@ -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; diff --git a/opensubdiv/osd/glslPatchCommon.glsl b/opensubdiv/osd/glslPatchCommon.glsl index b4469b7c..cae7c184 100644 --- a/opensubdiv/osd/glslPatchCommon.glsl +++ b/opensubdiv/osd/glslPatchCommon.glsl @@ -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; +} + diff --git a/opensubdiv/osd/glslPatchGregory.glsl b/opensubdiv/osd/glslPatchGregory.glsl index 3ff72516..cf60aae1 100644 --- a/opensubdiv/osd/glslPatchGregory.glsl +++ b/opensubdiv/osd/glslPatchGregory.glsl @@ -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; diff --git a/opensubdiv/osd/glslPatchGregoryBasis.glsl b/opensubdiv/osd/glslPatchGregoryBasis.glsl index 9556c825..bf68540c 100644 --- a/opensubdiv/osd/glslPatchGregoryBasis.glsl +++ b/opensubdiv/osd/glslPatchGregoryBasis.glsl @@ -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; diff --git a/opensubdiv/osd/glslPatchTransition.glsl b/opensubdiv/osd/glslPatchTransition.glsl deleted file mode 100644 index 5b8ed194..00000000 --- a/opensubdiv/osd/glslPatchTransition.glsl +++ /dev/null @@ -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 diff --git a/opensubdiv/osd/hlslPatchBSpline.hlsl b/opensubdiv/osd/hlslPatchBSpline.hlsl index 192e718f..c80becd7 100644 --- a/opensubdiv/osd/hlslPatchBSpline.hlsl +++ b/opensubdiv/osd/hlslPatchBSpline.hlsl @@ -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; diff --git a/opensubdiv/osd/hlslPatchCommon.hlsl b/opensubdiv/osd/hlslPatchCommon.hlsl index 7d2b6897..09a108fa 100644 --- a/opensubdiv/osd/hlslPatchCommon.hlsl +++ b/opensubdiv/osd/hlslPatchCommon.hlsl @@ -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 OsdPatchParamBuffer : register( t3 ); #else Buffer 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; +} + diff --git a/opensubdiv/osd/hlslPatchGregory.hlsl b/opensubdiv/osd/hlslPatchGregory.hlsl index 664ace03..3cc6624f 100644 --- a/opensubdiv/osd/hlslPatchGregory.hlsl +++ b/opensubdiv/osd/hlslPatchGregory.hlsl @@ -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; diff --git a/opensubdiv/osd/hlslPatchTransition.hlsl b/opensubdiv/osd/hlslPatchTransition.hlsl deleted file mode 100644 index a5f44e15..00000000 --- a/opensubdiv/osd/hlslPatchTransition.hlsl +++ /dev/null @@ -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; -}