Fix alpha contribution to tonal color.

Also adds a tonal color GM, a grayscale mode to shadowutils GM,
and animated alpha to SampleAndroidShadows.

Bug: skia:
Change-Id: I1dcb5cab7e53ffa7a3bf1a07b6ebfed38df1a9ed
Reviewed-on: https://skia-review.googlesource.com/85002
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2017-12-19 13:02:38 -05:00 committed by Skia Commit-Bot
parent faa095e984
commit 744cbb3888
8 changed files with 168 additions and 36 deletions

View File

@ -15,7 +15,6 @@ void draw_shadow(SkCanvas* canvas, const SkPath& path, int height, SkColor color
SkScalar lightR, bool isAmbient, uint32_t flags) {
SkScalar ambientAlpha = isAmbient ? .5f : 0.f;
SkScalar spotAlpha = isAmbient ? 0.f : .5f;
flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag;
SkShadowUtils::DrawShadow(canvas, path, height, lightPos, lightR, ambientAlpha, spotAlpha,
color, flags);
}
@ -23,7 +22,13 @@ void draw_shadow(SkCanvas* canvas, const SkPath& path, int height, SkColor color
static constexpr int kW = 800;
static constexpr int kH = 800;
void draw_paths(SkCanvas* canvas, bool hideOccluders) {
enum ShadowMode {
kDebugColorNoOccluders,
kDebugColorOccluders,
kGrayscale
};
void draw_paths(SkCanvas* canvas, ShadowMode mode) {
SkTArray<SkPath> paths;
paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10);
SkRRect oddRRect;
@ -52,7 +57,7 @@ void draw_paths(SkCanvas* canvas, bool hideOccluders) {
m->setRotate(33.f, 25.f, 25.f);
m->postScale(1.2f, 0.8f, 25.f, 25.f);
for (auto& m : matrices) {
for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) {
for (int flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) {
for (const auto& path : paths) {
SkRect postMBounds = path.getBounds();
m.mapRect(&postMBounds);
@ -68,13 +73,22 @@ void draw_paths(SkCanvas* canvas, bool hideOccluders) {
canvas->save();
canvas->concat(m);
draw_shadow(canvas, path, kHeight, SK_ColorRED, lightPos, kLightR, true, flags);
draw_shadow(canvas, path, kHeight, SK_ColorBLUE, lightPos, kLightR, false, flags);
// Draw the path outline in green on top of the ambient and spot shadows.
if (kDebugColorNoOccluders == mode || kDebugColorOccluders == mode) {
flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag;
draw_shadow(canvas, path, kHeight, SK_ColorRED, lightPos, kLightR,
true, flags);
draw_shadow(canvas, path, kHeight, SK_ColorBLUE, lightPos, kLightR,
false, flags);
} else if (kGrayscale == mode) {
SkShadowUtils::DrawShadow(canvas, path, kHeight, lightPos, kLightR,
0.1f, 0.25f, SK_ColorBLACK, flags);
}
SkPaint paint;
paint.setAntiAlias(true);
if (hideOccluders) {
if (kDebugColorNoOccluders == mode) {
// Draw the path outline in green on top of the ambient and spot shadows.
if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) {
paint.setColor(SK_ColorCYAN);
} else {
@ -83,7 +97,7 @@ void draw_paths(SkCanvas* canvas, bool hideOccluders) {
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(0);
} else {
paint.setColor(SK_ColorLTGRAY);
paint.setColor(kDebugColorOccluders == mode ? SK_ColorLTGRAY : SK_ColorWHITE);
if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) {
paint.setAlpha(128);
}
@ -112,9 +126,13 @@ void draw_paths(SkCanvas* canvas, bool hideOccluders) {
}
DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) {
draw_paths(canvas, true);
draw_paths(canvas, kDebugColorNoOccluders);
}
DEF_SIMPLE_GM(shadow_utils_occl, canvas, kW, kH) {
draw_paths(canvas, false);
draw_paths(canvas, kDebugColorOccluders);
}
DEF_SIMPLE_GM(shadow_utils_gray, canvas, kW, kH) {
draw_paths(canvas, kGrayscale);
}

85
gm/tonalshadows.cpp Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "SkCanvas.h"
#include "SkPath.h"
#include "SkShadowUtils.h"
enum BackgroundMode {
kLightBackground,
kDarkBackground
};
static constexpr int kW = 1225;
static constexpr int kH = 550;
void draw_content(SkCanvas* canvas, BackgroundMode mode) {
const SkScalar kLightWidth = 600;
const SkScalar kAmbientAlpha = 0.03f;
const SkScalar kSpotAlpha = 0.25f;
const SkColor kColors[30] = {
// purples
0xFF3A0072, 0xFF5D0099, 0xFF7F12B2, 0xFFA02AD1, 0xFFC245E5,
0xFFE95AF9, 0xFFFC79F0, 0xFFFDA6F0, 0xFFFFCCF8, 0xFFFFE1F9,
// oranges
0xFFEA3200, 0xFFFF4E00, 0xFFFF7300, 0xFFFF9100, 0xFFFFB000,
0xFFFFCE00, 0xFFFFE000, 0xFFFFF64D, 0xFFFFF98F, 0xFFFFFBCC,
// teals
0xFF004D51, 0xFF066266, 0xFF057F7F, 0xFF009999, 0xFF00B2B2,
0xFF15CCBE, 0xFF25E5CE, 0xFF2CFFE0, 0xFF80FFEA, 0xFFB3FFF0
};
SkPaint paint;
paint.setAntiAlias(true);
if (mode == kDarkBackground) {
canvas->drawColor(0xFF111111);
} else {
canvas->drawColor(0xFFEAEAEA);
}
SkPath path;
path.addRect(SkRect::MakeXYWH(-50, -50, 100, 100));
SkPoint3 lightPos = { 75, -400, 600 };
SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 16);
SkScalar yPos = 75;
for (int row = 0; row < 3; ++row) {
lightPos.fX = 75;
SkScalar xPos = 75;
for (int col = 0; col < 10; ++col) {
paint.setColor(kColors[10 * row + col]);
canvas->save();
canvas->translate(xPos, yPos);
SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
lightPos, kLightWidth,
kAmbientAlpha, kSpotAlpha, paint.getColor(), 0);
canvas->drawPath(path, paint);
canvas->restore();
lightPos.fX += 120;
xPos += 120;
}
lightPos.fY += 200;
yPos += 200;
}
}
DEF_SIMPLE_GM(tonalshadows_light, canvas, kW, kH) {
draw_content(canvas, kLightBackground);
}
DEF_SIMPLE_GM(tonalshadows_dark, canvas, kW, kH) {
draw_content(canvas, kDarkBackground);
}

View File

@ -317,6 +317,7 @@ gm_sources = [
"$_gm/tilemodes.cpp",
"$_gm/tilemodes_scaled.cpp",
"$_gm/tinybitmap.cpp",
"$_gm/tonalshadows.cpp",
"$_gm/transparency.cpp",
"$_gm/typeface.cpp",
"$_gm/variedtext.cpp",

View File

@ -84,9 +84,9 @@ public:
* set the alpha to (S_a + C_a - S_a*C_a).
*
* @param r Red value of color
* @param g Red value of color
* @param b Red value of color
* @param a Red value of color
* @param g Green value of color
* @param b Blue value of color
* @param a Alpha value of color
* @param colorScale Factor to scale color values by
* @param tonalAlpha Value to set alpha to
*/
@ -96,14 +96,28 @@ public:
SkScalar min = SkTMin(SkTMin(r, g), b);
SkScalar luminance = 0.5f*(max + min);
// We get best results with a luminance between 0.3 and 0.5, with smoothstep applied
SkScalar adjustedLuminance = (0.6f - 0.4f*luminance)*luminance*luminance + 0.3f;
// Similarly, we need to tone down the given greyscale alpha depending on how
// much color we're applying.
a -= (0.5f*adjustedLuminance - 0.15f);
// We compute a color alpha value based on the luminance of the color, scaled by an
// adjusted alpha value. We want the following properties to match the UX examples
// (assuming a = 0.25) and to ensure that we have reasonable results when the color
// is black and/or the alpha is 0:
// f(0, a) = 0
// f(luminance, 0) = 0
// f(1, 0.25) = .5
// f(0.5, 0.25) = .4
// f(1, 1) = 1
// The following functions match this as closely as possible.
SkScalar alphaAdjust = (2.6f + (-2.66667f + 1.06667f*a)*a)*a;
SkScalar colorAlpha = (3.544762f + (-4.891428f + 2.3466f*luminance)*luminance)*luminance;
colorAlpha = SkTPin(alphaAdjust*colorAlpha, 0.0f, 1.0f);
*colorScale = adjustedLuminance*(SK_Scalar1 - a);
*tonalAlpha = *colorScale + a;
// Similarly, we set the greyscale alpha based on luminance and alpha so that
// f(0, a) = a
// f(luminance, 0) = 0
// f(1, 0.25) = 0.15
SkScalar greyscaleAlpha = SkTPin(a*(1 - 0.4f*luminance), 0.0f, 1.0f);
*colorScale = colorAlpha*(SK_Scalar1 - greyscaleAlpha);
*tonalAlpha = *colorScale + greyscaleAlpha;
}
};

View File

@ -35,23 +35,27 @@ class ShadowsView : public SampleView {
SkScalar fZDelta;
SkScalar fAnimTranslate;
SkScalar fAnimAngle;
SkScalar fAnimAlpha;
bool fShowAmbient;
bool fShowSpot;
bool fUseAlt;
bool fShowObject;
bool fIgnoreShadowAlpha;
bool fDoAlphaAnimation;
public:
ShadowsView()
: fZDelta(0)
, fAnimTranslate(0)
, fAnimAngle(0)
, fAnimAlpha(1)
, fShowAmbient(true)
, fShowSpot(true)
, fUseAlt(false)
, fShowObject(true)
, fIgnoreShadowAlpha(false) {}
, fIgnoreShadowAlpha(false)
, fDoAlphaAnimation(false) {}
protected:
void onOnceBeforeDraw() override {
@ -99,6 +103,13 @@ protected:
fShowObject = !fShowObject;
handled = true;
break;
case 'N':
fDoAlphaAnimation = !fDoAlphaAnimation;
if (!fDoAlphaAnimation) {
fAnimAlpha = 1;
}
handled = true;
break;
case '>':
fZDelta += 0.5f;
handled = true;
@ -175,38 +186,38 @@ protected:
paint.setColor(SK_ColorWHITE);
canvas->translate(200, 90);
zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta);
this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha,
lightPos, kLightWidth, kSpotAlpha);
this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorRED);
canvas->translate(250, 0);
zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, kAmbientAlpha,
lightPos, kLightWidth, kSpotAlpha);
this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorBLUE);
canvas->translate(-250, 110);
zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta);
this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, kAmbientAlpha,
lightPos, kLightWidth, 0.5f);
this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*0.5f);
paint.setColor(SK_ColorGREEN);
canvas->translate(250, 0);
zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta);
this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha,
lightPos, kLightWidth, kSpotAlpha);
this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorYELLOW);
canvas->translate(-250, 110);
zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, kAmbientAlpha,
lightPos, kLightWidth, kSpotAlpha);
this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
paint.setColor(SK_ColorCYAN);
canvas->translate(250, 0);
zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta);
this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint,
kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
// circular reveal
SkPath tmpPath;
@ -259,7 +270,9 @@ protected:
bool onAnimate(const SkAnimTimer& timer) override {
fAnimTranslate = timer.pingPong(30, 0, 200, -200);
fAnimAngle = timer.pingPong(15, 0, 0, 20);
if (fDoAlphaAnimation) {
fAnimAlpha = timer.pingPong(5, 0, 1, 0);
}
return true;
}

View File

@ -121,6 +121,7 @@ protected:
if (!fShowSpot) {
spotAlpha = 0;
}
flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag;
if (fUseAlt) {
flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
}

View File

@ -1141,7 +1141,7 @@ bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
SkScalar colorScale;
SkScalar tonalAlpha;
SkShadowUtils::ComputeTonalColorParams(color.fRGBA[0], color.fRGBA[1],
color.fRGBA[2], rec.fSpotAlpha,
color.fRGBA[2], color.fRGBA[3]*rec.fSpotAlpha,
&colorScale, &tonalAlpha);
color.fRGBA[0] *= colorScale;
color.fRGBA[1] *= colorScale;

View File

@ -466,7 +466,7 @@ static SkColor compute_render_color(SkColor color, float alpha, bool useTonalCol
SkShadowUtils::ComputeTonalColorParams(color4f.fR,
color4f.fG,
color4f.fB,
alpha,
color4f.fA*alpha,
&colorScale, &tonalAlpha);
// After pre-multiplying, we want the alpha to be scaled by tonalAlpha, and
// the color scaled by colorScale. This scale factor gives that.