Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkDrawShadowInfo.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2017 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
9
11#include "include/core/SkPath.h"
12#include "include/core/SkRect.h"
15
17
19 return x*params.fX + y*params.fY + params.fZ;
20}
21
22bool GetSpotShadowTransform(const SkPoint3& lightPos, SkScalar lightRadius,
23 const SkMatrix& ctm, const SkPoint3& zPlaneParams,
24 const SkRect& pathBounds, bool directional,
25 SkMatrix* shadowTransform, SkScalar* radius) {
26 auto heightFunc = [zPlaneParams] (SkScalar x, SkScalar y) {
27 return zPlaneParams.fX*x + zPlaneParams.fY*y + zPlaneParams.fZ;
28 };
29 SkScalar occluderHeight = heightFunc(pathBounds.centerX(), pathBounds.centerY());
30
31 // TODO: have directional lights support tilt via the zPlaneParams
32 if (!ctm.hasPerspective() || directional) {
34 SkVector translate;
35 if (directional) {
36 SkDrawShadowMetrics::GetDirectionalParams(occluderHeight, lightPos.fX, lightPos.fY,
37 lightPos.fZ, lightRadius, radius,
38 &scale, &translate);
39 } else {
40 SkDrawShadowMetrics::GetSpotParams(occluderHeight, lightPos.fX, lightPos.fY,
41 lightPos.fZ, lightRadius, radius,
42 &scale, &translate);
43 }
44 shadowTransform->setScaleTranslate(scale, scale, translate.fX, translate.fY);
45 shadowTransform->preConcat(ctm);
46 } else {
47 if (SkScalarNearlyZero(pathBounds.width()) || SkScalarNearlyZero(pathBounds.height())) {
48 return false;
49 }
50
51 // get rotated quad in 3D
52 SkPoint pts[4];
53 ctm.mapRectToQuad(pts, pathBounds);
54
55 SkPoint3 pts3D[4];
56 SkScalar z = heightFunc(pathBounds.fLeft, pathBounds.fTop);
57 pts3D[0].set(pts[0].fX, pts[0].fY, z);
58 z = heightFunc(pathBounds.fRight, pathBounds.fTop);
59 pts3D[1].set(pts[1].fX, pts[1].fY, z);
60 z = heightFunc(pathBounds.fRight, pathBounds.fBottom);
61 pts3D[2].set(pts[2].fX, pts[2].fY, z);
62 z = heightFunc(pathBounds.fLeft, pathBounds.fBottom);
63 pts3D[3].set(pts[3].fX, pts[3].fY, z);
64
65 // project from light through corners to z=0 plane
66 for (int i = 0; i < 4; ++i) {
67 SkScalar dz = lightPos.fZ - pts3D[i].fZ;
68 // light shouldn't be below or at a corner's z-location
69 if (dz <= SK_ScalarNearlyZero) {
70 return false;
71 }
72 SkScalar zRatio = pts3D[i].fZ / dz;
73 pts3D[i].fX -= (lightPos.fX - pts3D[i].fX)*zRatio;
74 pts3D[i].fY -= (lightPos.fY - pts3D[i].fY)*zRatio;
75 pts3D[i].fZ = SK_Scalar1;
76 }
77
78 // Generate matrix that projects from [-1,1]x[-1,1] square to projected quad
79 SkPoint3 h0, h1, h2;
80 // Compute homogenous crossing point between top and bottom edges (gives new x-axis).
81 h0 = (pts3D[1].cross(pts3D[0])).cross(pts3D[2].cross(pts3D[3]));
82 // Compute homogenous crossing point between left and right edges (gives new y-axis).
83 h1 = (pts3D[0].cross(pts3D[3])).cross(pts3D[1].cross(pts3D[2]));
84 // Compute homogenous crossing point between diagonals (gives new origin).
85 h2 = (pts3D[0].cross(pts3D[2])).cross(pts3D[1].cross(pts3D[3]));
86 // If h2 is a vector (z=0 in 2D homogeneous space), that means that at least
87 // two of the quad corners are coincident and we don't have a realistic projection
88 if (SkScalarNearlyZero(h2.fZ)) {
89 return false;
90 }
91 // In some cases the crossing points are in the wrong direction
92 // to map (-1,-1) to pts3D[0], so we need to correct for that.
93 // Want h0 to be to the right of the left edge.
94 SkVector3 v = pts3D[3] - pts3D[0];
95 SkVector3 w = h0 - pts3D[0];
96 SkScalar perpDot = v.fX*w.fY - v.fY*w.fX;
97 if (perpDot > 0) {
98 h0 = -h0;
99 }
100 // Want h1 to be above the bottom edge.
101 v = pts3D[1] - pts3D[0];
102 perpDot = v.fX*w.fY - v.fY*w.fX;
103 if (perpDot < 0) {
104 h1 = -h1;
105 }
106 shadowTransform->setAll(h0.fX / h2.fZ, h1.fX / h2.fZ, h2.fX / h2.fZ,
107 h0.fY / h2.fZ, h1.fY / h2.fZ, h2.fY / h2.fZ,
108 h0.fZ / h2.fZ, h1.fZ / h2.fZ, 1);
109 // generate matrix that transforms from bounds to [-1,1]x[-1,1] square
110 SkMatrix toHomogeneous;
111 SkScalar xScale = 2/(pathBounds.fRight - pathBounds.fLeft);
112 SkScalar yScale = 2/(pathBounds.fBottom - pathBounds.fTop);
113 toHomogeneous.setAll(xScale, 0, -xScale*pathBounds.fLeft - 1,
114 0, yScale, -yScale*pathBounds.fTop - 1,
115 0, 0, 1);
116 shadowTransform->preConcat(toHomogeneous);
117
118 *radius = SkDrawShadowMetrics::SpotBlurRadius(occluderHeight, lightPos.fZ, lightRadius);
119 }
120
121 return true;
122}
123
124void GetLocalBounds(const SkPath& path, const SkDrawShadowRec& rec, const SkMatrix& ctm,
125 SkRect* bounds) {
126 SkRect ambientBounds = path.getBounds();
127 SkScalar occluderZ;
129 occluderZ = rec.fZPlaneParams.fZ;
130 } else {
131 occluderZ = compute_z(ambientBounds.fLeft, ambientBounds.fTop, rec.fZPlaneParams);
132 occluderZ = std::max(occluderZ, compute_z(ambientBounds.fRight, ambientBounds.fTop,
133 rec.fZPlaneParams));
134 occluderZ = std::max(occluderZ, compute_z(ambientBounds.fLeft, ambientBounds.fBottom,
135 rec.fZPlaneParams));
136 occluderZ = std::max(occluderZ, compute_z(ambientBounds.fRight, ambientBounds.fBottom,
137 rec.fZPlaneParams));
138 }
139 SkScalar ambientBlur;
140 SkScalar spotBlur;
141 SkScalar spotScale;
142 SkPoint spotOffset;
143 if (ctm.hasPerspective()) {
144 // transform ambient and spot bounds into device space
145 ctm.mapRect(&ambientBounds);
146
147 // get ambient blur (in device space)
148 ambientBlur = SkDrawShadowMetrics::AmbientBlurRadius(occluderZ);
149
150 // get spot params (in device space)
153 rec.fLightPos.fZ, rec.fLightRadius,
154 &spotBlur, &spotScale, &spotOffset);
155 } else {
156 SkPoint devLightPos = SkPoint::Make(rec.fLightPos.fX, rec.fLightPos.fY);
157 ctm.mapPoints(&devLightPos, 1);
158 SkDrawShadowMetrics::GetSpotParams(occluderZ, devLightPos.fX, devLightPos.fY,
159 rec.fLightPos.fZ, rec.fLightRadius,
160 &spotBlur, &spotScale, &spotOffset);
161 }
162 } else {
163 SkScalar devToSrcScale = SkScalarInvert(ctm.getMinScale());
164
165 // get ambient blur (in local space)
166 SkScalar devSpaceAmbientBlur = SkDrawShadowMetrics::AmbientBlurRadius(occluderZ);
167 ambientBlur = devSpaceAmbientBlur*devToSrcScale;
168
169 // get spot params (in local space)
172 rec.fLightPos.fZ, rec.fLightRadius,
173 &spotBlur, &spotScale, &spotOffset);
174 // light dir is in device space, so need to map spot offset back into local space
175 SkMatrix inverse;
176 if (ctm.invert(&inverse)) {
177 inverse.mapVectors(&spotOffset, 1);
178 }
179 } else {
181 rec.fLightPos.fZ, rec.fLightRadius,
182 &spotBlur, &spotScale, &spotOffset);
183 }
184
185 // convert spot blur to local space
186 spotBlur *= devToSrcScale;
187 }
188
189 // in both cases, adjust ambient and spot bounds
190 SkRect spotBounds = ambientBounds;
191 ambientBounds.outset(ambientBlur, ambientBlur);
192 spotBounds.fLeft *= spotScale;
193 spotBounds.fTop *= spotScale;
194 spotBounds.fRight *= spotScale;
195 spotBounds.fBottom *= spotScale;
196 spotBounds.offset(spotOffset.fX, spotOffset.fY);
197 spotBounds.outset(spotBlur, spotBlur);
198
199 // merge bounds
200 *bounds = ambientBounds;
201 bounds->join(spotBounds);
202 // outset a bit to account for floating point error
203 bounds->outset(1, 1);
204
205 // if perspective, transform back to src space
206 if (ctm.hasPerspective()) {
207 // TODO: create tighter mapping from dev rect back to src rect
208 SkMatrix inverse;
209 if (ctm.invert(&inverse)) {
210 inverse.mapRect(bounds);
211 }
212 }
213}
214
215
216} // namespace SkDrawShadowMetrics
217
#define SkScalarInvert(x)
Definition SkScalar.h:73
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition SkScalar.h:101
#define SK_Scalar1
Definition SkScalar.h:18
#define SK_ScalarNearlyZero
Definition SkScalar.h:99
@ kDirectionalLight_ShadowFlag
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
void mapVectors(SkVector dst[], const SkVector src[], int count) const
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition SkMatrix.h:562
void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty)
Definition SkMatrix.h:1803
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
Definition SkMatrix.cpp:770
bool invert(SkMatrix *inverse) const
Definition SkMatrix.h:1206
SkScalar getMinScale() const
SkMatrix & preConcat(const SkMatrix &other)
Definition SkMatrix.cpp:674
bool hasPerspective() const
Definition SkMatrix.h:312
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
void mapRectToQuad(SkPoint dst[4], const SkRect &rect) const
Definition SkMatrix.h:1620
const EmbeddedViewParams * params
float SkScalar
Definition extension.cpp:12
double y
double x
bool GetSpotShadowTransform(const SkPoint3 &lightPos, SkScalar lightRadius, const SkMatrix &ctm, const SkPoint3 &zPlaneParams, const SkRect &pathBounds, bool directional, SkMatrix *shadowTransform, SkScalar *radius)
void GetLocalBounds(const SkPath &path, const SkDrawShadowRec &rec, const SkMatrix &ctm, SkRect *bounds)
static SkScalar compute_z(SkScalar x, SkScalar y, const SkPoint3 &params)
void GetDirectionalParams(SkScalar occluderZ, SkScalar lightX, SkScalar lightY, SkScalar lightZ, SkScalar lightRadius, SkScalar *blurRadius, SkScalar *scale, SkVector *translate)
SkScalar AmbientBlurRadius(SkScalar height)
void GetSpotParams(SkScalar occluderZ, SkScalar lightX, SkScalar lightY, SkScalar lightZ, SkScalar lightRadius, SkScalar *blurRadius, SkScalar *scale, SkVector *translate)
SkScalar SpotBlurRadius(SkScalar occluderZ, SkScalar lightZ, SkScalar lightRadius)
SkScalar w
const Scalar scale
SkPoint3 cross(const SkPoint3 &vec) const
Definition SkPoint3.h:141
SkScalar fX
Definition SkPoint3.h:16
SkScalar fZ
Definition SkPoint3.h:16
void set(SkScalar x, SkScalar y, SkScalar z)
Definition SkPoint3.h:28
SkScalar fY
Definition SkPoint3.h:16
float fX
x-axis value
static constexpr SkPoint Make(float x, float y)
float fY
y-axis value
SkScalar fBottom
larger y-axis bounds
Definition extension.cpp:17
SkScalar fLeft
smaller x-axis bounds
Definition extension.cpp:14
void outset(float dx, float dy)
Definition SkRect.h:1077
SkScalar fRight
larger x-axis bounds
Definition extension.cpp:16
constexpr float centerX() const
Definition SkRect.h:776
void offset(float dx, float dy)
Definition SkRect.h:1016
constexpr float height() const
Definition SkRect.h:769
constexpr float centerY() const
Definition SkRect.h:785
constexpr float width() const
Definition SkRect.h:762
SkScalar fTop
smaller y-axis bounds
Definition extension.cpp:15