diff options
-rw-r--r-- | include/utils/SkShadowUtils.h | 1 | ||||
-rwxr-xr-x | src/utils/SkShadowTessellator.cpp | 69 | ||||
-rw-r--r-- | src/utils/SkShadowUtils.cpp | 7 |
3 files changed, 43 insertions, 34 deletions
diff --git a/include/utils/SkShadowUtils.h b/include/utils/SkShadowUtils.h index bf804a581f..2385a48075 100644 --- a/include/utils/SkShadowUtils.h +++ b/include/utils/SkShadowUtils.h @@ -28,7 +28,6 @@ public: * @param path The occluder used to generate the shadows. * @param zPlaneParams Values for the plane function which returns the Z offset of the * occluder from the canvas based on local x and y values (the current matrix is not applied). - * If the canvas matrix is not perspective, then only zPlaneParams.fZ is used. * @param lightPos The 3D position of the light relative to the canvas plane. This is * independent of the canvas's current matrix. * @param lightRadius The radius of the disc light. diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp index d8990d344a..0c36c53ffe 100755 --- a/src/utils/SkShadowTessellator.cpp +++ b/src/utils/SkShadowTessellator.cpp @@ -64,7 +64,7 @@ protected: std::function<SkScalar(const SkPoint&)> fTransformedHeightFunc; SkScalar fZOffset; // members for perspective height function - SkPoint3 fPerspZParams; + SkPoint3 fTransformedZParams; SkScalar fPartialDeterminants[3]; // first two points @@ -268,7 +268,7 @@ bool SkBaseShadowTessellator::addArc(const SkVector& nextNormal, bool finishArc) } bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) { - if (!ctm.hasPerspective()) { + if (SkScalarNearlyZero(fZPlaneParams.fX) && SkScalarNearlyZero(fZPlaneParams.fY)) { fTransformedHeightFunc = [this](const SkPoint& p) { return fZPlaneParams.fZ; }; @@ -277,9 +277,8 @@ bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) { if (!ctm.invert(&ctmInverse)) { return false; } - // multiply by transpose - fPerspZParams = SkPoint3::Make( + fTransformedZParams = SkPoint3::Make( ctmInverse[SkMatrix::kMScaleX] * fZPlaneParams.fX + ctmInverse[SkMatrix::kMSkewY] * fZPlaneParams.fY + ctmInverse[SkMatrix::kMPersp0] * fZPlaneParams.fZ, @@ -293,33 +292,41 @@ bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) { ctmInverse[SkMatrix::kMPersp2] * fZPlaneParams.fZ ); - // We use Cramer's rule to solve for the W value for a given post-divide X and Y, - // so pre-compute those values that are independent of X and Y. - // W is det(ctmInverse)/(PD[0]*X + PD[1]*Y + PD[2]) - fPartialDeterminants[0] = ctm[SkMatrix::kMSkewY] * ctm[SkMatrix::kMPersp1] - - ctm[SkMatrix::kMScaleY] * ctm[SkMatrix::kMPersp0]; - fPartialDeterminants[1] = ctm[SkMatrix::kMPersp0] * ctm[SkMatrix::kMSkewX] - - ctm[SkMatrix::kMPersp1] * ctm[SkMatrix::kMScaleX]; - fPartialDeterminants[2] = ctm[SkMatrix::kMScaleX] * ctm[SkMatrix::kMScaleY] - - ctm[SkMatrix::kMSkewX] * ctm[SkMatrix::kMSkewY]; - SkScalar ctmDeterminant = ctm[SkMatrix::kMTransX] * fPartialDeterminants[0] + - ctm[SkMatrix::kMTransY] * fPartialDeterminants[1] + - ctm[SkMatrix::kMPersp2] * fPartialDeterminants[2]; - - // Pre-bake the numerator of Cramer's rule into the zParams to avoid another multiply. - // TODO: this may introduce numerical instability, but I haven't seen any issues yet. - fPerspZParams.fX *= ctmDeterminant; - fPerspZParams.fY *= ctmDeterminant; - fPerspZParams.fZ *= ctmDeterminant; - - fTransformedHeightFunc = [this](const SkPoint& p) { - SkScalar denom = p.fX * fPartialDeterminants[0] + - p.fY * fPartialDeterminants[1] + - fPartialDeterminants[2]; - SkScalar w = SkScalarFastInvert(denom); - return (fPerspZParams.fX * p.fX + fPerspZParams.fY * p.fY + fPerspZParams.fZ)*w + - fZOffset; - }; + if (ctm.hasPerspective()) { + // We use Cramer's rule to solve for the W value for a given post-divide X and Y, + // so pre-compute those values that are independent of X and Y. + // W is det(ctmInverse)/(PD[0]*X + PD[1]*Y + PD[2]) + fPartialDeterminants[0] = ctm[SkMatrix::kMSkewY] * ctm[SkMatrix::kMPersp1] - + ctm[SkMatrix::kMScaleY] * ctm[SkMatrix::kMPersp0]; + fPartialDeterminants[1] = ctm[SkMatrix::kMPersp0] * ctm[SkMatrix::kMSkewX] - + ctm[SkMatrix::kMPersp1] * ctm[SkMatrix::kMScaleX]; + fPartialDeterminants[2] = ctm[SkMatrix::kMScaleX] * ctm[SkMatrix::kMScaleY] - + ctm[SkMatrix::kMSkewX] * ctm[SkMatrix::kMSkewY]; + SkScalar ctmDeterminant = ctm[SkMatrix::kMTransX] * fPartialDeterminants[0] + + ctm[SkMatrix::kMTransY] * fPartialDeterminants[1] + + ctm[SkMatrix::kMPersp2] * fPartialDeterminants[2]; + + // Pre-bake the numerator of Cramer's rule into the zParams to avoid another multiply. + // TODO: this may introduce numerical instability, but I haven't seen any issues yet. + fTransformedZParams.fX *= ctmDeterminant; + fTransformedZParams.fY *= ctmDeterminant; + fTransformedZParams.fZ *= ctmDeterminant; + + fTransformedHeightFunc = [this](const SkPoint& p) { + SkScalar denom = p.fX * fPartialDeterminants[0] + + p.fY * fPartialDeterminants[1] + + fPartialDeterminants[2]; + SkScalar w = SkScalarFastInvert(denom); + return fZOffset + w*(fTransformedZParams.fX * p.fX + + fTransformedZParams.fY * p.fY + + fTransformedZParams.fZ); + }; + } else { + fTransformedHeightFunc = [this](const SkPoint& p) { + return fZOffset + fTransformedZParams.fX * p.fX + + fTransformedZParams.fY * p.fY + fTransformedZParams.fZ; + }; + } } return true; diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index d84c330d07..806c98e68b 100644 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -583,8 +583,11 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi const SkPoint3& devLightPos, SkScalar lightRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, uint32_t flags) { + // check z plane + bool tiltZPlane = !SkScalarNearlyZero(zPlaneParams.fX) || !SkScalarNearlyZero(zPlaneParams.fY); + // try fast paths - bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag); + bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag) || tiltZPlane; if (!skipAnalytic && draw_analytic_shadows(canvas, path, zPlaneParams.fZ, devLightPos, lightRadius, ambientAlpha, spotAlpha, color, flags)) { @@ -598,7 +601,7 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi ShadowedPath shadowedPath(&path, &viewMatrix); bool transparent = SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag); - bool uncached = viewMatrix.hasPerspective() || path.isVolatile(); + bool uncached = tiltZPlane || path.isVolatile(); if (ambientAlpha > 0) { ambientAlpha = SkTMin(ambientAlpha, 1.f); |