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 kNumRows = 5;
|
||||||
constexpr int kCellSize = 128;
|
constexpr int kCellSize = 128;
|
||||||
constexpr SkScalar kPad = 8.0f;
|
constexpr SkScalar kPad = 8.0f;
|
||||||
constexpr SkScalar kBlurRadius = 8.0f;
|
constexpr SkScalar kInitialBlurRadius = 8.0f;
|
||||||
constexpr SkScalar kPeriod = 8.0f;
|
constexpr SkScalar kPeriod = 8.0f;
|
||||||
constexpr int kClipOffset = 32;
|
constexpr int kClipOffset = 32;
|
||||||
|
|
||||||
@ -292,7 +292,11 @@ public:
|
|||||||
|
|
||||||
static const int kModeCount = kLast_Mode + 1;
|
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));
|
this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,14 +353,15 @@ protected:
|
|||||||
SkPaint paint;
|
SkPaint paint;
|
||||||
paint.setAntiAlias(true);
|
paint.setAntiAlias(true);
|
||||||
// G channel is an F6.2 radius
|
// 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());
|
paint.setShader(SkGaussianEdgeShader::Make());
|
||||||
drawObj->draw(canvas, paint);
|
drawObj->draw(canvas, paint);
|
||||||
canvas->restore();
|
canvas->restore();
|
||||||
} else if (kBlurMask_Mode == fMode) {
|
} else if (kBlurMask_Mode == fMode) {
|
||||||
SkPath clippedPath;
|
SkPath clippedPath;
|
||||||
|
|
||||||
SkScalar sigma = kBlurRadius / 4.0f;
|
SkScalar sigma = fBlurRadius / 4.0f;
|
||||||
|
|
||||||
if (clipObj->contains(drawObj->bounds())) {
|
if (clipObj->contains(drawObj->bounds())) {
|
||||||
clippedPath = drawObj->asPath(2.0f*sigma);
|
clippedPath = drawObj->asPath(2.0f*sigma);
|
||||||
@ -383,7 +388,7 @@ protected:
|
|||||||
|
|
||||||
if (clipObj->asRRect(&clipRR) && drawObj->asRRect(&drawnRR)) {
|
if (clipObj->asRRect(&clipRR) && drawObj->asRRect(&drawnRR)) {
|
||||||
paint.setShader(SkRRectsGaussianEdgeShader::Make(clipRR, drawnRR,
|
paint.setShader(SkRRectsGaussianEdgeShader::Make(clipRR, drawnRR,
|
||||||
kBlurRadius));
|
fBlurRadius));
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas->drawRect(cover, paint);
|
canvas->drawRect(cover, paint);
|
||||||
@ -408,6 +413,12 @@ protected:
|
|||||||
case 'C':
|
case 'C':
|
||||||
fMode = (Mode)((fMode + 1) % kModeCount);
|
fMode = (Mode)((fMode + 1) % kModeCount);
|
||||||
return true;
|
return true;
|
||||||
|
case '+':
|
||||||
|
fBlurRadius += 1.0f;
|
||||||
|
return true;
|
||||||
|
case '-':
|
||||||
|
fBlurRadius = SkTMax(1.0f, fBlurRadius - 1.0f);
|
||||||
|
return true;
|
||||||
case 'p':
|
case 'p':
|
||||||
fPause = !fPause;
|
fPause = !fPause;
|
||||||
return true;
|
return true;
|
||||||
@ -427,6 +438,7 @@ private:
|
|||||||
SkScalar fFraction;
|
SkScalar fFraction;
|
||||||
Mode fMode;
|
Mode fMode;
|
||||||
bool fPause;
|
bool fPause;
|
||||||
|
float fBlurRadius;
|
||||||
|
|
||||||
typedef GM INHERITED;
|
typedef GM INHERITED;
|
||||||
};
|
};
|
||||||
|
@ -111,8 +111,9 @@ public:
|
|||||||
const char* outputName,
|
const char* outputName,
|
||||||
const char indices[2]) { // how to access the params for the 2 rrects
|
const char indices[2]) { // how to access the params for the 2 rrects
|
||||||
|
|
||||||
// positive distance is towards the center of the circle
|
// Positive distance is towards the center of the circle.
|
||||||
fragBuilder->codeAppendf("vec2 delta = %s.xy - %s.%s;",
|
// Map all the cases to the lower right quadrant.
|
||||||
|
fragBuilder->codeAppendf("vec2 delta = abs(%s.xy - %s.%s);",
|
||||||
fragBuilder->fragmentPosition(), posName, indices);
|
fragBuilder->fragmentPosition(), posName, indices);
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -126,44 +127,95 @@ public:
|
|||||||
break;
|
break;
|
||||||
case kRect_Mode:
|
case kRect_Mode:
|
||||||
fragBuilder->codeAppendf(
|
fragBuilder->codeAppendf(
|
||||||
"vec2 rectDist = vec2(1.0 - clamp((%s.%c - abs(delta.x))/%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 - abs(delta.y))/%s, 0.0, 1.0));",
|
"1.0 - clamp((%s.%c - delta.y)/%s, 0.0, 1.0));",
|
||||||
sizesName, indices[0], radName,
|
sizesName, indices[0], radName,
|
||||||
sizesName, indices[1], radName);
|
sizesName, indices[1], radName);
|
||||||
fragBuilder->codeAppendf("%s = clamp(1.0 - length(rectDist), 0.0, 1.0);",
|
fragBuilder->codeAppendf("%s = clamp(1.0 - length(rectDist), 0.0, 1.0);",
|
||||||
outputName);
|
outputName);
|
||||||
break;
|
break;
|
||||||
case kSimpleCircular_Mode:
|
case kSimpleCircular_Mode:
|
||||||
// For the circular round rect we first compute the distance
|
// For the circular round rect we combine 2 distances:
|
||||||
// to the rect. Then we compute a multiplier that is 1 if the
|
// the fractional position from the corner inset point to the corner's circle
|
||||||
// point is in one of the circular corners. We then compute the
|
// the minimum perpendicular distance to the bounding rectangle
|
||||||
// distance from the corner and then use the multiplier to mask
|
// The first distance is used when the pixel is inside the ice-cream-cone-shaped
|
||||||
// between the two distances.
|
// portion of a corner. The second is used everywhere else.
|
||||||
fragBuilder->codeAppendf("float xDist = clamp((%s.%c - abs(delta.x))/%s,"
|
// This is intended to approximate the interpolation pattern if we had tessellated
|
||||||
"0.0, 1.0);",
|
// 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);
|
sizesName, indices[0], radName);
|
||||||
fragBuilder->codeAppendf("float yDist = clamp((%s.%c - abs(delta.y))/%s,"
|
fragBuilder->codeAppendf("float yDist = (%s.%c - delta.y) / %s;",
|
||||||
"0.0, 1.0);",
|
|
||||||
sizesName, indices[1], radName);
|
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);
|
// ice-cream-cone fractional distance computation
|
||||||
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);");
|
|
||||||
|
|
||||||
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,"
|
fragBuilder->codeAppendf("vec2 coneBottom = vec2(%s.%c - insetDist,"
|
||||||
"0.0, 1.0);",
|
"%s.%c - insetDist);",
|
||||||
radiiName, indices[0], radName);
|
sizesName, indices[0], sizesName, indices[1]);
|
||||||
|
|
||||||
fragBuilder->codeAppendf("%s = (multiplier * cornerDist) +"
|
fragBuilder->codeAppendf("vec2 cornerTop = vec2(%s.%c - %s.%c, %s.%c) -"
|
||||||
"((1.0-multiplier) * rectDist);",
|
"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);
|
outputName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -247,10 +299,8 @@ public:
|
|||||||
// This is a bit of overkill since fX should equal fY for both round rects but it
|
// This is a bit of overkill since fX should equal fY for both round rects but it
|
||||||
// makes the shader code simpler.
|
// makes the shader code simpler.
|
||||||
pdman.set4f(fRadiiUni,
|
pdman.set4f(fRadiiUni,
|
||||||
0.5f * first.getSimpleRadii().fX,
|
first.getSimpleRadii().fX, first.getSimpleRadii().fY,
|
||||||
0.5f * first.getSimpleRadii().fY,
|
second.getSimpleRadii().fX, second.getSimpleRadii().fY);
|
||||||
0.5f * second.getSimpleRadii().fX,
|
|
||||||
0.5f * second.getSimpleRadii().fY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pdman.set1f(fRadiusUni, edgeFP.radius());
|
pdman.set1f(fRadiusUni, edgeFP.radius());
|
||||||
@ -264,7 +314,7 @@ public:
|
|||||||
// For circles we still upload both width & height to simplify things
|
// For circles we still upload both width & height to simplify things
|
||||||
GrGLSLProgramDataManager::UniformHandle fSizesUni;
|
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
|
// 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
|
// the indexing in the shader code simpler. In some future world we could also support
|
||||||
// non-circular corner round rects & ellipses.
|
// non-circular corner round rects & ellipses.
|
||||||
|
Loading…
Reference in New Issue
Block a user