Fix directional shadows.

The xy offset calculation for drawShadow was not quite correct. Rather
than normalizing the light vector and using the xy values of that as the
base offset value, we should scale the light vector by 1/z.

See https://github.com/flutter/engine/pull/27124#issuecomment-880182653
for more detail.

Bug: skia:10781
Change-Id: Ib69a313cb96a532f8d89644e3d69f666a184e897
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/428880
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2021-07-15 11:37:09 -04:00 committed by Skia Commit-Bot
parent dfec4f98ef
commit 6789b82401
5 changed files with 11 additions and 17 deletions

View File

@ -34,7 +34,7 @@ class MaterialShadowsView : public Sample {
fLargeRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-64, -64, 128, 128), 4, 4));
fSmallRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-40, -40, 80, 80), 4, 4));
fLightPos = SkPoint3::Make(0, -700, 600);
fLightPos = SkPoint3::Make(0, -700, 700);
}
SkString name() override { return SkString("MaterialShadows"); }

View File

@ -151,10 +151,8 @@ void GetLocalBounds(const SkPath& path, const SkDrawShadowRec& rec, const SkMatr
// get spot params (in device space)
if (SkToBool(rec.fFlags & SkShadowFlags::kDirectionalLight_ShadowFlag)) {
SkPoint3 lightDir = rec.fLightPos;
lightDir.normalize();
SkDrawShadowMetrics::GetDirectionalParams(occluderZ, lightDir.fX, lightDir.fY,
lightDir.fZ, rec.fLightRadius,
SkDrawShadowMetrics::GetDirectionalParams(occluderZ, rec.fLightPos.fX, rec.fLightPos.fY,
rec.fLightPos.fZ, rec.fLightRadius,
&spotBlur, &spotScale, &spotOffset);
} else {
SkPoint devLightPos = SkPoint::Make(rec.fLightPos.fX, rec.fLightPos.fY);
@ -172,10 +170,8 @@ void GetLocalBounds(const SkPath& path, const SkDrawShadowRec& rec, const SkMatr
// get spot params (in local space)
if (SkToBool(rec.fFlags & SkShadowFlags::kDirectionalLight_ShadowFlag)) {
SkPoint3 lightDir = rec.fLightPos;
lightDir.normalize();
SkDrawShadowMetrics::GetDirectionalParams(occluderZ, lightDir.fX, lightDir.fY,
lightDir.fZ, rec.fLightRadius,
SkDrawShadowMetrics::GetDirectionalParams(occluderZ, rec.fLightPos.fX, rec.fLightPos.fY,
rec.fLightPos.fZ, rec.fLightRadius,
&spotBlur, &spotScale, &spotOffset);
// light dir is in device space, so need to map spot offset back into local space
SkMatrix inverse;

View File

@ -68,8 +68,10 @@ inline void GetDirectionalParams(SkScalar occluderZ, SkScalar lightX, SkScalar l
SkScalar* blurRadius, SkScalar* scale, SkVector* translate) {
*blurRadius = lightRadius*occluderZ;
*scale = 1;
// assumption here is that light direction is normalized
*translate = SkVector::Make(-occluderZ * lightX, -occluderZ * lightY);
// Max z-ratio is "max expected elevation"/"min allowable z"
constexpr SkScalar kMaxZRatio = 64/SK_ScalarNearlyZero;
SkScalar zRatio = divide_and_pin(occluderZ, lightZ, 0.0f, kMaxZRatio);
*translate = SkVector::Make(-zRatio * lightX, -zRatio * lightY);
}
// Create the transformation to apply to a path to get its base shadow outline, given the light

View File

@ -1152,9 +1152,7 @@ bool GrSurfaceDrawContext::drawFastShadow(const GrClip* clip,
SkPoint3 devLightPos = rec.fLightPos;
bool directional = SkToBool(rec.fFlags & kDirectionalLight_ShadowFlag);
if (directional) {
devLightPos.normalize();
} else {
if (!directional) {
// transform light
viewMatrix.mapPoints((SkPoint*)&devLightPos.fX, 1);
}

View File

@ -664,9 +664,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
SkPoint3 zPlaneParams = rec.fZPlaneParams;
SkPoint3 devLightPos = rec.fLightPos;
if (directional) {
devLightPos.normalize();
} else {
if (!directional) {
viewMatrix.mapPoints((SkPoint*)&devLightPos.fX, 1);
}
float lightRadius = rec.fLightRadius;