Some more tweaks to perspective path clipping
Bug: skia:9546 Change-Id: Ib91880e09ae6373bc133d684aa7510c67681ec1e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/257629 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
e0f374bf8f
commit
c336315d3c
@ -146,15 +146,30 @@ struct SkHalfPlane {
|
||||
}
|
||||
|
||||
bool twoPts(SkPoint pts[2]) const {
|
||||
if (fB) {
|
||||
pts[0] = { 0, -fC / fB };
|
||||
pts[1] = { 1, (-fC - fA) / fB };
|
||||
} else if (fA) {
|
||||
pts[0] = { -fC / fA, 0 };
|
||||
pts[1] = { (-fC - fB) / fA, 1 };
|
||||
// normalize plane to help with the perpendicular step, below
|
||||
SkScalar len = SkScalarSqrt(fA*fA + fB*fB);
|
||||
if (!len) {
|
||||
return false;
|
||||
}
|
||||
SkScalar denom = SkScalarInvert(len);
|
||||
SkScalar a = fA * denom;
|
||||
SkScalar b = fB * denom;
|
||||
SkScalar c = fC * denom;
|
||||
|
||||
// We compute p0 on the half-plane by setting one of the components to 0
|
||||
// We compute p1 by stepping from p0 along a perpendicular to the normal
|
||||
if (b) {
|
||||
pts[0] = { 0, -c / b };
|
||||
pts[1] = { b, pts[0].fY - a};
|
||||
} else if (a) {
|
||||
pts[0] = { -c / a, 0 };
|
||||
pts[1] = { pts[0].fX + b, -a };
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkASSERT(SkScalarNearlyZero(this->operator()(pts[0].fX, pts[0].fY)));
|
||||
SkASSERT(SkScalarNearlyZero(this->operator()(pts[1].fX, pts[1].fY)));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -222,6 +237,39 @@ static SkPath clip(const SkPath& path, SkPoint p0, SkPoint p1) {
|
||||
}
|
||||
|
||||
static SkPath clip(const SkPath& path, const SkHalfPlane& plane) {
|
||||
// do a quick bounds check to see if we need to clip at all
|
||||
const SkRect& bounds = path.getBounds();
|
||||
|
||||
// check whether the diagonal aligned with the normal crosses the plane
|
||||
SkPoint diagMin, diagMax;
|
||||
if (plane.fA >= 0) {
|
||||
diagMin.fX = bounds.fLeft;
|
||||
diagMax.fX = bounds.fRight;
|
||||
} else {
|
||||
diagMin.fX = bounds.fRight;
|
||||
diagMax.fX = bounds.fLeft;
|
||||
}
|
||||
if (plane.fB >= 0) {
|
||||
diagMin.fY = bounds.fTop;
|
||||
diagMax.fY = bounds.fBottom;
|
||||
} else {
|
||||
diagMin.fY = bounds.fBottom;
|
||||
diagMax.fY = bounds.fTop;
|
||||
}
|
||||
SkScalar test = plane(diagMin.fX, diagMin.fY);
|
||||
SkScalar sign = test*plane(diagMax.fX, diagMin.fY);
|
||||
if (sign > 0) {
|
||||
// the path is either all on one side of the half-plane or the other
|
||||
if (test < 0) {
|
||||
// completely culled
|
||||
return SkPath();
|
||||
} else {
|
||||
// no clipping necessary
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
// quick check failed, we have to clip
|
||||
SkPoint pts[2];
|
||||
if (plane.twoPts(pts)) {
|
||||
return clip(path, pts[0], pts[1]);
|
||||
@ -393,7 +441,7 @@ static void half_planes(const SkMatrix44& m44, SkScalar W, SkScalar H, SkHalfPla
|
||||
|
||||
a = 2*a/W - m; b = 2*b/W - n; d = 2*d/W - p;
|
||||
e = 2*e/H - m; f = 2*f/H - n; h = 2*h/H - p;
|
||||
i = 2*i - m; j = 2*j - n; l = 2*l - p;
|
||||
// i = 2*i - m; j = 2*j - n; l = 2*l - p;
|
||||
|
||||
planes[0] = { m - a, n - b, p - d }; // w - x
|
||||
planes[1] = { m + a, n + b, p + d }; // w + x
|
||||
@ -403,6 +451,19 @@ static void half_planes(const SkMatrix44& m44, SkScalar W, SkScalar H, SkHalfPla
|
||||
planes[5] = { m + i, n + j, p + l }; // w + z
|
||||
}
|
||||
|
||||
static SkHalfPlane half_plane_w0(const SkMatrix44& m44, SkScalar W, SkScalar H) {
|
||||
float mx[16];
|
||||
m44.asColMajorf(mx);
|
||||
|
||||
SkScalar
|
||||
// a = mx[0], b = mx[4], /* c = mx[ 8], */ d = mx[12],
|
||||
// e = mx[1], f = mx[5], /* g = mx[ 9], */ h = mx[13],
|
||||
// i = mx[2], j = mx[6], /* k = mx[10], */ l = mx[14],
|
||||
m = mx[3], n = mx[7], /* o = mx[11], */ p = mx[15];
|
||||
|
||||
return { m, n, p - 0.05f }; // w = 0.05f
|
||||
}
|
||||
|
||||
class HalfPlaneView3 : public Sample {
|
||||
float fNear = 0.05f;
|
||||
float fFar = 4;
|
||||
@ -413,6 +474,7 @@ class HalfPlaneView3 : public Sample {
|
||||
SkPoint3 fUp { 0, 1, 0 };
|
||||
|
||||
SkMatrix44 fRot;
|
||||
SkPoint3 fTrans;
|
||||
|
||||
SkPath fPath;
|
||||
sk_sp<SkShader> fShader;
|
||||
@ -440,13 +502,15 @@ class HalfPlaneView3 : public Sample {
|
||||
SkMatrix44 get44() const {
|
||||
SkMatrix44 camera,
|
||||
perspective,
|
||||
translate,
|
||||
viewport;
|
||||
|
||||
Sk3Perspective(&perspective, fNear, fFar, fAngle);
|
||||
Sk3LookAt(&camera, fEye, fCOA, fUp);
|
||||
translate.setTranslate(fTrans.fX, fTrans.fY, fTrans.fZ);
|
||||
viewport.setScale(200, 200, 1).postTranslate( 200, 200, 0);
|
||||
|
||||
return viewport * perspective * camera * fRot * inv(viewport);
|
||||
return viewport * perspective * camera * translate * fRot * inv(viewport);
|
||||
}
|
||||
|
||||
void onDrawContent(SkCanvas* canvas) override {
|
||||
@ -468,8 +532,9 @@ class HalfPlaneView3 : public Sample {
|
||||
|
||||
SkHalfPlane planes[6];
|
||||
half_planes(mx44, 400, 400, planes);
|
||||
SkHalfPlane hpw = half_plane_w0(mx44, 400, 400);
|
||||
|
||||
SkPath path = clip(fPath, planes[4]);
|
||||
SkPath path = clip(fPath, hpw);//planes[4]);
|
||||
canvas->save();
|
||||
canvas->concat(mx);
|
||||
canvas->drawPath(path, paint);
|
||||
@ -479,7 +544,8 @@ class HalfPlaneView3 : public Sample {
|
||||
// draw_halfplane(canvas, p, SK_ColorRED);
|
||||
// }
|
||||
draw_halfplane(canvas, planes[4], SK_ColorBLUE);
|
||||
draw_halfplane(canvas, planes[5], SK_ColorGREEN);
|
||||
// draw_halfplane(canvas, planes[5], SK_ColorGREEN);
|
||||
draw_halfplane(canvas, hpw, SK_ColorRED);
|
||||
}
|
||||
|
||||
bool onChar(SkUnichar uni) override {
|
||||
@ -492,8 +558,8 @@ class HalfPlaneView3 : public Sample {
|
||||
case '-': this->rotate(0, 0, delta); return true;
|
||||
case '+': this->rotate(0, 0, -delta); return true;
|
||||
|
||||
case 'i': fEye.fZ += 0.1f; SkDebugf("ez %g\n", fEye.fZ); return true;
|
||||
case 'k': fEye.fZ -= 0.1f; SkDebugf("ez %g\n", fEye.fZ); return true;
|
||||
case 'i': fTrans.fZ += 0.1f; SkDebugf("ez %g\n", fTrans.fZ); return true;
|
||||
case 'k': fTrans.fZ -= 0.1f; SkDebugf("ez %g\n", fTrans.fZ); return true;
|
||||
|
||||
case 'n': fNear += 0.1f; SkDebugf("near %g\n", fNear); return true;
|
||||
case 'N': fNear -= 0.1f; SkDebugf("near %g\n", fNear); return true;
|
||||
|
Loading…
Reference in New Issue
Block a user