std::function<SkScalar(const SkPoint&)> fTransformedHeightFunc;
SkScalar fZOffset;
// members for perspective height function
- SkPoint3 fPerspZParams;
+ SkPoint3 fTransformedZParams;
SkScalar fPartialDeterminants[3];
// first two points
}
bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) {
- if (!ctm.hasPerspective()) {
+ if (SkScalarNearlyZero(fZPlaneParams.fX) && SkScalarNearlyZero(fZPlaneParams.fY)) {
fTransformedHeightFunc = [this](const SkPoint& p) {
return fZPlaneParams.fZ;
};
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,
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;
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)) {
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);