Add filled occluders to shadow_utils GM, take 2

Classifies fully visible opaque shadows differently
than transparent to avoid cache collisions.

Change-Id: Iba5aab2b2cbe08f70205c343e86fe92b0cab7497
Reviewed-on: https://skia-review.googlesource.com/16858
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2017-05-15 10:44:22 -04:00 committed by Skia Commit-Bot
parent e334c59654
commit 78c8f30d61
2 changed files with 50 additions and 22 deletions

View File

@ -22,7 +22,7 @@ void draw_shadow(SkCanvas* canvas, const SkPath& path, int height, SkColor color
static constexpr int kW = 800; static constexpr int kW = 800;
static constexpr int kH = 800; static constexpr int kH = 800;
DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) { void draw_paths(SkCanvas* canvas, bool hideOccluders) {
SkTArray<SkPath> paths; SkTArray<SkPath> paths;
paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10); paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10);
SkRRect oddRRect; SkRRect oddRRect;
@ -34,7 +34,7 @@ DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
paths.push_back().addOval(SkRect::MakeWH(20, 60)); paths.push_back().addOval(SkRect::MakeWH(20, 60));
static constexpr SkScalar kPad = 15.f; static constexpr SkScalar kPad = 15.f;
static constexpr SkPoint3 kLightPos = {250, 400, 500}; static constexpr SkPoint3 kLightPos = { 250, 400, 500 };
static constexpr SkScalar kLightR = 100.f; static constexpr SkScalar kLightR = 100.f;
static constexpr SkScalar kHeight = 50.f; static constexpr SkScalar kHeight = 50.f;
canvas->translate(3 * kPad, 3 * kPad); canvas->translate(3 * kPad, 3 * kPad);
@ -47,7 +47,7 @@ DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
m->setRotate(33.f, 25.f, 25.f); m->setRotate(33.f, 25.f, 25.f);
m->postScale(1.2f, 0.8f, 25.f, 25.f); m->postScale(1.2f, 0.8f, 25.f, 25.f);
for (auto& m : matrices) { for (auto& m : matrices) {
for (auto flags : {kNone_ShadowFlag, kTransparentOccluder_ShadowFlag}) { for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) {
for (const auto& path : paths) { for (const auto& path : paths) {
SkRect postMBounds = path.getBounds(); SkRect postMBounds = path.getBounds();
m.mapRect(&postMBounds); m.mapRect(&postMBounds);
@ -68,10 +68,22 @@ DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
// Draw the path outline in green on top of the ambient and spot shadows. // Draw the path outline in green on top of the ambient and spot shadows.
SkPaint paint; SkPaint paint;
paint.setColor(SK_ColorGREEN);
paint.setAntiAlias(true); paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style); if (hideOccluders) {
paint.setStrokeWidth(0); if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) {
paint.setColor(SK_ColorCYAN);
} else {
paint.setColor(SK_ColorGREEN);
}
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(0);
} else {
paint.setColor(SK_ColorLTGRAY);
if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) {
paint.setAlpha(128);
}
paint.setStyle(SkPaint::kFill_Style);
}
canvas->drawPath(path, paint); canvas->drawPath(path, paint);
canvas->restore(); canvas->restore();
@ -93,3 +105,11 @@ DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
canvas->restore(); canvas->restore();
} }
} }
DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
draw_paths(canvas, true);
}
DEF_SIMPLE_GM(shadow_utils_occl, canvas, kW, kH) {
draw_paths(canvas, false);
}

View File

