aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2017-05-15 13:49:21 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-05-15 18:21:39 +0000
commit4c9b893953a4dddc20edafd7583523c94c01c889 (patch)
treefc37a17cf6cecfbeabf692fbd37027b2739c6cce
parent0ec981ba493e4a1f8d7aad513f3ae9e1f2c14711 (diff)
Allow shadow zParams to be applied to affine transformations
Change-Id: Iedfded98ce82d15945667232fde22d046d5106b3 Reviewed-on: https://skia-review.googlesource.com/16879 Commit-Queue: Jim Van Verth <jvanverth@google.com> Reviewed-by: Mike Reed <reed@google.com>
-rw-r--r--include/utils/SkShadowUtils.h1
-rwxr-xr-xsrc/utils/SkShadowTessellator.cpp69
-rw-r--r--src/utils/SkShadowUtils.cpp7
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);