Add ShadowFlag to use only blurs for concave shapes.
The geometric method for concave shadows seems to be failing in certain cases. See: https://github.com/flutter/flutter/issues/84262. I've never been satisfied with this solution and I've been thinking of removing it. This flag allows for Flutter to disable it for the time being until I can determine if anyone else is using it. Change-Id: Ia0a3f57002d94928f2baa655c88dc4d10b9edef8 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/533881 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
c35e492a19
commit
e8199af1d9
@ -18,8 +18,10 @@ enum SkShadowFlags {
|
||||
kGeometricOnly_ShadowFlag = 0x02,
|
||||
/** Light position represents a direction, light radius is blur radius at elevation 1 */
|
||||
kDirectionalLight_ShadowFlag = 0x04,
|
||||
/** Concave paths will only use blur to generate the shadow */
|
||||
kConcaveBlurOnly_ShadowFlag = 0x08,
|
||||
/** mask for all shadow flags */
|
||||
kAll_ShadowFlag = 0x07
|
||||
kAll_ShadowFlag = 0x0F
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -42,6 +42,7 @@ class ShadowsView : public Sample {
|
||||
bool fShowAmbient = true;
|
||||
bool fShowSpot = true;
|
||||
bool fUseAlt = false;
|
||||
bool fUseBlur = true;
|
||||
bool fShowObject = true;
|
||||
bool fIgnoreShadowAlpha = false;
|
||||
bool fDoAlphaAnimation = false;
|
||||
@ -108,6 +109,10 @@ class ShadowsView : public Sample {
|
||||
fUseAlt = !fUseAlt;
|
||||
handled = true;
|
||||
break;
|
||||
case 'B':
|
||||
fUseBlur = !fUseBlur;
|
||||
handled = true;
|
||||
break;
|
||||
case 'O':
|
||||
fShowObject = !fShowObject;
|
||||
handled = true;
|
||||
@ -158,6 +163,9 @@ class ShadowsView : public Sample {
|
||||
if (fUseAlt) {
|
||||
flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
|
||||
}
|
||||
if (fUseBlur) {
|
||||
flags |= SkShadowFlags::kConcaveBlurOnly_ShadowFlag;
|
||||
}
|
||||
|
||||
SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 0, 0, 0);
|
||||
SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 0);
|
||||
|
@ -668,6 +668,8 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
|
||||
bool tiltZPlane = tilted(rec.fZPlaneParams);
|
||||
bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
|
||||
bool directional = SkToBool(rec.fFlags & SkShadowFlags::kDirectionalLight_ShadowFlag);
|
||||
bool useBlur = SkToBool(rec.fFlags & SkShadowFlags::kConcaveBlurOnly_ShadowFlag) &&
|
||||
!path.isConvex();
|
||||
bool uncached = tiltZPlane || path.isVolatile();
|
||||
|
||||
SkPoint3 zPlaneParams = rec.fZPlaneParams;
|
||||
@ -679,7 +681,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
|
||||
|
||||
if (SkColorGetA(rec.fAmbientColor) > 0) {
|
||||
bool success = false;
|
||||
if (uncached) {
|
||||
if (uncached && !useBlur) {
|
||||
sk_sp<SkVertices> vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix,
|
||||
zPlaneParams,
|
||||
transparent);
|
||||
@ -702,7 +704,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
if (!success && !useBlur) {
|
||||
AmbientVerticesFactory factory;
|
||||
factory.fOccluderHeight = zPlaneParams.fZ;
|
||||
factory.fTransparent = transparent;
|
||||
@ -713,59 +715,62 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
|
||||
factory.fOffset.fY = viewMatrix.getTranslateY();
|
||||
}
|
||||
|
||||
if (!draw_shadow(factory, drawVertsProc, shadowedPath, rec.fAmbientColor)) {
|
||||
// Pretransform the path to avoid transforming the stroke, below.
|
||||
SkPath devSpacePath;
|
||||
path.transform(viewMatrix, &devSpacePath);
|
||||
devSpacePath.setIsVolatile(true);
|
||||
success = draw_shadow(factory, drawVertsProc, shadowedPath, rec.fAmbientColor);
|
||||
}
|
||||
|
||||
// The tesselator outsets by AmbientBlurRadius (or 'r') to get the outer ring of
|
||||
// the tesselation, and sets the alpha on the path to 1/AmbientRecipAlpha (or 'a').
|
||||
//
|
||||
// We want to emulate this with a blur. The full blur width (2*blurRadius or 'f')
|
||||
// can be calculated by interpolating:
|
||||
//
|
||||
// original edge outer edge
|
||||
// | |<---------- r ------>|
|
||||
// |<------|--- f -------------->|
|
||||
// | | |
|
||||
// alpha = 1 alpha = a alpha = 0
|
||||
//
|
||||
// Taking ratios, f/1 = r/a, so f = r/a and blurRadius = f/2.
|
||||
//
|
||||
// We now need to outset the path to place the new edge in the center of the
|
||||
// blur region:
|
||||
//
|
||||
// original new
|
||||
// | |<------|--- r ------>|
|
||||
// |<------|--- f -|------------>|
|
||||
// | |<- o ->|<--- f/2 --->|
|
||||
//
|
||||
// r = o + f/2, so o = r - f/2
|
||||
//
|
||||
// We outset by using the stroker, so the strokeWidth is o/2.
|
||||
//
|
||||
SkScalar devSpaceOutset = SkDrawShadowMetrics::AmbientBlurRadius(zPlaneParams.fZ);
|
||||
SkScalar oneOverA = SkDrawShadowMetrics::AmbientRecipAlpha(zPlaneParams.fZ);
|
||||
SkScalar blurRadius = 0.5f*devSpaceOutset*oneOverA;
|
||||
SkScalar strokeWidth = 0.5f*(devSpaceOutset - blurRadius);
|
||||
// All else has failed, draw with blur
|
||||
if (!success) {
|
||||
// Pretransform the path to avoid transforming the stroke, below.
|
||||
SkPath devSpacePath;
|
||||
path.transform(viewMatrix, &devSpacePath);
|
||||
devSpacePath.setIsVolatile(true);
|
||||
|
||||
// Now draw with blur
|
||||
SkPaint paint;
|
||||
paint.setColor(rec.fAmbientColor);
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
paint.setStyle(SkPaint::kStrokeAndFill_Style);
|
||||
SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(blurRadius);
|
||||
bool respectCTM = false;
|
||||
paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, respectCTM));
|
||||
this->drawPath(devSpacePath, paint);
|
||||
}
|
||||
// The tesselator outsets by AmbientBlurRadius (or 'r') to get the outer ring of
|
||||
// the tesselation, and sets the alpha on the path to 1/AmbientRecipAlpha (or 'a').
|
||||
//
|
||||
// We want to emulate this with a blur. The full blur width (2*blurRadius or 'f')
|
||||
// can be calculated by interpolating:
|
||||
//
|
||||
// original edge outer edge
|
||||
// | |<---------- r ------>|
|
||||
// |<------|--- f -------------->|
|
||||
// | | |
|
||||
// alpha = 1 alpha = a alpha = 0
|
||||
//
|
||||
// Taking ratios, f/1 = r/a, so f = r/a and blurRadius = f/2.
|
||||
//
|
||||
// We now need to outset the path to place the new edge in the center of the
|
||||
// blur region:
|
||||
//
|
||||
// original new
|
||||
// | |<------|--- r ------>|
|
||||
// |<------|--- f -|------------>|
|
||||
// | |<- o ->|<--- f/2 --->|
|
||||
//
|
||||
// r = o + f/2, so o = r - f/2
|
||||
//
|
||||
// We outset by using the stroker, so the strokeWidth is o/2.
|
||||
//
|
||||
SkScalar devSpaceOutset = SkDrawShadowMetrics::AmbientBlurRadius(zPlaneParams.fZ);
|
||||
SkScalar oneOverA = SkDrawShadowMetrics::AmbientRecipAlpha(zPlaneParams.fZ);
|
||||
SkScalar blurRadius = 0.5f*devSpaceOutset*oneOverA;
|
||||
SkScalar strokeWidth = 0.5f*(devSpaceOutset - blurRadius);
|
||||
|
||||
// Now draw with blur
|
||||
SkPaint paint;
|
||||
paint.setColor(rec.fAmbientColor);
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
paint.setStyle(SkPaint::kStrokeAndFill_Style);
|
||||
SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(blurRadius);
|
||||
bool respectCTM = false;
|
||||
paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, respectCTM));
|
||||
this->drawPath(devSpacePath, paint);
|
||||
}
|
||||
}
|
||||
|
||||
if (SkColorGetA(rec.fSpotColor) > 0) {
|
||||
bool success = false;
|
||||
if (uncached) {
|
||||
if (uncached && !useBlur) {
|
||||
sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix,
|
||||
zPlaneParams,
|
||||
devLightPos, lightRadius,
|
||||
@ -790,7 +795,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
if (!success && !useBlur) {
|
||||
SpotVerticesFactory factory;
|
||||
factory.fOccluderHeight = zPlaneParams.fZ;
|
||||
factory.fDevLightPos = devLightPos;
|
||||
@ -856,24 +861,27 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (!draw_shadow(factory, drawVertsProc, shadowedPath, color)) {
|
||||
// draw with blur
|
||||
SkMatrix shadowMatrix;
|
||||
if (!SkDrawShadowMetrics::GetSpotShadowTransform(devLightPos, lightRadius,
|
||||
viewMatrix, zPlaneParams,
|
||||
path.getBounds(), directional,
|
||||
&shadowMatrix, &radius)) {
|
||||
return;
|
||||
}
|
||||
SkAutoDeviceTransformRestore adr2(this, shadowMatrix);
|
||||
success = draw_shadow(factory, drawVertsProc, shadowedPath, color);
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setColor(rec.fSpotColor);
|
||||
SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
|
||||
bool respectCTM = false;
|
||||
paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, respectCTM));
|
||||
this->drawPath(path, paint);
|
||||
// All else has failed, draw with blur
|
||||
if (!success) {
|
||||
SkMatrix shadowMatrix;
|
||||
SkScalar radius;
|
||||
if (!SkDrawShadowMetrics::GetSpotShadowTransform(devLightPos, lightRadius,
|
||||
viewMatrix, zPlaneParams,
|
||||
path.getBounds(), directional,
|
||||
&shadowMatrix, &radius)) {
|
||||
return;
|
||||
}
|
||||
SkAutoDeviceTransformRestore adr2(this, shadowMatrix);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setColor(rec.fSpotColor);
|
||||
SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
|
||||
bool respectCTM = false;
|
||||
paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, sigma, respectCTM));
|
||||
this->drawPath(path, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user