@ -181,10 +181,12 @@ struct SpotVerticesFactory {
enum class OccluderType { enum class OccluderType {
// The umbra cannot be dropped out because the occluder is not opaque. // The umbra cannot be dropped out because the occluder is not opaque.
kTransparent, kTransparent,
// The occluder is opaque and the umbra is fully visible
kOpaqueFullUmbra,
// The umbra can be dropped where it is occluded. // The umbra can be dropped where it is occluded.
kOpaque, kOpaquePartialUmbra,
// It is known that the entire umbra is occluded. // It is known that the entire umbra is occluded.
kOpaqueCoversUmbra kOpaqueNoUmbra
}; };
SkVector fOffset; SkVector fOffset;
@ -200,12 +202,13 @@ struct SpotVerticesFactory {
} }
switch (fOccluderType) { switch (fOccluderType) {
case OccluderType::kTransparent: case OccluderType::kTransparent:
case OccluderType::kOpaqueCoversUmbra: case OccluderType::kOpaqueFullUmbra:
case OccluderType::kOpaqueNoUmbra:
// 'this' and 'that' will either both have no umbra removed or both have all the // 'this' and 'that' will either both have no umbra removed or both have all the
// umbra removed. // umbra removed.
*translate = that.fOffset - fOffset; *translate = that.fOffset - fOffset;
return true; return true;
case OccluderType::kOpaque: case OccluderType::kOpaquePartialUmbra:
// In this case we partially remove the umbra differently for 'this' and 'that' // In this case we partially remove the umbra differently for 'this' and 'that'
// if the offsets don't match. // if the offsets don't match.
if (fOffset == that.fOffset) { if (fOffset == that.fOffset) {
@ -642,7 +645,8 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
float zRatio = SkTPin(occluderHeight / (devLightPos.fZ - occluderHeight), 0.0f, 0.95f); float zRatio = SkTPin(occluderHeight / (devLightPos.fZ - occluderHeight), 0.0f, 0.95f);
SkScalar radius = lightRadius * zRatio; SkScalar radius = lightRadius * zRatio;
// Compute the translation for the spot shadow. // Compute the scale and translation for the spot shadow.
SkScalar scale = devLightPos.fZ / (devLightPos.fZ - occluderHeight);
SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY()); SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
viewMatrix.mapPoints(&center, 1); viewMatrix.mapPoints(&center, 1);
factory.fOffset = SkVector::Make(zRatio * (center.fX - devLightPos.fX), factory.fOffset = SkVector::Make(zRatio * (center.fX - devLightPos.fX),
@ -652,17 +656,18 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
factory.fLightRadius = lightRadius; factory.fLightRadius = lightRadius;
SkRect devBounds; SkRect devBounds;
viewMatrix.mapRect(&devBounds, path.getBounds()); viewMatrix.mapRect(&devBounds, path.getBounds());
if (transparent || if (transparent) {
// if the translation of the shadow is big enough we're going to end up
// filling the entire umbra, so we can treat this as transparent
SkTAbs(factory.fOffset.fX) > 0.5f*devBounds.width() ||
SkTAbs(factory.fOffset.fY) > 0.5f*devBounds.height()) {
factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent; factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent;
} else if (factory.fOffset.length() < radius) { } else if (SkTAbs(factory.fOffset.fX) > 0.5f*devBounds.width() ||
SkTAbs(factory.fOffset.fY) > 0.5f*devBounds.height()) {
// if the translation of the shadow is big enough we're going to end up
// filling the entire umbra, so we can treat these as all the same
factory.fOccluderType = SpotVerticesFactory::OccluderType::kOpaqueFullUmbra;
} else if (factory.fOffset.length()*scale + scale < radius) {
// if we don't translate more than the blur distance, can assume umbra is covered // if we don't translate more than the blur distance, can assume umbra is covered
factory.fOccluderType = SpotVerticesFactory::OccluderType::kOpaqueCoversUmbra; factory.fOccluderType = SpotVerticesFactory::OccluderType::kOpaqueNoUmbra;
} else { } else {
factory.fOccluderType = SpotVerticesFactory::OccluderType::kOpaque; factory.fOccluderType = SpotVerticesFactory::OccluderType::kOpaquePartialUmbra;
} }
#ifdef DEBUG_SHADOW_CHECKS #ifdef DEBUG_SHADOW_CHECKS
@ -670,11 +675,14 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoi
case SpotVerticesFactory::OccluderType::kTransparent: case SpotVerticesFactory::OccluderType::kTransparent:
color = 0xFFD2B48C; // tan for transparent color = 0xFFD2B48C; // tan for transparent
break; break;
case SpotVerticesFactory::OccluderType::kOpaque: case SpotVerticesFactory::OccluderType::kOpaqueFullUmbra:
color = 0xFF614126; // brown for umBra
break;
case SpotVerticesFactory::OccluderType::kOpaquePartialUmbra:
color = 0xFFFFA500; // orange for opaque color = 0xFFFFA500; // orange for opaque
break; break;
case SpotVerticesFactory::OccluderType::kOpaqueCoversUmbra: case SpotVerticesFactory::OccluderType::kOpaqueNoUmbra:
color = SK_ColorYELLOW; // corn yellow for covered color = 0xFFE5E500; // corn yellow for covered
break; break;
} }
#endif #endif