Fix star artifact in SkRRectsGaussianEdgeShader
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3360 Change-Id: I791ae5f44a88ac3e4debdf1d4092c605acdf4969 Reviewed-on: https://skia-review.googlesource.com/3360 Reviewed-by: Jim Van Verth <jvanverth@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
16adfa3933
commit
40085e62ba
@ -19,7 +19,7 @@ constexpr int kNumCols = 2;
|
||||
constexpr int kNumRows = 5;
|
||||
constexpr int kCellSize = 128;
|
||||
constexpr SkScalar kPad = 8.0f;
|
||||
constexpr SkScalar kBlurRadius = 8.0f;
|
||||
constexpr SkScalar kInitialBlurRadius = 8.0f;
|
||||
constexpr SkScalar kPeriod = 8.0f;
|
||||
constexpr int kClipOffset = 32;
|
||||
|
||||
@ -292,7 +292,11 @@ public:
|
||||
|
||||
static const int kModeCount = kLast_Mode + 1;
|
||||
|
||||
RevealGM() : fFraction(0.5f), fMode(kRRectsGaussianEdge_Mode), fPause(false) {
|
||||
RevealGM()
|
||||
: fFraction(0.5f)
|
||||
, fMode(kRRectsGaussianEdge_Mode)
|
||||
, fPause(false)
|
||||
, fBlurRadius(kInitialBlurRadius) {
|
||||
this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
|
||||
}
|
||||
|
||||
@ -349,14 +353,15 @@ protected:
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
// G channel is an F6.2 radius
|
||||
paint.setColor(SkColorSetARGB(255, 0, (unsigned char)(4*kBlurRadius), 0));
|
||||
int iBlurRad = (int)(4.0f * fBlurRadius);
|
||||
paint.setColor(SkColorSetARGB(255, iBlurRad >> 8, iBlurRad & 0xFF, 0));
|
||||
paint.setShader(SkGaussianEdgeShader::Make());
|
||||
drawObj->draw(canvas, paint);
|
||||
canvas->restore();
|
||||
} else if (kBlurMask_Mode == fMode) {
|
||||
SkPath clippedPath;
|
||||
|
||||
SkScalar sigma = kBlurRadius / 4.0f;
|
||||
SkScalar sigma = fBlurRadius / 4.0f;
|
||||
|
||||
if (clipObj->contains(drawObj->bounds())) {
|
||||
clippedPath = drawObj->asPath(2.0f*sigma);
|
||||
@ -383,7 +388,7 @@ protected:
|
||||
|
||||
if (clipObj->asRRect(&clipRR) && drawObj->asRRect(&drawnRR)) {
|
||||
paint.setShader(SkRRectsGaussianEdgeShader::Make(clipRR, drawnRR,
|
||||
kBlurRadius));
|
||||
fBlurRadius));
|
||||
}
|
||||
|
||||
canvas->drawRect(cover, paint);
|
||||
@ -408,6 +413,12 @@ protected:
|
||||
case 'C':
|
||||
fMode = (Mode)((fMode + 1) % kModeCount);
|
||||
return true;
|
||||
case '+':
|
||||
fBlurRadius += 1.0f;
|
||||
return true;
|
||||
case '-':
|
||||
fBlurRadius = SkTMax(1.0f, fBlurRadius - 1.0f);
|
||||
return true;
|
||||
case 'p':
|
||||
fPause = !fPause;
|
||||
return true;
|
||||
@ -427,6 +438,7 @@ private:
|
||||
SkScalar fFraction;
|
||||
Mode fMode;
|
||||
bool fPause;
|
||||
float fBlurRadius;
|
||||
|
||||
typedef GM INHERITED;
|
||||
};
|
||||
|
@ -111,8 +111,9 @@ public:
|
||||
const char* outputName,
|
||||
const char indices[2]) { // how to access the params for the 2 rrects
|
||||
|
||||
// positive distance is towards the center of the circle
|
||||
fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;",
|
||||
// Positive distance is towards the center of the circle.
|
||||
// Map all the cases to the lower right quadrant.
|
||||
fragBuilder->codeAppendf("vec2 delta = abs(%s.xy - %s.%s);",
|
||||
fragBuilder->fragmentPosition(), posName, indices);
|
||||
|
||||
switch (mode) {
|
||||
@ -126,44 +127,95 @@ public:
|
||||
break;
|
||||
case kRect_Mode:
|
||||
fragBuilder->codeAppendf(
|
||||
"vec2 rectDist = vec2(1.0 - clamp((%s.%c - abs(delta.x))/%s, 0.0, 1.0),"
|
||||
"1.0 - clamp((%s.%c - abs(delta.y))/%s, 0.0, 1.0));",
|
||||
"vec2 rectDist = vec2(1.0 - clamp((%s.%c - delta.x)/%s, 0.0, 1.0),"
|
||||
"1.0 - clamp((%s.%c - delta.y)/%s, 0.0, 1.0));",
|
||||
sizesName, indices[0], radName,
|
||||
sizesName, indices[1], radName);
|
||||
fragBuilder->codeAppendf("%s = clamp(1.0 - length(rectDist), 0.0, 1.0);",
|
||||
outputName);
|
||||
break;
|
||||
case kSimpleCircular_Mode:
|
||||
// For the circular round rect we first compute the distance
|
||||
// to the rect. Then we compute a multiplier that is 1 if the
|
||||
// point is in one of the circular corners. We then compute the
|
||||
// distance from the corner and then use the multiplier to mask
|
||||
// between the two distances.
|
||||
fragBuilder->codeAppendf("float xDist = clamp((%s.%c - abs(delta.x))/%s,"
|
||||
"0.0, 1.0);",
|
||||
// For the circular round rect we combine 2 distances:
|
||||
// the fractional position from the corner inset point to the corner's circle
|
||||
// the minimum perpendicular distance to the bounding rectangle
|
||||
// The first distance is used when the pixel is inside the ice-cream-cone-shaped
|
||||
// portion of a corner. The second is used everywhere else.
|
||||
// This is intended to approximate the interpolation pattern if we had tessellated
|
||||
// this geometry into a RRect outside and a rect inside.
|
||||
|
||||
//----------------
|
||||
// rect distance computation
|
||||
fragBuilder->codeAppendf("float xDist = (%s.%c - delta.x) / %s;",
|
||||
sizesName, indices[0], radName);
|
||||
fragBuilder->codeAppendf("float yDist = clamp((%s.%c - abs(delta.y))/%s,"
|
||||
"0.0, 1.0);",
|
||||
fragBuilder->codeAppendf("float yDist = (%s.%c - delta.y) / %s;",
|
||||
sizesName, indices[1], radName);
|
||||
fragBuilder->codeAppend("float rectDist = min(xDist, yDist);");
|
||||
fragBuilder->codeAppend("float rectDist = clamp(min(xDist, yDist), 0.0, 1.0);");
|
||||
|
||||
fragBuilder->codeAppendf("vec2 cornerCenter = %s.%s - %s.%s;",
|
||||
sizesName, indices, radiiName, indices);
|
||||
fragBuilder->codeAppend("delta = vec2(abs(delta.x) - cornerCenter.x,"
|
||||
"abs(delta.y) - cornerCenter.y);");
|
||||
fragBuilder->codeAppendf("xDist = %s.%c - abs(delta.x);", radiiName, indices[0]);
|
||||
fragBuilder->codeAppendf("yDist = %s.%c - abs(delta.y);", radiiName, indices[1]);
|
||||
fragBuilder->codeAppend("float cornerDist = min(xDist, yDist);");
|
||||
fragBuilder->codeAppend("float multiplier = step(0.0, cornerDist);");
|
||||
//----------------
|
||||
// ice-cream-cone fractional distance computation
|
||||
|
||||
fragBuilder->codeAppendf("delta += %s.%s;", radiiName, indices);
|
||||
// When the blurRadius is larger than the corner radius we want to use it to
|
||||
// compute the pointy end of the ice cream cone. If it smaller we just want to use
|
||||
// the center of the corner's circle. When using the blurRadius the inset amount
|
||||
// can't exceed the halfwidths of the RRect.
|
||||
fragBuilder->codeAppendf("float insetDist = min(max(%s, %s.%c),min(%s.%c, %s.%c));",
|
||||
radName, radiiName, indices[0],
|
||||
sizesName, indices[0], sizesName, indices[1]);
|
||||
// "maxValue" is a correction term for if the blurRadius is larger than the
|
||||
// size of the RRect. In that case we don't want to go all the way to black.
|
||||
fragBuilder->codeAppendf("float maxValue = insetDist/%s;", radName);
|
||||
|
||||
fragBuilder->codeAppendf("cornerDist = clamp((2.0 * %s.%c - length(delta))/%s,"
|
||||
"0.0, 1.0);",
|
||||
radiiName, indices[0], radName);
|
||||
fragBuilder->codeAppendf("vec2 coneBottom = vec2(%s.%c - insetDist,"
|
||||
"%s.%c - insetDist);",
|
||||
sizesName, indices[0], sizesName, indices[1]);
|
||||
|
||||
fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +"
|
||||
"((1.0-multiplier) * rectDist);",
|
||||
fragBuilder->codeAppendf("vec2 cornerTop = vec2(%s.%c - %s.%c, %s.%c) -"
|
||||
"coneBottom;",
|
||||
sizesName, indices[0], radiiName, indices[0],
|
||||
sizesName, indices[1]);
|
||||
fragBuilder->codeAppendf("vec2 cornerRight = vec2(%s.%c, %s.%c - %s.%c) -"
|
||||
"coneBottom;",
|
||||
sizesName, indices[0],
|
||||
sizesName, indices[1], radiiName, indices[1]);
|
||||
|
||||
fragBuilder->codeAppend("vec2 ptInConeSpace = delta - coneBottom;");
|
||||
fragBuilder->codeAppend("float distToPtInConeSpace = length(ptInConeSpace);");
|
||||
|
||||
fragBuilder->codeAppend("float cross1 = ptInConeSpace.x * cornerTop.y -"
|
||||
"ptInConeSpace.y * cornerTop.x;");
|
||||
fragBuilder->codeAppend("float cross2 = -ptInConeSpace.x * cornerRight.y + "
|
||||
"ptInConeSpace.y * cornerRight.x;");
|
||||
|
||||
fragBuilder->codeAppend("float inCone = step(0.0, cross1) * step(0.0, cross2);");
|
||||
|
||||
fragBuilder->codeAppendf("vec2 cornerCenterInConeSpace = vec2(insetDist - %s.%c);",
|
||||
radiiName, indices[0]);
|
||||
|
||||
fragBuilder->codeAppend("vec2 connectingVec = ptInConeSpace -"
|
||||
"cornerCenterInConeSpace;");
|
||||
fragBuilder->codeAppend("ptInConeSpace = normalize(ptInConeSpace);");
|
||||
|
||||
// "a" (i.e., dot(ptInConeSpace, ptInConeSpace) should always be 1.0f since
|
||||
// ptInConeSpace is now normalized
|
||||
fragBuilder->codeAppend("float b = 2.0 * dot(ptInConeSpace, connectingVec);");
|
||||
fragBuilder->codeAppendf("float c = dot(connectingVec, connectingVec) - "
|
||||
"%s.%c * %s.%c;",
|
||||
radiiName, indices[0], radiiName, indices[0]);
|
||||
|
||||
fragBuilder->codeAppend("float fourAC = 4*c;");
|
||||
// This max prevents sqrt(-1) when outside the cone
|
||||
fragBuilder->codeAppend("float bSq = max(b*b, fourAC);");
|
||||
|
||||
// lop off negative values that are outside the cone
|
||||
fragBuilder->codeAppend("float coneDist = max(0.0, "
|
||||
"0.5 * (-b + sqrt(bSq - fourAC)));");
|
||||
// make the coneDist a fraction of how far it is from the edge to the cone's base
|
||||
fragBuilder->codeAppend("coneDist = (maxValue*coneDist) /"
|
||||
"(coneDist+distToPtInConeSpace);");
|
||||
fragBuilder->codeAppend("coneDist = clamp(coneDist, 0.0, 1.0);");
|
||||
|
||||
//----------------
|
||||
fragBuilder->codeAppendf("%s = (inCone * coneDist) + ((1.0-inCone) * rectDist);",
|
||||
outputName);
|
||||
break;
|
||||
}
|
||||
@ -247,10 +299,8 @@ public:
|
||||
// This is a bit of overkill since fX should equal fY for both round rects but it
|
||||
// makes the shader code simpler.
|
||||
pdman.set4f(fRadiiUni,
|
||||
0.5f * first.getSimpleRadii().fX,
|
||||
0.5f * first.getSimpleRadii().fY,
|
||||
0.5f * second.getSimpleRadii().fX,
|
||||
0.5f * second.getSimpleRadii().fY);
|
||||
first.getSimpleRadii().fX, first.getSimpleRadii().fY,
|
||||
second.getSimpleRadii().fX, second.getSimpleRadii().fY);
|
||||
}
|
||||
|
||||
pdman.set1f(fRadiusUni, edgeFP.radius());
|
||||
@ -264,7 +314,7 @@ public:
|
||||
// For circles we still upload both width & height to simplify things
|
||||
GrGLSLProgramDataManager::UniformHandle fSizesUni;
|
||||
|
||||
// The half corner radii of the two round rects (rx1/2, ry1/2, rx2/2, ry2/2)
|
||||
// The corner radii of the two round rects (rx1, ry1, rx2, ry2)
|
||||
// We upload both the x&y radii (although they are currently always the same) to make
|
||||
// the indexing in the shader code simpler. In some future world we could also support
|
||||
// non-circular corner round rects & ellipses.
|
||||
|
Loading…
Reference in New Issue
Block a user