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>
This commit is contained in:
parent
0ec981ba49
commit
4c9b893953
@ -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.
|
||||
|
@ -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];
|
||||
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.
|
||||
fPerspZParams.fX *= ctmDeterminant;
|
||||
fPerspZParams.fY *= ctmDeterminant;
|
||||
fPerspZParams.fZ *= ctmDeterminant;
|
||||
// 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 (fPerspZParams.fX * p.fX + fPerspZParams.fY * p.fY + fPerspZParams.fZ)*w +
|
||||
fZOffset;
|
||||
};
|
||||
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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user