Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
3DSlide.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2020 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
14#include "src/base/SkRandom.h"
15#include "tools/DecodeUtils.h"
16#include "tools/Resources.h"
18
19struct VSphere {
22
24
25 bool contains(SkV2 v) const {
26 return (v - fCenter).length() <= fRadius;
27 }
28
29 SkV2 pinLoc(SkV2 p) const {
30 auto v = p - fCenter;
31 if (v.length() > fRadius) {
32 v *= (fRadius / v.length());
33 }
34 return fCenter + v;
35 }
36
38 v = (v - fCenter) * (1 / fRadius);
39 SkScalar len2 = v.lengthSquared();
40 if (len2 > 1) {
41 v = v.normalize();
42 len2 = 1;
43 }
44 SkScalar z = SkScalarSqrt(1 - len2);
45 return {v.x, v.y, z};
46 }
47
52
54 SkV3 u = this->computeUnitV3(a);
55 SkV3 v = this->computeUnitV3(b);
56 SkV3 axis = u.cross(v);
57 SkScalar length = axis.length();
58
60 return {axis * (1.0f / length), std::acos(u.dot(v))};
61 }
62 return {{0, 0, 0}, 0};
63 }
64
66 auto [axis, angle] = this->computeRotationInfo(a, b);
67 return SkM44::Rotate(axis, angle);
68 }
69};
70
71static SkM44 inv(const SkM44& m) {
72 SkM44 inverse;
73 SkAssertResult(m.invert(&inverse));
74 return inverse;
75}
76
77// Compute the inverse transpose (of the upper-left 3x3) of a matrix, used to transform vectors
78static SkM44 normals(SkM44 m) {
79 m.setRow(3, {0, 0, 0, 1});
80 m.setCol(3, {0, 0, 0, 1});
81 SkAssertResult(m.invert(&m));
82 return m.transpose();
83}
84
86protected:
87 float fNear = 0.05f;
88 float fFar = 4;
89 float fAngle = SK_ScalarPI / 12;
90
91 SkV3 fEye { 0, 0, 1.0f/std::tan(fAngle/2) - 1 };
92 SkV3 fCOA { 0, 0, 0 };
93 SkV3 fUp { 0, 1, 0 };
94
95public:
96 void concatCamera(SkCanvas* canvas, const SkRect& area, SkScalar zscale) {
97 SkM44 camera = SkM44::LookAt(fEye, fCOA, fUp),
98 perspective = SkM44::Perspective(fNear, fFar, fAngle),
99 viewport = SkM44::Translate(area.centerX(), area.centerY(), 0) *
100 SkM44::Scale(area.width()*0.5f, area.height()*0.5f, zscale);
101
102 canvas->concat(viewport * perspective * camera * inv(viewport));
103 }
104};
105
106struct Face {
109
111 return SkM44::Translate(x, y, z);
112 }
113
114 static SkM44 R(SkV3 axis, SkScalar rad) {
115 return SkM44::Rotate(axis, rad);
116 }
117
119 return R({0,1,0}, fRy) * R({1,0,0}, fRx) * T(0, 0, scale);
120 }
121};
122
123static bool isFrontFacing(const SkM44& m) {
125 if (!m.invert(&m2)) {
126 m2.setIdentity();
127 }
128 /*
129 * Classically we want to dot the transpose(inverse(ctm)) with our surface normal.
130 * In this case, the normal is known to be {0, 0, 1}, so we only actually need to look
131 * at the z-scale of the inverse (the transpose doesn't change the main diagonal, so
132 * no need to actually transpose).
133 */
134 return m2.rc(2,2) > 0;
135}
136
137const Face faces[] = {
138 { 0, 0, SK_ColorRED }, // front
139 { 0, SK_ScalarPI, SK_ColorGREEN }, // back
140
141 { SK_ScalarPI/2, 0, SK_ColorBLUE }, // top
142 {-SK_ScalarPI/2, 0, SK_ColorCYAN }, // bottom
143
144 { 0, SK_ScalarPI/2, SK_ColorMAGENTA }, // left
145 { 0,-SK_ScalarPI/2, SK_ColorYELLOW }, // right
146};
147
149
154
156 return s.computeUnitV3(fLoc) * fDistance;
157 }
158
159 void draw(SkCanvas* canvas) const {
161 paint.setAntiAlias(true);
162 paint.setColor(SK_ColorWHITE);
163 canvas->drawCircle(fLoc.x, fLoc.y, fRadius + 2, paint);
164 paint.setColor(SK_ColorBLACK);
165 canvas->drawCircle(fLoc.x, fLoc.y, fRadius, paint);
166 }
167};
168
169#include "src/base/SkTime.h"
170
172 SkV3 fAxis = {0, 0, 0};
173 SkScalar fAngle = 0,
174 fPrevAngle = 1234567;
175 double fNow = 0,
176 fPrevNow = 0;
177
178 SkScalar fAngleSpeed = 0,
179 fAngleSign = 1;
180
181 inline static constexpr double kSlowDown = 4;
182 inline static constexpr SkScalar kMaxSpeed = 16;
183
184public:
185 void update(SkV3 axis, SkScalar angle) {
186 if (angle != fPrevAngle) {
187 fPrevAngle = fAngle;
188 fAngle = angle;
189
190 fPrevNow = fNow;
191 fNow = SkTime::GetSecs();
192
193 fAxis = axis;
194 }
195 }
196
198 if (fAngleSpeed > 0) {
199 double now = SkTime::GetSecs();
200 double dtime = now - fPrevNow;
201 fPrevNow = now;
202 double delta = fAngleSign * fAngleSpeed * dtime;
203 fAngle += delta;
204 fAngleSpeed -= kSlowDown * dtime;
205 if (fAngleSpeed < 0) {
206 fAngleSpeed = 0;
207 }
208 }
209 return SkM44::Rotate(fAxis, fAngle);
210
211 }
212
213 void start() {
214 if (fPrevNow != fNow) {
215 fAngleSpeed = (fAngle - fPrevAngle) / (fNow - fPrevNow);
216 fAngleSign = fAngleSpeed < 0 ? -1 : 1;
217 fAngleSpeed = std::min(kMaxSpeed, std::abs(fAngleSpeed));
218 } else {
219 fAngleSpeed = 0;
220 }
221 fPrevNow = SkTime::GetSecs();
222 fAngle = 0;
223 }
224
225 void reset() {
226 fAngleSpeed = 0;
227 fAngle = 0;
228 fPrevAngle = 1234567;
229 }
230
231 bool isAnimating() const { return fAngleSpeed != 0; }
232};
233
235 enum {
236 DX = 400,
237 DY = 300
238 };
239
240 SkM44 fRotation; // part of model
241
242 RotateAnimator fRotateAnimator;
243
244protected:
245 enum Flags {
246 kCanRunOnCPU = 1 << 0,
248 };
249
250 LightOnSphere fLight = {{200 + DX, 200 + DY}, 800, 12};
251
254
255public:
257 : fSphere({200 + DX, 200 + DY}, 400)
258 , fFlags(flags)
259 {}
260
261 bool onChar(SkUnichar uni) override {
262 switch (uni) {
263 case 'Z': fLight.fDistance += 10; return true;
264 case 'z': fLight.fDistance -= 10; return true;
265 }
266 return this->ThreeDSlide::onChar(uni);
267 }
268
269 virtual void drawFace(SkCanvas*, SkColor, int face, bool front, const SkM44& localToWorld) = 0;
270
271 void draw(SkCanvas* canvas) override {
272 if (!canvas->recordingContext() && !(fFlags & kCanRunOnCPU)) {
273 return;
274 }
275
276 canvas->save();
277 canvas->translate(DX, DY);
278
279 this->concatCamera(canvas, {0, 0, 400, 400}, 200);
280
281 SkM44 m = fRotateAnimator.rotation() * fRotation;
282 for (bool front : {false, true}) {
283 int index = 0;
284 for (auto f : faces) {
285 SkAutoCanvasRestore acr(canvas, true);
286
287 SkM44 trans = SkM44::Translate(200, 200, 0); // center of the rotation
288
289 canvas->concat(trans);
290
291 // "World" space - content is centered at the origin, in device scale (+-200)
292 SkM44 localToWorld = m * f.asM44(200) * inv(trans);
293
294 canvas->concat(localToWorld);
295 this->drawFace(canvas, f.fColor, index++, front, localToWorld);
296 }
297 }
298
299 canvas->restore(); // camera & center the content in the window
300
301 if (fFlags & kShowLightDome){
302 fLight.draw(canvas);
303
305 paint.setAntiAlias(true);
307 paint.setColor(0x40FF0000);
313 }
314 }
315
317 SkV2 p = fLight.fLoc - SkV2{x, y};
318 if (p.length() <= fLight.fRadius) {
319 Click* c = new Click();
320 c->fMeta.setS32("type", 0);
321 return c;
322 }
323 if (fSphere.contains({x, y})) {
324 Click* c = new Click();
325 c->fMeta.setS32("type", 1);
326
327 fRotation = fRotateAnimator.rotation() * fRotation;
328 fRotateAnimator.reset();
329 return c;
330 }
331 return nullptr;
332 }
333 bool onClick(Click* click) override {
334 if (click->fMeta.hasS32("type", 0)) {
335 fLight.fLoc = fSphere.pinLoc({click->fCurr.fX, click->fCurr.fY});
336 return true;
337 }
338 if (click->fMeta.hasS32("type", 1)) {
339 if (click->fState == skui::InputState::kUp) {
340 fRotation = fRotateAnimator.rotation() * fRotation;
341 fRotateAnimator.start();
342 } else {
343 auto [axis, angle] = fSphere.computeRotationInfo(
344 {click->fOrig.fX, click->fOrig.fY},
345 {click->fCurr.fX, click->fCurr.fY});
346 fRotateAnimator.update(axis, angle);
347 }
348 return true;
349 }
350 return true;
351 }
352
353 bool animate(double nanos) override {
354 return fRotateAnimator.isAnimating();
355 }
356};
357
359 sk_sp<SkShader> fBmpShader, fImgShader;
361 SkRRect fRR;
362
363public:
365
366 void load(SkScalar w, SkScalar h) override {
367 fRR = SkRRect::MakeRectXY({20, 20, 380, 380}, 50, 50);
368 auto img = ToolUtils::GetResourceAsImage("images/brickwork-texture.jpg");
369 fImgShader = img->makeShader(SkSamplingOptions(), SkMatrix::Scale(2, 2));
370 img = ToolUtils::GetResourceAsImage("images/brickwork_normal-map.jpg");
371 fBmpShader = img->makeShader(SkSamplingOptions(), SkMatrix::Scale(2, 2));
372
373 const char code[] = R"(
374 uniform shader color_map;
375 uniform shader normal_map;
376
377 uniform float4x4 localToWorld;
378 uniform float4x4 localToWorldAdjInv;
379 uniform float3 lightPos;
380
381 float3 convert_normal_sample(half4 c) {
382 float3 n = 2 * c.rgb - 1;
383 n.y = -n.y;
384 return n;
385 }
386
387 half4 main(float2 p) {
388 float3 norm = convert_normal_sample(normal_map.eval(p));
389 float3 plane_norm = normalize(localToWorldAdjInv * norm.xyz0).xyz;
390
391 float3 plane_pos = (localToWorld * p.xy01).xyz;
392 float3 light_dir = normalize(lightPos - plane_pos);
393
394 float ambient = 0.2;
395 float dp = dot(plane_norm, light_dir);
396 float scale = min(ambient + max(dp, 0), 1);
397
398 return color_map.eval(p) * scale.xxx1;
399 }
400 )";
401 auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(code));
402 if (!effect) {
403 SkDebugf("runtime error %s\n", error.c_str());
404 }
405 fEffect = effect;
406 }
407
408 void drawFace(SkCanvas* canvas, SkColor color, int face, bool front,
409 const SkM44& localToWorld) override {
410 if (!front || !isFrontFacing(canvas->getLocalToDevice())) {
411 return;
412 }
413
414 SkRuntimeShaderBuilder builder(fEffect);
415 builder.uniform("lightPos") = fLight.computeWorldPos(fSphere);
416 builder.uniform("localToWorld") = localToWorld;
417 builder.uniform("localToWorldAdjInv") = normals(localToWorld);
418
419 builder.child("color_map") = fImgShader;
420 builder.child("normal_map") = fBmpShader;
421
423 paint.setColor(color);
424 paint.setShader(builder.makeShader());
425
426 canvas->drawRRect(fRR, paint);
427 }
428};
429DEF_SLIDE( return new Bump3DSlide; )
430
431#include "modules/skottie/include/Skottie.h"
432
434 sk_sp<skottie::Animation> fAnim[6];
435
436public:
437 SkottieCubeSlide() : CubeBaseSlide(kCanRunOnCPU) { fName = "skottie3d"; }
438
439 void load(SkScalar w, SkScalar h) override {
440 const char* files[] = {
441 "skottie/skottie-chained-mattes.json",
442 "skottie/skottie-gradient-ramp.json",
443 "skottie/skottie_sample_2.json",
444 "skottie/skottie-3d-3planes.json",
445 "skottie/skottie-text-animator-4.json",
446 "skottie/skottie-motiontile-effect-phase.json",
447
448 };
449 for (unsigned i = 0; i < std::size(files); ++i) {
450 if (auto stream = GetResourceAsStream(files[i])) {
451 fAnim[i] = skottie::Animation::Make(stream.get());
452 }
453 }
454 }
455
456 void drawFace(SkCanvas* canvas, SkColor color, int face, bool front, const SkM44&) override {
457 if (!front || !isFrontFacing(canvas->getLocalToDevice())) {
458 return;
459 }
460
462 paint.setColor(color);
463 SkRect r = {0, 0, 400, 400};
464 canvas->drawRect(r, paint);
465 fAnim[face]->render(canvas, &r);
466 }
467
468 bool animate(double nanos) override {
469 for (auto& anim : fAnim) {
470 SkScalar dur = anim->duration();
471 SkScalar t = fmod(1e-9 * nanos, dur) / dur;
472 anim->seek(t);
473 }
474 return true;
475 }
476};
477DEF_SLIDE( return new SkottieCubeSlide; )
const Face faces[]
Definition 3DSlide.cpp:137
static SkM44 normals(SkM44 m)
Definition 3DSlide.cpp:78
static SkM44 inv(const SkM44 &m)
Definition 3DSlide.cpp:71
static bool isFrontFacing(const SkM44 &m)
Definition 3DSlide.cpp:123
const char * fName
SkColor4f color
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition Resources.cpp:31
#define SkAssertResult(cond)
Definition SkAssert.h:123
constexpr SkColor SK_ColorYELLOW
Definition SkColor.h:139
constexpr SkColor SK_ColorMAGENTA
Definition SkColor.h:147
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorCYAN
Definition SkColor.h:143
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:101
#define SkScalarSqrt(x)
Definition SkScalar.h:42
#define SK_ScalarPI
Definition SkScalar.h:21
int32_t SkUnichar
Definition SkTypes.h:175
#define DEF_SLIDE(code)
Definition Slide.h:25
static SkScalar center(float pos0, float pos1)
void drawFace(SkCanvas *canvas, SkColor color, int face, bool front, const SkM44 &localToWorld) override
Definition 3DSlide.cpp:408
void load(SkScalar w, SkScalar h) override
Definition 3DSlide.cpp:366
virtual void drawFace(SkCanvas *, SkColor, int face, bool front, const SkM44 &localToWorld)=0
bool animate(double nanos) override
Definition 3DSlide.cpp:353
void draw(SkCanvas *canvas) override
Definition 3DSlide.cpp:271
Click * onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override
Definition 3DSlide.cpp:316
bool onChar(SkUnichar uni) override
Definition 3DSlide.cpp:261
LightOnSphere fLight
Definition 3DSlide.cpp:250
VSphere fSphere
Definition 3DSlide.cpp:252
CubeBaseSlide(Flags flags)
Definition 3DSlide.cpp:256
bool onClick(Click *click) override
Definition 3DSlide.cpp:333
void update(SkV3 axis, SkScalar angle)
Definition 3DSlide.cpp:185
bool isAnimating() const
Definition 3DSlide.cpp:231
SkM44 rotation()
Definition 3DSlide.cpp:197
void drawRect(const SkRect &rect, const SkPaint &paint)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
virtual GrRecordingContext * recordingContext() const
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
SkM44 getLocalToDevice() const
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
int save()
Definition SkCanvas.cpp:451
void concat(const SkMatrix &matrix)
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
Definition SkM44.h:150
static SkM44 LookAt(const SkV3 &eye, const SkV3 &center, const SkV3 &up)
Definition SkM44.cpp:331
SkScalar rc(int r, int c) const
Definition SkM44.h:261
static SkM44 Rotate(SkV3 axis, SkScalar radians)
Definition SkM44.h:239
@ kUninitialized_Constructor
Definition SkM44.h:167
static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z=0)
Definition SkM44.h:225
static SkM44 Perspective(float near, float far, float angle)
Definition SkM44.cpp:343
static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z=1)
Definition SkM44.h:232
SkM44 & setIdentity()
Definition SkM44.h:293
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition SkMatrix.h:75
void setS32(const char name[], int32_t value)
bool hasS32(const char name[], int32_t value) const
Definition SkMetaData.h:28
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition SkRRect.h:180
static Result MakeForShader(SkString sksl, const Options &)
void drawFace(SkCanvas *canvas, SkColor color, int face, bool front, const SkM44 &) override
Definition 3DSlide.cpp:456
bool animate(double nanos) override
Definition 3DSlide.cpp:468
void load(SkScalar w, SkScalar h) override
Definition 3DSlide.cpp:439
virtual bool onChar(SkUnichar c)
Definition Slide.h:44
float fNear
Definition 3DSlide.cpp:87
void concatCamera(SkCanvas *canvas, const SkRect &area, SkScalar zscale)
Definition 3DSlide.cpp:96
float fFar
Definition 3DSlide.cpp:88
float fAngle
Definition 3DSlide.cpp:89
static sk_sp< Animation > Make(const char *data, size_t length)
Definition Skottie.cpp:534
const Paint & paint
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct s
struct MyStruct a[10]
FlutterSemanticsFlag flags
const uint8_t uint32_t uint32_t GError ** error
#define R(r)
size_t length
double y
double x
double GetSecs()
Definition SkTime.h:16
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition DecodeUtils.h:25
ModifierKey
Definition ModifierKey.h:9
SkScalar w
SkScalar h
#define T
const Scalar scale
static SkM44 T(SkScalar x, SkScalar y, SkScalar z)
Definition 3DSlide.cpp:110
SkScalar fRy
Definition 3DSlide.cpp:107
static SkM44 R(SkV3 axis, SkScalar rad)
Definition 3DSlide.cpp:114
SkM44 asM44(SkScalar scale) const
Definition 3DSlide.cpp:118
SkColor fColor
Definition 3DSlide.cpp:108
SkScalar fRx
Definition 3DSlide.cpp:107
SkScalar fDistance
Definition 3DSlide.cpp:152
SkV3 computeWorldPos(const VSphere &s) const
Definition 3DSlide.cpp:155
SkScalar fRadius
Definition 3DSlide.cpp:153
void draw(SkCanvas *canvas) const
Definition 3DSlide.cpp:159
float fX
x-axis value
float fY
y-axis value
constexpr float centerX() const
Definition SkRect.h:776
constexpr float height() const
Definition SkRect.h:769
constexpr float centerY() const
Definition SkRect.h:785
constexpr float width() const
Definition SkRect.h:762
Definition SkM44.h:19
SkV2 normalize() const
Definition SkM44.h:50
float x
Definition SkM44.h:20
SkScalar lengthSquared() const
Definition SkM44.h:45
float y
Definition SkM44.h:20
Definition SkM44.h:56
SkV3 cross(const SkV3 &v) const
Definition SkM44.h:91
SkScalar dot(const SkV3 &v) const
Definition SkM44.h:90
SkScalar length() const
Definition SkM44.h:88
SkScalar fRadius
Definition 3DSlide.cpp:21
SkM44 computeRotation(SkV2 a, SkV2 b) const
Definition 3DSlide.cpp:65
RotateInfo computeRotationInfo(SkV2 a, SkV2 b) const
Definition 3DSlide.cpp:53
VSphere(SkV2 center, SkScalar radius)
Definition 3DSlide.cpp:23
SkV2 fCenter
Definition 3DSlide.cpp:20
SkV3 computeUnitV3(SkV2 v) const
Definition 3DSlide.cpp:37
bool contains(SkV2 v) const
Definition 3DSlide.cpp:25
SkV2 pinLoc(SkV2 p) const
Definition 3DSlide.cpp:29