Expose camera matrix in SkCanvas
3 new getters:
- localToWorld
- localToCamera
- localToDevice (same as total-matrix)
The current tracking minimizes overhead, by using a computed inverse to
produce the localToWorld/Camera. This can be change as needed in the
future (more precision, but more memory/overhead), but for now is
sufficient to try out the new APIs.
Change-Id: I85440318f36dca935124b782e110fe9c0152ae7a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/264648
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/samplecode/Sample3D.cpp b/samplecode/Sample3D.cpp
index d52154e..828cf99 100644
--- a/samplecode/Sample3D.cpp
+++ b/samplecode/Sample3D.cpp
@@ -144,9 +144,71 @@
{ 0,-SK_ScalarPI/2 }, // right
};
+#include "include/core/SkColorFilter.h"
+#include "include/effects/SkColorMatrix.h"
+
+static SkV3 normalize(SkV3 v) { return v * (1.0f / v.length()); }
+
+static SkColorMatrix comput_planar_lighting(SkCanvas* canvas, SkV3 lightDir) {
+ SkM44 l2w = canvas->getLocalToWorld();
+ auto normal = normalize(l2w * SkV3{0, 0, 1});
+ float dot = -normal * lightDir;
+
+ SkColorMatrix cm;
+ if (dot < 0) {
+ dot = 0;
+ }
+
+ float ambient = 0.5f;
+ float scale = ambient + dot;
+ cm.setScale(scale, scale, scale, 1);
+ return cm;
+}
+
+struct Light {
+ SkPoint fCenter;
+ SkPoint fEndPt;
+ SkScalar fRadius;
+ SkScalar fHeight;
+
+ bool hitTest(SkScalar x, SkScalar y) const {
+ auto xx = x - fCenter.fX;
+ auto yy = y - fCenter.fY;
+ return xx*xx + yy*yy <= fRadius*fRadius;
+ }
+
+ void update(SkScalar x, SkScalar y) {
+ auto xx = x - fCenter.fX;
+ auto yy = y - fCenter.fY;
+ auto len = SkScalarSqrt(xx*xx + yy*yy);
+ if (len > fRadius) {
+ xx *= fRadius / len;
+ yy *= fRadius / len;
+ }
+ fEndPt = {fCenter.fX + xx, fCenter.fY + yy};
+ }
+
+ SkV3 getDir() const {
+ auto pt = fEndPt - fCenter;
+ return normalize({pt.fX, pt.fY, -fHeight});
+ }
+
+ void draw(SkCanvas* canvas) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas->drawCircle(fCenter.fX, fCenter.fY, 5, paint);
+ paint.setStyle(SkPaint::kStroke_Style);
+ canvas->drawCircle(fCenter.fX, fCenter.fY, fRadius, paint);
+ paint.setColor(SK_ColorRED);
+ canvas->drawLine(fCenter.fX, fCenter.fY, fEndPt.fX, fEndPt.fY, paint);
+ }
+};
class SampleRR3D : public Sample3DView {
SkRRect fRR;
+ Light fLight = {
+ {60, 60}, {60, 60}, 50, 10
+ };
sk_sp<SkShader> fShader;
SkString name() override { return SkString("rrect3d"); }
@@ -167,13 +229,22 @@
canvas->concat(trans * fRot * m * inv(trans));
+ if (!front(canvas->getLocalToDevice())) {
+ return;
+ }
+
SkPaint paint;
- paint.setAlphaf(front(canvas->getTotalM44()) ? 1 : 0.25f);
+ paint.setAlphaf(front(canvas->getLocalToDevice()) ? 1 : 0.25f);
paint.setShader(fShader);
+
+ SkColorMatrix cm = comput_planar_lighting(canvas, fLight.getDir());
+ paint.setColorFilter(SkColorFilters::Matrix(cm));
+
canvas->drawRRect(fRR, paint);
}
void onDrawContent(SkCanvas* canvas) override {
+ canvas->save();
canvas->translate(400, 300);
this->saveCamera(canvas, {0, 0, 400, 400}, 200);
@@ -184,6 +255,20 @@
}
canvas->restore();
+ canvas->restore();
+
+ fLight.draw(canvas);
+ }
+
+ Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
+ if (fLight.hitTest(x, y)) {
+ return new Click();
+ }
+ return nullptr;
+ }
+ bool onClick(Click* click) override {
+ fLight.update(click->fCurr.fX, click->fCurr.fY);
+ return true;
}
};
DEF_SAMPLE( return new SampleRR3D(); )