From 8d9ae550ff9ff3a78edfc988c6f60cd81b9295c4 Mon Sep 17 00:00:00 2001 From: Takahito Tejima Date: Wed, 20 May 2015 10:49:45 -0700 Subject: [PATCH] Add a HLSL version of GregoryBasis patch shader. hlslPatchGregoryBasis.hlsl is an equivalent to glslPatchGregoryBasis. Update dxViewer to be able to switch among bspline, gregorybasis, legacy end capping. also fixes a bug of GLSL legacy gregory shader which had an inconsistent resource naming with example codes. It looks like there's still an issue of D3D11 patchParam data fetching. we'll come back to that bug. --- examples/dxPtexViewer/dxPtexViewer.cpp | 32 +-- examples/dxPtexViewer/shader.hlsl | 17 +- examples/dxViewer/dxviewer.cpp | 81 ++++--- examples/dxViewer/shader.hlsl | 18 +- opensubdiv/osd/CMakeLists.txt | 1 + opensubdiv/osd/glslPatchGregory.glsl | 8 +- opensubdiv/osd/hlslPatchBSpline.hlsl | 6 +- opensubdiv/osd/hlslPatchCommon.hlsl | 2 - opensubdiv/osd/hlslPatchGregoryBasis.hlsl | 253 ++++++++++++++++++++++ opensubdiv/osd/hlslPatchShaderSource.cpp | 12 +- 10 files changed, 363 insertions(+), 67 deletions(-) mode change 100644 => 100755 examples/dxPtexViewer/dxPtexViewer.cpp create mode 100644 opensubdiv/osd/hlslPatchGregoryBasis.hlsl diff --git a/examples/dxPtexViewer/dxPtexViewer.cpp b/examples/dxPtexViewer/dxPtexViewer.cpp old mode 100644 new mode 100755 index 5e2e77e9..fcf7adf7 --- a/examples/dxPtexViewer/dxPtexViewer.cpp +++ b/examples/dxPtexViewer/dxPtexViewer.cpp @@ -725,8 +725,7 @@ createOsdMesh(int level, int kernel) { OpenSubdiv::Osd::MeshBitset bits; bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive); - // gregory basis hasn't supported yet in D3D11Mesh - bits.set(OpenSubdiv::Osd::MeshEndCapLegacyGregory, true); + bits.set(OpenSubdiv::Osd::MeshEndCapGregoryBasis, true); int numVertexElements = 6; //g_adaptive ? 3 : 6; int numVaryingElements = 0; @@ -1014,12 +1013,20 @@ drawModel() { // patch drawing for (int i = 0; i < (int)patches.size(); ++i) { OpenSubdiv::Osd::DrawContext::PatchArray const & patch = patches[i]; + OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor(); + OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType(); D3D11_PRIMITIVE_TOPOLOGY topology; - // if (patch.GetDescriptor().GetType() != OpenSubdiv::Far::PatchTables::REGULAR) continue; - if (g_mesh->GetDrawContext()->IsAdaptive()) { - switch (patch.GetDescriptor().GetNumControlVertices()) { + switch (patchType) { + case OpenSubdiv::Far::PatchDescriptor::TRIANGLES: + topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + break; + case OpenSubdiv::Far::PatchDescriptor::QUADS: + topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; + break; + default: + switch (desc.GetNumControlVertices()) { case 4: topology = D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; break; @@ -1032,17 +1039,15 @@ drawModel() { case 16: topology = D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST; break; + case 20: + topology = D3D11_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST; + break; default: assert(false); break; } - } else { - if (g_scheme == kLoop) { - topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - } else { - topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; - } - } + break; + }; Effect effect; effect.value = 0; @@ -1457,7 +1462,8 @@ initD3D11(HWND hWnd) { hDriverType = driverTypes[driverTypeIndex]; unsigned int deviceFlags = 0; #ifndef NDEBUG - deviceFlags |= D3D11_CREATE_DEVICE_DEBUG; + // XXX: this is problematic in some environments. +// deviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif hr = D3D11CreateDeviceAndSwapChain(NULL, hDriverType, NULL, deviceFlags, NULL, 0, diff --git a/examples/dxPtexViewer/shader.hlsl b/examples/dxPtexViewer/shader.hlsl index a2983d00..7774a92b 100644 --- a/examples/dxPtexViewer/shader.hlsl +++ b/examples/dxPtexViewer/shader.hlsl @@ -444,14 +444,9 @@ getAdaptivePatchColor(int3 patchParam, float sharpness) if (sharpness > 0) { pattern = 1; } -#elif defined OSD_PATCH_GREGORY - patchType = 4; -#elif defined OSD_PATCH_GREGORY_BOUNDARY - patchType = 5; -#elif defined OSD_PATCH_GREGORY_BASIS - patchType = 6; #endif + int pattern = countbits(OsdGetPatchTransitionMask(patchParam)); int edgeCount = countbits(OsdGetPatchBoundaryMask(patchParam)); if (edgeCount == 1) { patchType = 2; // BOUNDARY @@ -460,7 +455,15 @@ getAdaptivePatchColor(int3 patchParam, float sharpness) patchType = 3; // CORNER } - int pattern = countbits(OsdGetPatchTransitionMask(patchParam)); + // XXX: it looks like edgeCount != 0 for some gregory boundary patches. + // there might be a bug somewhere... +#if defined OSD_PATCH_GREGORY + patchType = 4; +#elif defined OSD_PATCH_GREGORY_BOUNDARY + patchType = 5; +#elif defined OSD_PATCH_GREGORY_BASIS + patchType = 6; +#endif return patchColors[6*patchType + pattern]; } diff --git a/examples/dxViewer/dxviewer.cpp b/examples/dxViewer/dxviewer.cpp index 4ff50317..d4c583ab 100644 --- a/examples/dxViewer/dxviewer.cpp +++ b/examples/dxViewer/dxviewer.cpp @@ -94,6 +94,11 @@ enum DisplayStyle { kWire = 0, kWireShaded, kPoint }; +enum EndCap { kEndCapNone = 0, + kEndCapBSplineBasis, + kEndCapGregoryBasis, + kEndCapLegacyGregory }; + enum HudCheckBox { kHUD_CB_DISPLAY_CAGE_EDGES, kHUD_CB_DISPLAY_CAGE_VERTS, kHUD_CB_ANIMATE_VERTICES, @@ -114,6 +119,7 @@ int g_frame = 0, int g_freeze = 0, g_displayStyle = kWireShaded, g_adaptive = 1, + g_endCap = kEndCapBSplineBasis, g_singleCreasePatch = 1, g_drawCageEdges = 1, g_drawCageVertices = 0, @@ -304,8 +310,9 @@ createOsdMesh(ShapeDesc const & shapeDesc, int level, int kernel, Scheme scheme= Osd::MeshBitset bits; bits.set(Osd::MeshAdaptive, doAdaptive); bits.set(Osd::MeshUseSingleCreasePatch, doSingleCreasePatch); - // gregory basis hasn't supported yet in D3D11Mesh - bits.set(Osd::MeshEndCapLegacyGregory, true); + bits.set(Osd::MeshEndCapBSplineBasis, g_endCap == kEndCapBSplineBasis); + bits.set(Osd::MeshEndCapGregoryBasis, g_endCap == kEndCapGregoryBasis); + bits.set(Osd::MeshEndCapLegacyGregory, g_endCap == kEndCapLegacyGregory); int numVertexElements = 6; int numVaryingElements = 0; @@ -624,10 +631,8 @@ bindProgram(Effect effect, OpenSubdiv::Osd::DrawContext::PatchArray const & patc int numElements = 6; effectDesc.maxValence = maxValence; effectDesc.numElements = numElements; - effectDesc.effect.singleCreasePatch = 0; - } - if (patch.GetDescriptor().GetType() == Descriptor::GREGORY_BASIS) { - effectDesc.effect.singleCreasePatch = 0; + // note: singleCreasePatch needs to be left defined for the patchParam + // datatype consistency. } D3D11DrawConfig *config = g_shaderCache.GetDrawConfig(effectDesc); @@ -834,10 +839,14 @@ display() { D3D11_PRIMITIVE_TOPOLOGY topology; - if (g_mesh->GetDrawContext()->IsAdaptive()) { - - OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor(); - + switch (patchType) { + case OpenSubdiv::Far::PatchDescriptor::TRIANGLES: + topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + break; + case OpenSubdiv::Far::PatchDescriptor::QUADS: + topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; + break; + default: switch (desc.GetNumControlVertices()) { case 4: topology = D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; @@ -851,18 +860,15 @@ display() { case 16: topology = D3D11_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST; break; + case 20: + topology = D3D11_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST; + break; default: assert(false); break; } - } else { - - if (g_scheme == kLoop) { - topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - } else { - topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; - } - } + break; + }; bindProgram(GetEffect(), patch); @@ -992,11 +998,22 @@ keyboard(char key) { } //------------------------------------------------------------------------------ +static void +rebuildOsdMesh() { + createOsdMesh( g_defaultShapes[ g_currentShape ], g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme ); +} + static void callbackDisplayStyle(int b) { g_displayStyle = b; } +static void +callbackEndCap(int endCap) { + g_endCap = endCap; + rebuildOsdMesh(); +} + static void callbackKernel(int k) { @@ -1019,13 +1036,13 @@ callbackKernel(int k) { } #endif - createOsdMesh(g_defaultShapes[g_currentShape], g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme); + rebuildOsdMesh(); } static void callbackLevel(int l) { g_level = l; - createOsdMesh(g_defaultShapes[g_currentShape], g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme); + rebuildOsdMesh(); } static void @@ -1040,8 +1057,7 @@ callbackModel(int m) { } g_currentShape = m; - - createOsdMesh(g_defaultShapes[g_currentShape], g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme); + rebuildOsdMesh(); } static void @@ -1062,13 +1078,13 @@ callbackFreeze(bool checked, int f) { static void callbackAdaptive(bool checked, int a) { g_adaptive = checked; - createOsdMesh(g_defaultShapes[g_currentShape], g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme); + rebuildOsdMesh(); } static void callbackSingleCreasePatch(bool checked, int /* a */) { g_singleCreasePatch = checked; - createOsdMesh(g_defaultShapes[g_currentShape], g_level, g_kernel, g_defaultShapes[ g_currentShape ].scheme); + rebuildOsdMesh(); } static void @@ -1153,10 +1169,25 @@ initHUD() { g_hud->AddCheckBox("Adaptive (`)", true, 10, 190, callbackAdaptive, 0, '`'); g_hud->AddCheckBox("Single Crease Patch (S)", g_singleCreasePatch!=0, 10, 210, callbackSingleCreasePatch, 0, 'S'); + int endcap_pulldown = g_hud->AddPullDown( + "End cap (E)", 10, 230, 200, callbackEndCap, 'E'); + g_hud->AddPullDownButton(endcap_pulldown,"None", + kEndCapNone, + g_endCap == kEndCapNone); + g_hud->AddPullDownButton(endcap_pulldown, "BSpline", + kEndCapBSplineBasis, + g_endCap == kEndCapBSplineBasis); + g_hud->AddPullDownButton(endcap_pulldown, "GregoryBasis", + kEndCapGregoryBasis, + g_endCap == kEndCapGregoryBasis); + g_hud->AddPullDownButton(endcap_pulldown, "LegacyGregory", + kEndCapLegacyGregory, + g_endCap == kEndCapLegacyGregory); + for (int i = 1; i < 11; ++i) { char level[16]; sprintf(level, "Lv. %d", i); - g_hud->AddRadioButton(3, level, i==2, 10, 210+i*20, callbackLevel, i, '0'+(i%10)); + g_hud->AddRadioButton(3, level, i==2, 10, 230+i*20, callbackLevel, i, '0'+(i%10)); } int shapes_pulldown = g_hud->AddPullDown("Shape (N)", -300, 10, 300, callbackModel, 'n'); diff --git a/examples/dxViewer/shader.hlsl b/examples/dxViewer/shader.hlsl index bed51c93..5348a94f 100644 --- a/examples/dxViewer/shader.hlsl +++ b/examples/dxViewer/shader.hlsl @@ -406,14 +406,9 @@ getAdaptivePatchColor(int3 patchParam, float sharpness) if (sharpness > 0) { patchType = 1; } -#elif defined OSD_PATCH_GREGORY - patchType = 4; -#elif defined OSD_PATCH_GREGORY_BOUNDARY - patchType = 5; -#elif defined OSD_PATCH_GREGORY_BASIS - patchType = 6; #endif + int pattern = countbits(OsdGetPatchTransitionMask(patchParam)); int edgeCount = countbits(OsdGetPatchBoundaryMask(patchParam)); if (edgeCount == 1) { patchType = 2; // BOUNDARY @@ -422,7 +417,16 @@ getAdaptivePatchColor(int3 patchParam, float sharpness) patchType = 3; // CORNER } - int pattern = countbits(OsdGetPatchTransitionMask(patchParam)); + // XXX: it looks like edgeCount != 0 for gregory_boundary. + // there might be a bug somewhere. +#if defined OSD_PATCH_GREGORY + patchType = 4; +#elif defined OSD_PATCH_GREGORY_BOUNDARY + patchType = 5; +#elif defined OSD_PATCH_GREGORY_BASIS + patchType = 6; +#endif + return patchColors[6*patchType + pattern]; } diff --git a/opensubdiv/osd/CMakeLists.txt b/opensubdiv/osd/CMakeLists.txt index 65f2ddbd..775c155b 100644 --- a/opensubdiv/osd/CMakeLists.txt +++ b/opensubdiv/osd/CMakeLists.txt @@ -201,6 +201,7 @@ if( DXSDK_FOUND ) hlslPatchCommon.hlsl hlslPatchBSpline.hlsl hlslPatchGregory.hlsl + hlslPatchGregoryBasis.hlsl ) list(APPEND PLATFORM_GPU_LIBRARIES ${DXSDK_LIBRARIES} diff --git a/opensubdiv/osd/glslPatchGregory.glsl b/opensubdiv/osd/glslPatchGregory.glsl index 80439b8e..7c316da2 100644 --- a/opensubdiv/osd/glslPatchGregory.glsl +++ b/opensubdiv/osd/glslPatchGregory.glsl @@ -57,7 +57,7 @@ float sinfn(uint n, uint j) { //---------------------------------------------------------- #ifdef OSD_PATCH_VERTEX_GREGORY_SHADER -uniform samplerBuffer VertexBuffer; +uniform samplerBuffer OsdVertexBuffer; uniform isamplerBuffer OsdValenceBuffer; layout (location=0) in vec4 position; @@ -71,9 +71,9 @@ out block { vec3 readVertex(uint vertexIndex) { vertexIndex += OsdBaseVertex(); - return vec3(texelFetch(VertexBuffer, int(OSD_NUM_ELEMENTS*vertexIndex)).x, - texelFetch(VertexBuffer, int(OSD_NUM_ELEMENTS*vertexIndex+1)).x, - texelFetch(VertexBuffer, int(OSD_NUM_ELEMENTS*vertexIndex+2)).x); + return vec3(texelFetch(OsdVertexBuffer, int(OSD_NUM_ELEMENTS*vertexIndex)).x, + texelFetch(OsdVertexBuffer, int(OSD_NUM_ELEMENTS*vertexIndex+1)).x, + texelFetch(OsdVertexBuffer, int(OSD_NUM_ELEMENTS*vertexIndex+2)).x); } void main() diff --git a/opensubdiv/osd/hlslPatchBSpline.hlsl b/opensubdiv/osd/hlslPatchBSpline.hlsl index c80becd7..e22c34e8 100644 --- a/opensubdiv/osd/hlslPatchBSpline.hlsl +++ b/opensubdiv/osd/hlslPatchBSpline.hlsl @@ -84,7 +84,7 @@ ComputeMatrixSimplified(float sharpness) HS_CONSTANT_FUNC_OUT HSConstFunc( - InputPatch patch, + InputPatch patch, OutputPatch bezierPatch, uint primitiveID : SV_PrimitiveID) { @@ -99,7 +99,7 @@ HSConstFunc( OsdComputeBSplineBoundaryPoints(position, patchParam); - OSD_PATCH_CULL(OSD_PATCH_INPUT_SIZE); + OSD_PATCH_CULL(16); float4 tessLevelOuter = float4(0,0,0,0); float4 tessLevelInner = float4(0,0,0,0); @@ -130,7 +130,7 @@ HSConstFunc( [outputcontrolpoints(16)] [patchconstantfunc("HSConstFunc")] HullVertex hs_main_patches( - in InputPatch patch, + in InputPatch patch, uint primitiveID : SV_PrimitiveID, in uint ID : SV_OutputControlPointID ) { diff --git a/opensubdiv/osd/hlslPatchCommon.hlsl b/opensubdiv/osd/hlslPatchCommon.hlsl index 016f5abe..1cfb255a 100644 --- a/opensubdiv/osd/hlslPatchCommon.hlsl +++ b/opensubdiv/osd/hlslPatchCommon.hlsl @@ -30,8 +30,6 @@ #undef OSD_FRACTIONAL_ODD_SPACING #undef OSD_FRACTIONAL_EVEN_SPACING -#define OSD_PATCH_INPUT_SIZE 16 - #define M_PI 3.14159265359f struct InputVertex { diff --git a/opensubdiv/osd/hlslPatchGregoryBasis.hlsl b/opensubdiv/osd/hlslPatchGregoryBasis.hlsl new file mode 100644 index 00000000..10c1b808 --- /dev/null +++ b/opensubdiv/osd/hlslPatchGregoryBasis.hlsl @@ -0,0 +1,253 @@ +// +// 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. +// + +#if defined OSD_FRACTIONAL_ODD_SPACING + #define HS_PARTITION "fractional_odd" +#elif defined OSD_FRACTIONAL_EVEN_SPACING + #define HS_PARTITION "fractional_even" +#else + #define HS_PARTITION "integer" +#endif + +//---------------------------------------------------------- +// Patches.Vertex +//---------------------------------------------------------- + +void vs_main_patches( in InputVertex input, + out HullVertex output ) +{ + output.position = mul(OsdModelViewMatrix(), input.position); + OSD_PATCH_CULL_COMPUTE_CLIPFLAGS(input.position); +} + +//---------------------------------------------------------- +// Patches.HullGregoryBasis +//---------------------------------------------------------- + +HS_CONSTANT_FUNC_OUT +HSConstFunc( + InputPatch patch, + uint primitiveID : SV_PrimitiveID) +{ + HS_CONSTANT_FUNC_OUT output; + + int3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(primitiveID)); + + OSD_PATCH_CULL(20); + + 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); + + OsdGetTessLevels(patch[0].position.xyz, patch[5].position.xyz, + patch[10].position.xyz, patch[15].position.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]; + + return output; +} + +[domain("quad")] +[partitioning(HS_PARTITION)] +[outputtopology("triangle_ccw")] +[outputcontrolpoints(20)] +[patchconstantfunc("HSConstFunc")] +HullVertex hs_main_patches( + in InputPatch patch, + uint primitiveID : SV_PrimitiveID, + in uint ID : SV_OutputControlPointID ) +{ + int3 patchParam = OsdGetPatchParam(OsdGetPatchIndex(primitiveID)); + HullVertex output; + + output.position = float4(patch[ID].position.xyz, 1.0); + output.patchCoord = OsdGetPatchCoord(patchParam); + + return output; +} + +//---------------------------------------------------------- +// Patches.DomainGregory +//---------------------------------------------------------- + +[domain("quad")] +void ds_main_patches( + in HS_CONSTANT_FUNC_OUT input, + in OutputPatch patch, + in float2 uv : SV_DomainLocation, + out OutputVertex output ) +{ + float u = uv.x, + v = uv.y; + + float3 p[20]; + for (int i = 0; i < 20; ++i) { + p[i] = patch[i].position.xyz; + } + float3 q[16]; + + float U = 1-u, V=1-v; + + float d11 = u+v; if(u+v==0.0f) d11 = 1.0f; + float d12 = U+v; if(U+v==0.0f) d12 = 1.0f; + float d21 = u+V; if(u+V==0.0f) d21 = 1.0f; + float d22 = U+V; if(U+V==0.0f) d22 = 1.0f; + + q[ 5] = (u*p[3] + v*p[4])/d11; + q[ 6] = (U*p[9] + v*p[8])/d12; + q[ 9] = (u*p[19] + V*p[18])/d21; + q[10] = (U*p[13] + V*p[14])/d22; + + q[ 0] = p[0]; + q[ 1] = p[1]; + q[ 2] = p[7]; + q[ 3] = p[5]; + q[ 4] = p[2]; + q[ 7] = p[6]; + q[ 8] = p[16]; + q[11] = p[12]; + q[12] = p[15]; + q[13] = p[17]; + q[14] = p[11]; + q[15] = p[10]; + + float3 WorldPos = float3(0, 0, 0); + float3 Tangent = float3(0, 0, 0); + float3 BiTangent = float3(0, 0, 0); + +#ifdef OSD_COMPUTE_NORMAL_DERIVATIVES + float B[4], D[4], C[4]; + + float3 BUCP[4] = {float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,0,0)}, + DUCP[4] = {float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,0,0)}, + CUCP[4] = {float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,0,0)}; + + float3 dUU = float3(0, 0, 0); + float3 dVV = float3(0, 0, 0); + float3 dUV = float3(0, 0, 0); + + Univar4x4(u, B, D, C); + + for (int i=0; i<4; ++i) { + for (uint j=0; j<4; ++j) { + // reverse face front + float3 A = q[i + 4*j]; + + BUCP[i] += A * B[j]; + DUCP[i] += A * D[j]; + CUCP[i] += A * C[j]; + } + } + + Univar4x4(v, B, D, C); + + for (int i=0; i<4; ++i) { + WorldPos += B[i] * BUCP[i]; + Tangent += B[i] * DUCP[i]; + BiTangent += D[i] * BUCP[i]; + dUU += B[i] * CUCP[i]; + dVV += C[i] * BUCP[i]; + dUV += D[i] * DUCP[i]; + } + + int level = patch[0].patchCoord.z; + BiTangent *= 3 * level; + Tangent *= 3 * level; + dUU *= 6 * level; + dVV *= 6 * level; + dUV *= 9 * level; + + float3 n = cross(BiTangent, Tangent); + float3 normal = normalize(n); + + float E = dot(Tangent, Tangent); + float F = dot(Tangent, BiTangent); + float G = dot(BiTangent, BiTangent); + float e = dot(normal, dUU); + float f = dot(normal, dUV); + float g = dot(normal, dVV); + + float3 Nu = (f*F-e*G)/(E*G-F*F) * Tangent + (e*F-f*E)/(E*G-F*F) * BiTangent; + float3 Nv = (g*F-f*G)/(E*G-F*F) * Tangent + (f*F-g*E)/(E*G-F*F) * BiTangent; + + Nu = Nu/length(n) - n * (dot(Nu,n)/pow(dot(n,n), 1.5)); + Nv = Nv/length(n) - n * (dot(Nv,n)/pow(dot(n,n), 1.5)); + + output.Nu = Nu; + output.Nv = Nv; + +#else + float B[4], D[4]; + float3 BUCP[4] = {float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,0,0)}, + DUCP[4] = {float3(0,0,0), float3(0,0,0), float3(0,0,0), float3(0,0,0)}; + + Univar4x4(uv.x, B, D); + + for (int i=0; i<4; ++i) { + for (uint j=0; j<4; ++j) { + // reverse face front + float3 A = q[i + 4*j]; + + BUCP[i] += A * B[j]; + DUCP[i] += A * D[j]; + } + } + + Univar4x4(uv.y, B, D); + + for (uint i=0; i<4; ++i) { + WorldPos += B[i] * BUCP[i]; + Tangent += B[i] * DUCP[i]; + BiTangent += D[i] * BUCP[i]; + } + int level = patch[0].patchCoord.z; + BiTangent *= 3 * level; + Tangent *= 3 * level; + + float3 normal = normalize(cross(BiTangent, Tangent)); + +#endif + + output.position = float4(WorldPos, 1.0f); + output.normal = normal; + output.tangent = BiTangent; + output.bitangent = Tangent; + + output.edgeDistance = 0; + + float2 UV = float2(v, u); + output.patchCoord = OsdInterpolatePatchCoord(UV, patch[0].patchCoord); + + OSD_DISPLACEMENT_CALLBACK; + + output.positionOut = mul(OsdProjectionMatrix(), output.position); +} diff --git a/opensubdiv/osd/hlslPatchShaderSource.cpp b/opensubdiv/osd/hlslPatchShaderSource.cpp index 54aa2cd2..21fb4fff 100644 --- a/opensubdiv/osd/hlslPatchShaderSource.cpp +++ b/opensubdiv/osd/hlslPatchShaderSource.cpp @@ -42,6 +42,9 @@ static const char *bsplineShaderSource = static const char *gregoryShaderSource = #include "hlslPatchGregory.gen.h" ; +static const char *gregoryBasisShaderSource = +#include "hlslPatchGregoryBasis.gen.h" +; /*static*/ std::string @@ -61,8 +64,7 @@ HLSLPatchShaderSource::GetVertexShaderSource(Far::PatchDescriptor::Type type) { return std::string("#define OSD_PATCH_GREGORY_BOUNDRY\n") + std::string(gregoryShaderSource); case Far::PatchDescriptor::GREGORY_BASIS: - assert(false); // not implemented yet. - break; + return gregoryBasisShaderSource; default: break; // returns empty (points, lines, quads, ...) } @@ -81,8 +83,7 @@ HLSLPatchShaderSource::GetHullShaderSource(Far::PatchDescriptor::Type type) { return std::string("#define OSD_PATCH_GREGORY_BOUNDRY\n") + std::string(gregoryShaderSource); case Far::PatchDescriptor::GREGORY_BASIS: - assert(false); // not implemented yet. - break; + return gregoryBasisShaderSource; default: break; // returns empty (points, lines, quads, ...) } @@ -101,8 +102,7 @@ HLSLPatchShaderSource::GetDomainShaderSource(Far::PatchDescriptor::Type type) { return std::string("#define OSD_PATCH_GREGORY_BOUNDRY\n") + std::string(gregoryShaderSource); case Far::PatchDescriptor::GREGORY_BASIS: - assert(false); // not implemented yet. - break; + return gregoryBasisShaderSource; default: break; // returns empty (points, lines, quads, ...) }