mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-23 12:10:08 +00:00
Metal patch shader changes for degenerate normals
Updated Metal patch shaders to resolve degenerate normals. This fix was ported from the GLSL patch shader source. Also, added missing inf sharp test cases to mtlViewer.
This commit is contained in:
parent
3e2f76e6dd
commit
6e02082bd7
@ -57,6 +57,9 @@ static void initShapes() {
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_inf_crease0", catmark_inf_crease0, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_inf_crease1", catmark_inf_crease1, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_flap", catmark_flap, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_flap2", catmark_flap2, kCatmark ) );
|
||||
@ -91,7 +94,6 @@ static void initShapes() {
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_tent", catmark_tent, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_torus", catmark_torus, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark ) );
|
||||
// g_defaultShapes.push_back( ShapeDesc("catmark_square_hedit0", catmark_square_hedit0, kCatmark ) );
|
||||
@ -120,3 +122,4 @@ static void initShapes() {
|
||||
g_defaultShapes.push_back( ShapeDesc("loop_pole64", loop_pole64, kLoop ) );
|
||||
g_defaultShapes.push_back( ShapeDesc("loop_pole360", loop_pole360, kLoop ) );
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -590,6 +590,14 @@ OsdComputeBSplineBoundaryPoints(thread VertexType* cpt, int3 patchParam)
|
||||
}
|
||||
}
|
||||
|
||||
template<typename PerPatchVertexBezier>
|
||||
void
|
||||
OsdEvalPatchBezier(int3 patchParam, float2 UV,
|
||||
PerPatchVertexBezier cv,
|
||||
thread float3& P, thread float3& dPu, thread float3& dPv,
|
||||
thread float3& N, thread float3& dNu, thread float3& dNv,
|
||||
thread float2& vSegments);
|
||||
|
||||
void
|
||||
OsdEvalPatchGregory(int3 patchParam, float2 UV, thread float3* cv,
|
||||
thread float3& P, thread float3& dPu, thread float3& dPv,
|
||||
@ -624,113 +632,28 @@ OsdEvalPatchGregory(int3 patchParam, float2 UV, thread float3* cv,
|
||||
float d21 = u+V;
|
||||
float d22 = U+V;
|
||||
|
||||
float3 q[16];
|
||||
OsdPerPatchVertexBezier bezcv[16];
|
||||
float2 vSegments;
|
||||
|
||||
q[ 5] = (d11 == 0.0) ? cv[3] : (u*cv[3] + v*cv[4])/d11;
|
||||
q[ 6] = (d12 == 0.0) ? cv[8] : (U*cv[9] + v*cv[8])/d12;
|
||||
q[ 9] = (d21 == 0.0) ? cv[18] : (u*cv[19] + V*cv[18])/d21;
|
||||
q[10] = (d22 == 0.0) ? cv[13] : (U*cv[13] + V*cv[14])/d22;
|
||||
bezcv[ 5].P = (d11 == 0.0) ? cv[3] : (u*cv[3] + v*cv[4])/d11;
|
||||
bezcv[ 6].P = (d12 == 0.0) ? cv[8] : (U*cv[9] + v*cv[8])/d12;
|
||||
bezcv[ 9].P = (d21 == 0.0) ? cv[18] : (u*cv[19] + V*cv[18])/d21;
|
||||
bezcv[10].P = (d22 == 0.0) ? cv[13] : (U*cv[13] + V*cv[14])/d22;
|
||||
|
||||
q[ 0] = cv[0];
|
||||
q[ 1] = cv[1];
|
||||
q[ 2] = cv[7];
|
||||
q[ 3] = cv[5];
|
||||
q[ 4] = cv[2];
|
||||
q[ 7] = cv[6];
|
||||
q[ 8] = cv[16];
|
||||
q[11] = cv[12];
|
||||
q[12] = cv[15];
|
||||
q[13] = cv[17];
|
||||
q[14] = cv[11];
|
||||
q[15] = cv[10];
|
||||
bezcv[ 0].P = cv[0];
|
||||
bezcv[ 1].P = cv[1];
|
||||
bezcv[ 2].P = cv[7];
|
||||
bezcv[ 3].P = cv[5];
|
||||
bezcv[ 4].P = cv[2];
|
||||
bezcv[ 7].P = cv[6];
|
||||
bezcv[ 8].P = cv[16];
|
||||
bezcv[11].P = cv[12];
|
||||
bezcv[12].P = cv[15];
|
||||
bezcv[13].P = cv[17];
|
||||
bezcv[14].P = cv[11];
|
||||
bezcv[15].P = cv[10];
|
||||
|
||||
P = float3(0,0,0);
|
||||
dPu = float3(0,0,0);
|
||||
dPv = float3(0,0,0);
|
||||
|
||||
#if 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);
|
||||
|
||||
OsdUnivar4x4(UV.x, B, D, C);
|
||||
|
||||
for (int i=0; i<4; ++i) {
|
||||
for (int j=0; j<4; ++j) {
|
||||
float3 A = q[4*i + j];
|
||||
BUCP[i] += A * B[j];
|
||||
DUCP[i] += A * D[j];
|
||||
CUCP[i] += A * C[j];
|
||||
}
|
||||
}
|
||||
|
||||
OsdUnivar4x4(UV.y, B, D, C);
|
||||
|
||||
for (int i=0; i<4; ++i) {
|
||||
P += B[i] * BUCP[i];
|
||||
dPu += B[i] * DUCP[i];
|
||||
dPv += D[i] * BUCP[i];
|
||||
dUU += B[i] * CUCP[i];
|
||||
dVV += C[i] * BUCP[i];
|
||||
dUV += D[i] * DUCP[i];
|
||||
}
|
||||
|
||||
int level = OsdGetPatchFaceLevel(patchParam);
|
||||
dPu *= 3 * level;
|
||||
dPv *= 3 * level;
|
||||
dUU *= 6 * level;
|
||||
dVV *= 6 * level;
|
||||
dUV *= 9 * level;
|
||||
|
||||
float3 n = cross(dPu, dPv);
|
||||
N = normalize(n);
|
||||
|
||||
float E = dot(dPu, dPu);
|
||||
float F = dot(dPu, dPv);
|
||||
float G = dot(dPv, dPv);
|
||||
float e = dot(N, dUU);
|
||||
float f = dot(N, dUV);
|
||||
float g = dot(N, dVV);
|
||||
|
||||
dNu = (f*F-e*G)/(E*G-F*F) * dPu + (e*F-f*E)/(E*G-F*F) * dPv;
|
||||
dNv = (g*F-f*G)/(E*G-F*F) * dPu + (f*F-g*E)/(E*G-F*F) * dPv;
|
||||
|
||||
dNu = dNu/length(n) - n * (dot(dNu,n)/powr(dot(n,n), 1.5));
|
||||
dNv = dNv/length(n) - n * (dot(dNv,n)/powr(dot(n,n), 1.5));
|
||||
#else //OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
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)};
|
||||
|
||||
OsdUnivar4x4(UV.x, B, D);
|
||||
|
||||
for (int i=0; i<4; ++i) {
|
||||
for (int j=0; j<4; ++j) {
|
||||
float3 A = q[4*i + j];
|
||||
BUCP[i] += A * B[j];
|
||||
DUCP[i] += A * D[j];
|
||||
}
|
||||
}
|
||||
|
||||
OsdUnivar4x4(UV.y, B, D);
|
||||
|
||||
for (int i=0; i<4; ++i) {
|
||||
P += B[i] * BUCP[i];
|
||||
dPu += B[i] * DUCP[i];
|
||||
dPv += D[i] * BUCP[i];
|
||||
}
|
||||
int level = OsdGetPatchFaceLevel(patchParam);
|
||||
dPu *= 3 * level;
|
||||
dPv *= 3 * level;
|
||||
|
||||
N = normalize(cross(dPu, dPv));
|
||||
dNu = float3(0,0,0);
|
||||
dNv = float3(0,0,0);
|
||||
#endif //OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
OsdEvalPatchBezier(patchParam, UV, bezcv, P, dPu, dPv, N, dNu, dNv, vSegments);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1559,20 +1482,30 @@ OsdEvalPatchBezier(int3 patchParam, float2 UV,
|
||||
thread float3& N, thread float3& dNu, thread float3& dNv,
|
||||
thread float2& vSegments)
|
||||
{
|
||||
#if 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)};
|
||||
OsdUnivar4x4(UV.x, B, D, C);
|
||||
#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)};
|
||||
OsdUnivar4x4(UV.x, B, D);
|
||||
#endif
|
||||
//
|
||||
// Use the recursive nature of the basis functions to compute a 2x2 set
|
||||
// of intermediate points (via repeated linear interpolation). These
|
||||
// points define a bilinear surface tangent to the desired surface at P
|
||||
// and so containing dPu and dPv. The cost of computing P, dPu and dPv
|
||||
// this way is comparable to that of typical tensor product evaluation
|
||||
// (if not faster).
|
||||
//
|
||||
// If N = dPu X dPv degenerates, it often results from an edge of the
|
||||
// 2x2 bilinear hull collapsing or two adjacent edges colinear. In both
|
||||
// cases, the expected non-planar quad degenerates into a triangle, and
|
||||
// the tangent plane of that triangle provides the desired normal N.
|
||||
//
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Reduce 4x4 points to 2x4 -- two levels of linear interpolation in U
|
||||
// and so 3 original rows contributing to each of the 2 resulting rows:
|
||||
float u = UV.x;
|
||||
float uinv = 1.0f - u;
|
||||
|
||||
float u0 = uinv * uinv;
|
||||
float u1 = u * uinv * 2.0f;
|
||||
float u2 = u * u;
|
||||
|
||||
float3 LROW[4], RROW[4];
|
||||
#if OSD_PATCH_ENABLE_SINGLE_CREASE
|
||||
#if USE_PTVS_SHARPNESS
|
||||
float sharpness = OsdGetPatchSharpness(patchParam);
|
||||
@ -1580,112 +1513,166 @@ OsdEvalPatchBezier(int3 patchParam, float2 UV,
|
||||
float Sc = ceil(sharpness);
|
||||
float s0 = 1 - exp2(-Sf);
|
||||
float s1 = 1 - exp2(-Sc);
|
||||
|
||||
vSegments = float2(s0, s1);
|
||||
#else //USE_PTVS_SHARPNESS
|
||||
#else // USE_PTVS_SHARPNESS
|
||||
vSegments = cv[0].vSegments;
|
||||
#endif //USE_PTVS_SHARPNESS
|
||||
|
||||
#endif // USE_PTVS_SHARPNESS
|
||||
float s = OsdGetPatchSingleCreaseSegmentParameter(patchParam, UV);
|
||||
|
||||
for (int i=0; i<4; ++i) {
|
||||
for (int j=0; j<4; ++j) {
|
||||
int k = 4*i + j;
|
||||
|
||||
float3 A = (s <= vSegments.x) ? cv[k].P
|
||||
: ((s <= vSegments.y) ? cv[k].P1
|
||||
: cv[k].P2);
|
||||
|
||||
BUCP[i] += A * B[j];
|
||||
DUCP[i] += A * D[j];
|
||||
#if OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
CUCP[i] += A * C[j];
|
||||
#endif //OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
int j = i*4;
|
||||
if (s <= vSegments.x) {
|
||||
LROW[i] = u0 * cv[ j ].P + u1 * cv[j+1].P + u2 * cv[j+2].P;
|
||||
RROW[i] = u0 * cv[j+1].P + u1 * cv[j+2].P + u2 * cv[j+3].P;
|
||||
} else if (s <= vSegments.y) {
|
||||
LROW[i] = u0 * cv[ j ].P1 + u1 * cv[j+1].P1 + u2 * cv[j+2].P1;
|
||||
RROW[i] = u0 * cv[j+1].P1 + u1 * cv[j+2].P1 + u2 * cv[j+3].P1;
|
||||
} else {
|
||||
LROW[i] = u0 * cv[ j ].P2 + u1 * cv[j+1].P2 + u2 * cv[j+2].P2;
|
||||
RROW[i] = u0 * cv[j+1].P2 + u1 * cv[j+2].P2 + u2 * cv[j+3].P2;
|
||||
}
|
||||
}
|
||||
#else //OSD_PATCH_ENABLE_SINGLE_CREASE
|
||||
// ----------------------------------------------------------------
|
||||
for (int i=0; i<4; ++i) {
|
||||
for (int j=0; j<4; ++j) {
|
||||
float3 A = cv[4*i + j].P;
|
||||
BUCP[i] += A * B[j];
|
||||
DUCP[i] += A * D[j];
|
||||
#if OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
CUCP[i] += A * C[j];
|
||||
#endif //OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
}
|
||||
}
|
||||
#endif //OSD_PATCH_ENABLE_SINGLE_CREASE
|
||||
// ----------------------------------------------------------------
|
||||
#else
|
||||
LROW[0] = u0 * cv[ 0].P + u1 * cv[ 1].P + u2 * cv[ 2].P;
|
||||
LROW[1] = u0 * cv[ 4].P + u1 * cv[ 5].P + u2 * cv[ 6].P;
|
||||
LROW[2] = u0 * cv[ 8].P + u1 * cv[ 9].P + u2 * cv[10].P;
|
||||
LROW[3] = u0 * cv[12].P + u1 * cv[13].P + u2 * cv[14].P;
|
||||
|
||||
#if OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
// used for weingarten term
|
||||
OsdUnivar4x4(UV.y, B, D, C);
|
||||
RROW[0] = u0 * cv[ 1].P + u1 * cv[ 2].P + u2 * cv[ 3].P;
|
||||
RROW[1] = u0 * cv[ 5].P + u1 * cv[ 6].P + u2 * cv[ 7].P;
|
||||
RROW[2] = u0 * cv[ 9].P + u1 * cv[10].P + u2 * cv[11].P;
|
||||
RROW[3] = u0 * cv[13].P + u1 * cv[14].P + u2 * cv[15].P;
|
||||
#endif
|
||||
|
||||
P = B[0] * BUCP[0];
|
||||
dPu = B[0] * DUCP[0];
|
||||
dPv = D[0] * BUCP[0];
|
||||
// Reduce 2x4 points to 2x2 -- two levels of linear interpolation in V
|
||||
// and so 3 original pairs contributing to each of the 2 resulting:
|
||||
float v = UV.y;
|
||||
float vinv = 1.0f - v;
|
||||
|
||||
float3 dUU = B[0] * CUCP[0];
|
||||
float3 dVV = C[0] * BUCP[0];
|
||||
float3 dUV = D[0] * DUCP[0];
|
||||
float v0 = vinv * vinv;
|
||||
float v1 = v * vinv * 2.0f;
|
||||
float v2 = v * v;
|
||||
|
||||
for (int k=1; k<4; ++k) {
|
||||
P += B[k] * BUCP[k];
|
||||
dPu += B[k] * DUCP[k];
|
||||
dPv += D[k] * BUCP[k];
|
||||
float3 LPAIR[2], RPAIR[2];
|
||||
LPAIR[0] = v0 * LROW[0] + v1 * LROW[1] + v2 * LROW[2];
|
||||
RPAIR[0] = v0 * RROW[0] + v1 * RROW[1] + v2 * RROW[2];
|
||||
|
||||
dUU += B[k] * CUCP[k];
|
||||
dVV += C[k] * BUCP[k];
|
||||
dUV += D[k] * DUCP[k];
|
||||
}
|
||||
LPAIR[1] = v0 * LROW[1] + v1 * LROW[2] + v2 * LROW[3];
|
||||
RPAIR[1] = v0 * RROW[1] + v1 * RROW[2] + v2 * RROW[3];
|
||||
|
||||
// Interpolate points on the edges of the 2x2 bilinear hull from which
|
||||
// both position and partials are trivially determined:
|
||||
float3 DU0 = vinv * LPAIR[0] + v * LPAIR[1];
|
||||
float3 DU1 = vinv * RPAIR[0] + v * RPAIR[1];
|
||||
float3 DV0 = uinv * LPAIR[0] + u * RPAIR[0];
|
||||
float3 DV1 = uinv * LPAIR[1] + u * RPAIR[1];
|
||||
|
||||
int level = OsdGetPatchFaceLevel(patchParam);
|
||||
dPu *= 3 * level;
|
||||
dPv *= 3 * level;
|
||||
dPu = (DU1 - DU0) * 3 * level;
|
||||
dPv = (DV1 - DV0) * 3 * level;
|
||||
|
||||
P = u * DU1 + uinv * DU0;
|
||||
|
||||
// Compute the normal and test for degeneracy:
|
||||
//
|
||||
// We need a geometric measure of the size of the patch for a suitable
|
||||
// tolerance. Magnitudes of the partials are generally proportional to
|
||||
// that size -- the sum of the partials is readily available, cheap to
|
||||
// compute, and has proved effective in most cases (though not perfect).
|
||||
// The size of the bounding box of the patch, or some approximation to
|
||||
// it, would be better but more costly to compute.
|
||||
//
|
||||
float proportionalNormalTolerance = 0.00001f;
|
||||
|
||||
float nEpsilon = (length(dPu) + length(dPv)) * proportionalNormalTolerance;
|
||||
|
||||
N = cross(dPu, dPv);
|
||||
|
||||
float nLength = length(N);
|
||||
if (nLength > nEpsilon) {
|
||||
N = N / nLength;
|
||||
} else {
|
||||
float3 diagCross = cross(RPAIR[1] - LPAIR[0], LPAIR[1] - RPAIR[0]);
|
||||
float diagCrossLength = length(diagCross);
|
||||
if (diagCrossLength > nEpsilon) {
|
||||
N = diagCross / diagCrossLength;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
dNu = float3(0,0,0);
|
||||
dNv = float3(0,0,0);
|
||||
#else
|
||||
//
|
||||
// Compute 2nd order partials of P(u,v) in order to compute 1st order partials
|
||||
// for the un-normalized n(u,v) = dPu X dPv, then project into the tangent
|
||||
// plane of normalized N. With resulting dNu and dNv we can make another
|
||||
// attempt to resolve a still-degenerate normal.
|
||||
//
|
||||
// We don't use the Weingarten equations here as they require N != 0 and also
|
||||
// are a little less numerically stable/accurate in single precision.
|
||||
//
|
||||
float B0u[4], B1u[4], B2u[4];
|
||||
float B0v[4], B1v[4], B2v[4];
|
||||
|
||||
OsdUnivar4x4(UV.x, B0u, B1u, B2u);
|
||||
OsdUnivar4x4(UV.y, B0v, B1v, B2v);
|
||||
|
||||
float3 dUU = float3(0,0,0);
|
||||
float3 dVV = float3(0,0,0);
|
||||
float3 dUV = float3(0,0,0);
|
||||
|
||||
for (int i=0; i<4; ++i) {
|
||||
for (int j=0; j<4; ++j) {
|
||||
#if OSD_PATCH_ENABLE_SINGLE_CREASE
|
||||
int k = 4*i + j;
|
||||
float3 CV = (s <= vSegments.x) ? cv[k].P
|
||||
: ((s <= vSegments.y) ? cv[k].P1
|
||||
: cv[k].P2);
|
||||
#else
|
||||
float3 CV = cv[4*i + j].P;
|
||||
#endif
|
||||
dUU += (B0v[i] * B2u[j]) * CV;
|
||||
dVV += (B2v[i] * B0u[j]) * CV;
|
||||
dUV += (B1v[i] * B1u[j]) * CV;
|
||||
}
|
||||
}
|
||||
|
||||
dUU *= 6 * level;
|
||||
dVV *= 6 * level;
|
||||
dUV *= 9 * level;
|
||||
|
||||
float3 n = cross(dPu, dPv);
|
||||
float ln = 1.0 / length(n);
|
||||
N = ln * n;
|
||||
dNu = cross(dUU, dPv) + cross(dPu, dUV);
|
||||
dNv = cross(dUV, dPv) + cross(dPu, dVV);
|
||||
|
||||
float E = dot(dPu, dPu);
|
||||
float F = dot(dPu, dPv);
|
||||
float G = dot(dPv, dPv);
|
||||
float e = dot(N, dUU);
|
||||
float f = dot(N, dUV);
|
||||
float g = dot(N, dVV);
|
||||
float EGFF = 1.0 / (E*G - F*F);
|
||||
float nLengthInv = 1.0;
|
||||
if (nLength > nEpsilon) {
|
||||
nLengthInv = 1.0 / nLength;
|
||||
} else {
|
||||
// N may have been resolved above if degenerate, but if N was resolved
|
||||
// we don't have an accurate length for its un-normalized value, and that
|
||||
// length is needed to project the un-normalized dNu and dNv into the
|
||||
// tangent plane of N.
|
||||
//
|
||||
// So compute N more accurately with available second derivatives, i.e.
|
||||
// with a 1st order Taylor approximation to un-normalized N(u,v).
|
||||
|
||||
dNu = (f*F-e*G) * EGFF * dPu + (e*F-f*E) * EGFF * dPv;
|
||||
dNv = (g*F-f*G) * EGFF * dPu + (f*F-g*E) * EGFF * dPv;
|
||||
float DU = (UV.x == 1.0f) ? -1.0f : 1.0f;
|
||||
float DV = (UV.y == 1.0f) ? -1.0f : 1.0f;
|
||||
|
||||
float powrn = 1.0 / powr(dot(n,n), 1.5);
|
||||
N = DU * dNu + DV * dNv;
|
||||
|
||||
dNu = dNu * ln - n * (dot(dNu,n) * powrn);
|
||||
dNv = dNv * ln - n * (dot(dNv,n) * powrn);
|
||||
#else //OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
OsdUnivar4x4(UV.y, B, D);
|
||||
|
||||
P = B[0] * BUCP[0];
|
||||
dPu = B[0] * DUCP[0];
|
||||
dPv = D[0] * BUCP[0];
|
||||
|
||||
for (int k=1; k<4; ++k) {
|
||||
P += B[k] * BUCP[k];
|
||||
dPu += B[k] * DUCP[k];
|
||||
dPv += D[k] * BUCP[k];
|
||||
nLength = length(N);
|
||||
if (nLength > nEpsilon) {
|
||||
nLengthInv = 1.0f / nLength;
|
||||
N = N * nLengthInv;
|
||||
}
|
||||
}
|
||||
int level = OsdGetPatchFaceLevel(patchParam);
|
||||
dPu *= 3 * level;
|
||||
dPv *= 3 * level;
|
||||
|
||||
N = normalize(cross(dPu, dPv));
|
||||
dNu = float3(0,0,0);
|
||||
dNv = float3(0,0,0);
|
||||
#endif //OSD_COMPUTE_NORMAL_DERIVATIVES
|
||||
// Project derivatives of non-unit normals into tangent plane of N:
|
||||
dNu = (dNu - dot(dNu,N) * N) * nLengthInv;
|
||||
dNv = (dNv - dot(dNv,N) * N) * nLengthInv;
|
||||
#endif
|
||||
}
|
||||
|
||||
// compute single-crease patch matrix
|
||||
|
Loading…
Reference in New Issue
Block a user