Add alternative spot shadow to Android shadow sample
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2246273003 Review-Url: https://codereview.chromium.org/2256713002
This commit is contained in:
parent
28341fad84
commit
d7315f9133
@ -25,15 +25,15 @@ class ShadowsView : public SampleView {
|
||||
SkPoint3 fLightPos;
|
||||
|
||||
bool fShowAmbient;
|
||||
bool fUseAltAmbient;
|
||||
bool fShowSpot;
|
||||
bool fUseAlt;
|
||||
bool fShowObject;
|
||||
|
||||
public:
|
||||
ShadowsView()
|
||||
: fShowAmbient(true)
|
||||
, fUseAltAmbient(true)
|
||||
, fShowSpot(true)
|
||||
, fUseAlt(true)
|
||||
, fShowObject(true) {}
|
||||
|
||||
protected:
|
||||
@ -41,7 +41,7 @@ protected:
|
||||
fCirclePath.addCircle(0, 0, 50);
|
||||
fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
|
||||
fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
|
||||
fLightPos = SkPoint3::Make(-220, -330, 150);
|
||||
fLightPos = SkPoint3::Make(-2, -2, 6);
|
||||
}
|
||||
|
||||
// overrides from SkEventSink
|
||||
@ -57,12 +57,12 @@ protected:
|
||||
case 'B':
|
||||
fShowAmbient = !fShowAmbient;
|
||||
break;
|
||||
case 'T':
|
||||
fUseAltAmbient = !fUseAltAmbient;
|
||||
break;
|
||||
case 'S':
|
||||
fShowSpot = !fShowSpot;
|
||||
break;
|
||||
case 'T':
|
||||
fUseAlt = !fUseAlt;
|
||||
break;
|
||||
case 'O':
|
||||
fShowObject = !fShowObject;
|
||||
break;
|
||||
@ -143,64 +143,48 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
SkRect pathRect;
|
||||
SkRRect pathRRect;
|
||||
if ((!path.isOval(&pathRect) || pathRect.width() != pathRect.height()) &&
|
||||
(!path.isRRect(&pathRRect) || !pathRRect.allCornersCircular()) &&
|
||||
!path.isRect(&pathRect)) {
|
||||
this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
|
||||
return;
|
||||
}
|
||||
|
||||
const SkScalar kHeightFactor = 1.f / 128.f;
|
||||
const SkScalar kGeomFactor = 64;
|
||||
|
||||
SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
|
||||
SkScalar radius = zValue*kHeightFactor*kGeomFactor;
|
||||
|
||||
// fast path
|
||||
SkRect pathRect;
|
||||
SkRRect pathRRect;
|
||||
if ((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
|
||||
(path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
|
||||
path.isRect(&pathRect)) {
|
||||
|
||||
// For all of these, we outset the rect by half the radius to get our stroke shape.
|
||||
if (path.isOval(nullptr)) {
|
||||
pathRect.outset(0.5f*radius, 0.5f*radius);
|
||||
pathRRect = SkRRect::MakeOval(pathRect);
|
||||
} else if (path.isRect(nullptr)) {
|
||||
pathRect.outset(0.5f*radius, 0.5f*radius);
|
||||
pathRRect = SkRRect::MakeRectXY(pathRect, 0.5f*radius, 0.5f*radius);
|
||||
} else {
|
||||
pathRRect.outset(0.5f*radius, 0.5f*radius);
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(SkColorSetARGB((unsigned char)(ambientAlpha*umbraAlpha*255.999f),
|
||||
0, 0, 0));
|
||||
paint.setStrokeWidth(radius);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
|
||||
paint.setShader(SkGaussianEdgeShader::Make());
|
||||
canvas->drawRRect(pathRRect, paint);
|
||||
// For all of these, we outset the rect by the radius to get our coverage shape.
|
||||
if (path.isOval(nullptr)) {
|
||||
pathRect.outset(radius, radius);
|
||||
pathRRect = SkRRect::MakeOval(pathRect);
|
||||
} else if (path.isRect(nullptr)) {
|
||||
pathRect.outset(radius, radius);
|
||||
pathRRect = SkRRect::MakeRectXY(pathRect, radius, radius);
|
||||
} else {
|
||||
// occlude blur
|
||||
SkRect occlRect;
|
||||
GetOcclRect(path, &occlRect);
|
||||
sk_sp<SkMaskFilter> f = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
|
||||
SkBlurMask::ConvertRadiusToSigma(radius),
|
||||
occlRect,
|
||||
SkBlurMaskFilter::kNone_BlurFlag);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setMaskFilter(std::move(f));
|
||||
paint.setColor(SkColorSetARGB((unsigned char)(ambientAlpha*umbraAlpha*255.999f),
|
||||
0, 0, 0));
|
||||
canvas->drawPath(path, paint);
|
||||
|
||||
// draw occlusion rect
|
||||
#if DRAW_OCCL_RECT
|
||||
SkPaint stroke;
|
||||
stroke.setStyle(SkPaint::kStroke_Style);
|
||||
stroke.setColor(SK_ColorBLUE);
|
||||
canvas->drawRect(occlRect, stroke);
|
||||
#endif
|
||||
pathRRect.outset(radius, radius);
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
// handle scale of radius due to CTM
|
||||
SkScalar maxScale = canvas->getTotalMatrix().getMaxScale();
|
||||
radius *= maxScale;
|
||||
unsigned char gray = (unsigned char)(ambientAlpha*umbraAlpha*255.999f);
|
||||
SkASSERT(radius < 256);
|
||||
// convert the radius to fixed point 8.8 and
|
||||
// place it in the G,B components of the color
|
||||
unsigned char intPart = (unsigned char)radius;
|
||||
SkScalar fracPart = radius - intPart;
|
||||
paint.setColor(SkColorSetARGB(1, gray, intPart, (unsigned char)(fracPart*256.f)));
|
||||
|
||||
sk_sp<SkShader> gaussShader = std::move(SkGaussianEdgeShader::Make());
|
||||
paint.setShader(gaussShader);
|
||||
canvas->drawRRect(pathRRect, paint);
|
||||
}
|
||||
|
||||
void drawSpotShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
|
||||
@ -235,10 +219,19 @@ protected:
|
||||
GetOcclRect(path, &occlRect);
|
||||
// apply inverse transform
|
||||
occlRect.offset(-offset);
|
||||
#if 0
|
||||
// It looks like the scale may be invalid
|
||||
SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
|
||||
if (scale < 1.0f) {
|
||||
scale = 1.0f;
|
||||
} else if (scale > 1024.f) {
|
||||
scale = 1024.f;
|
||||
}
|
||||
occlRect.fLeft /= scale;
|
||||
occlRect.fRight /= scale;
|
||||
occlRect.fTop /= scale;
|
||||
occlRect.fBottom /= scale;
|
||||
#endif
|
||||
sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
|
||||
SkBlurMask::ConvertRadiusToSigma(radius),
|
||||
occlRect,
|
||||
@ -251,7 +244,10 @@ protected:
|
||||
|
||||
// apply transformation to shadow
|
||||
canvas->translate(offset.fX, offset.fY);
|
||||
#if 0
|
||||
// It looks like the scale may be invalid
|
||||
canvas->scale(scale, scale);
|
||||
#endif
|
||||
canvas->drawPath(path, paint);
|
||||
|
||||
// draw occlusion rect
|
||||
@ -263,21 +259,93 @@ protected:
|
||||
#endif
|
||||
}
|
||||
|
||||
void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
|
||||
const SkPaint& paint) {
|
||||
const SkScalar kLightWidth = 3;
|
||||
const SkScalar kAmbientAlpha = 0.25f;
|
||||
const SkScalar kSpotAlpha = 0.25f;
|
||||
void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
|
||||
SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
|
||||
if (spotAlpha <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkRect pathRect;
|
||||
SkRRect pathRRect;
|
||||
if ((!path.isOval(&pathRect) || pathRect.width() != pathRect.height()) &&
|
||||
(!path.isRRect(&pathRRect) || !pathRRect.allCornersCircular()) &&
|
||||
!path.isRect(&pathRect)) {
|
||||
this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
|
||||
return;
|
||||
}
|
||||
|
||||
SkScalar zRatio = zValue / (lightPos.fZ - zValue);
|
||||
if (zRatio < 0.0f) {
|
||||
zRatio = 0.0f;
|
||||
} else if (zRatio > 0.95f) {
|
||||
zRatio = 0.95f;
|
||||
}
|
||||
SkScalar radius = lightWidth*zRatio;
|
||||
|
||||
// For all of these, we outset the rect by the radius to get our coverage shape.
|
||||
if (path.isOval(nullptr)) {
|
||||
pathRect.outset(radius, radius);
|
||||
pathRRect = SkRRect::MakeOval(pathRect);
|
||||
} else if (path.isRect(nullptr)) {
|
||||
pathRect.outset(radius, radius);
|
||||
pathRRect = SkRRect::MakeRectXY(pathRect, radius, radius);
|
||||
} else {
|
||||
pathRRect.outset(radius, radius);
|
||||
}
|
||||
|
||||
// compute the transformation params
|
||||
SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
|
||||
canvas->getTotalMatrix().mapPoints(¢er, 1);
|
||||
SkPoint offset = SkPoint::Make(-zRatio*(lightPos.fX - center.fX),
|
||||
-zRatio*(lightPos.fY - center.fY));
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
sk_sp<SkShader> gaussShader = std::move(SkGaussianEdgeShader::Make());
|
||||
paint.setShader(gaussShader);
|
||||
// handle scale of radius due to CTM
|
||||
SkScalar maxScale = canvas->getTotalMatrix().getMaxScale();
|
||||
radius *= maxScale;
|
||||
unsigned char gray = (unsigned char)(spotAlpha*255.999f);
|
||||
SkASSERT(radius < 256);
|
||||
// convert the radius to fixed point 8.8 and
|
||||
// place it in the G,B components of the color
|
||||
unsigned char intPart = (unsigned char)radius;
|
||||
SkScalar fracPart = radius - intPart;
|
||||
paint.setColor(SkColorSetARGB(1, gray, intPart, (unsigned char)(fracPart*256.f)));
|
||||
|
||||
// apply transformation to shadow
|
||||
canvas->translate(offset.fX, offset.fY);
|
||||
#if 0
|
||||
// It looks like the scale may be invalid
|
||||
SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
|
||||
if (scale < 1.0f) {
|
||||
scale = 1.0f;
|
||||
} else if (scale > 1024.f) {
|
||||
scale = 1024.f;
|
||||
}
|
||||
canvas->scale(scale, scale);
|
||||
#endif
|
||||
canvas->drawRRect(pathRRect, paint);
|
||||
}
|
||||
|
||||
void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
|
||||
const SkPaint& paint, SkScalar ambientAlpha,
|
||||
const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
|
||||
if (fShowAmbient) {
|
||||
if (fUseAltAmbient) {
|
||||
this->drawAmbientShadowAlt(canvas, path, zValue, kAmbientAlpha);
|
||||
if (fUseAlt) {
|
||||
this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
|
||||
} else {
|
||||
this->drawAmbientShadow(canvas, path, zValue, kAmbientAlpha);
|
||||
this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
|
||||
}
|
||||
}
|
||||
if (fShowSpot) {
|
||||
this->drawSpotShadow(canvas, path, zValue, fLightPos, kLightWidth, kSpotAlpha);
|
||||
if (fUseAlt) {
|
||||
this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
|
||||
} else {
|
||||
this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
|
||||
}
|
||||
}
|
||||
if (fShowObject) {
|
||||
canvas->drawPath(path, paint);
|
||||
@ -286,25 +354,40 @@ protected:
|
||||
|
||||
void onDrawContent(SkCanvas* canvas) override {
|
||||
this->drawBG(canvas);
|
||||
const SkScalar kLightWidth = 3;
|
||||
const SkScalar kAmbientAlpha = 0.25f;
|
||||
const SkScalar kSpotAlpha = 0.25f;
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
SkPoint3 lightPos = fLightPos;
|
||||
|
||||
paint.setColor(SK_ColorWHITE);
|
||||
canvas->translate(200, 90);
|
||||
this->drawShadowedPath(canvas, fRectPath, 5, paint);
|
||||
lightPos.fX += 200;
|
||||
lightPos.fY += 90;
|
||||
this->drawShadowedPath(canvas, fRectPath, 5, paint, kAmbientAlpha,
|
||||
lightPos, kLightWidth, kSpotAlpha);
|
||||
|
||||
paint.setColor(SK_ColorRED);
|
||||
canvas->translate(250, 0);
|
||||
this->drawShadowedPath(canvas, fRRPath, 5, paint);
|
||||
lightPos.fX += 250;
|
||||
this->drawShadowedPath(canvas, fRRPath, 5, paint, kAmbientAlpha,
|
||||
lightPos, kLightWidth, kSpotAlpha);
|
||||
|
||||
paint.setColor(SK_ColorBLUE);
|
||||
canvas->translate(-250, 110);
|
||||
this->drawShadowedPath(canvas, fCirclePath, 5, paint);
|
||||
lightPos.fX -= 250;
|
||||
lightPos.fY += 110;
|
||||
this->drawShadowedPath(canvas, fCirclePath, 5, paint, 0.0f,
|
||||
lightPos, kLightWidth, 0.5f);
|
||||
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
canvas->translate(250, 0);
|
||||
this->drawShadowedPath(canvas, fRRPath, 5, paint);
|
||||
lightPos.fX += 250;
|
||||
this->drawShadowedPath(canvas, fRRPath, 5, paint, kAmbientAlpha,
|
||||
lightPos, kLightWidth, kSpotAlpha);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -11,6 +11,10 @@
|
||||
|
||||
/** \class SkGaussianEdgeShaderImpl
|
||||
This subclass of shader applies a Gaussian to shadow edge
|
||||
|
||||
The radius of the Gaussian blur is specified by the g and b values of the color,
|
||||
where g is the integer component and b is the fractional component. The r value
|
||||
represents the max final alpha.
|
||||
*/
|
||||
class SkGaussianEdgeShaderImpl : public SkShader {
|
||||
public:
|
||||
@ -65,20 +69,13 @@ public:
|
||||
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
|
||||
fragBuilder->codeAppendf("vec4 output = %s;", args.fInputColor);
|
||||
// outside the outer edge
|
||||
fragBuilder->codeAppendf("if (%s.z <= 0) {", fragBuilder->distanceVectorName());
|
||||
fragBuilder->codeAppend("output *= 0.0;");
|
||||
// inside the stroke
|
||||
fragBuilder->codeAppendf("} else if (%s.w > 0) {", fragBuilder->distanceVectorName());
|
||||
fragBuilder->codeAppendf("float factor = %s.w/(%s.z + %s.w);",
|
||||
fragBuilder->distanceVectorName(),
|
||||
fragBuilder->distanceVectorName(),
|
||||
fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
|
||||
fragBuilder->codeAppend("float radius = color.g*255.0 + color.b;");
|
||||
|
||||
fragBuilder->codeAppendf("float factor = 1.0 - clamp(%s.z/radius, 0.0, 1.0);",
|
||||
fragBuilder->distanceVectorName());
|
||||
fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
|
||||
fragBuilder->codeAppend("output *= factor;");
|
||||
fragBuilder->codeAppend("}");
|
||||
fragBuilder->codeAppendf("%s = output;", args.fOutputColor);
|
||||
fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.r);", args.fOutputColor);
|
||||
}
|
||||
|
||||
static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
|
||||
|
Loading…
Reference in New Issue
Block a user