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:
parent
faa095e984
commit
744cbb3888
@ -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
85
gm/tonalshadows.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,7 @@ protected:
|
||||
if (!fShowSpot) {
|
||||
spotAlpha = 0;
|
||||
}
|
||||
flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag;
|
||||
if (fUseAlt) {
|
||||
flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user