-
Notifications
You must be signed in to change notification settings - Fork 6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[flow] Switch to directional shadows #27124
Conversation
flow/layers/physical_shape_layer.cc
Outdated
const SkScalar kLightHeight = 600; | ||
const SkScalar kLightRadius = 800; | ||
const SkScalar kLightXOffset = 0; | ||
const SkScalar kLightYOffset = -450; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code used to use an offset of -600 from the top of the bounds, but the value is now hard-coded as a -450 offset directionally. Doesn't that produce a different effect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or is this change intentional due to undesired results of the previous fixed offset?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. I just copied these values from canvaskit/util.dart. We should ask this to @yjbanov.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The values we use on the web side don't have much science to them. We just eyeballed the result and checked with the material team. In the 6 months since the change we've received zero complaints about how the shadows look.
I investigated ambientBlur = 0.5 * zPlane.z / ctm.getMinScale()
if kDirectionalLight_ShadowFlag in flags:
spotBlur = lightRadius * zPlane.z / ctm.getMinScale()
spotScale = 1
spotOffset.x = - lightPos.normalize().x * zPlane.z / ctm.getMinScale()
spotOffset.y = - lightPos.normalize().y * zPlane.z / ctm.getMinScale()
else:
spotBlur = lightRadius * (zPlane.z / (lightPos.z - zPlane.z)) / ctm.getMinScale()
spotScale = lightPos.z / (lightPos.z - zPlane.z)
spotOffset.x = - (zPlane.z / (lightPos.z - zPlane.z)) *
((lightPos.x - ctm.getTranslateX()) / ctm.getMinScale())
spotOffset.y = - (zPlane.z / (lightPos.z - zPlane.z)) *
((lightPos.y - ctm.getTranslateY()) / ctm.getMinScale()) If these equations applied to the old implementation: ambientBlur = 0.5 * elevation
spotBlur = kLightRadius * elevation / (kLightHeight - elevation)
spotScale = kLightHeight / (kLightHeight - elevation)
spotOffset.x = - elevation / (kLightHeight - elevation) *
(((bounds.left() + bounds.right()) / 2 - ctm.getTranslateX()) / ctm.getMinScale())
spotOffset.y = - elevation / (kLightHeight - elevation) *
((bounds.top() - kLightHeight - ctm.getTranslateY()) / ctm.getMinScale()) These 5 variables needs to be equal between old and new implementation but it is impossible. ambientBlur = 0.5 * elevation
spotBlur = kLightRadius / kLightHeight * elevation
spotScale = 1
spotOffset.x = 0
spotOffset.y = elevation / ctm.getMinScale() Let's find out new implementation's values: 0.5 * zPlane.z / ctm.getMinScale() = 0.5 * elevation
lightRadius * zPlane.z / ctm.getMinScale() = kLightRadius / kLightHeight * elevation
- zPlane.z * lightPos.normalize().x / ctm.getMinScale() = 0
- zPlane.z * lightPos.normalize().y / ctm.getMinScale() = elevation / ctm.getMinScale() After simplifying: zPlane.z = elevation * ctm.getMinScale()
lightRadius = kLightRadius / kLightHeight
lightPos.normalize().x = 0
lightPos.normalize().y = - 1 / ctm.getMinScale()
SkShadowUtils::GetLocalBounds(
ctm,
path,
SkPoint3::Make(0, 0, elevation * dpr),
SkPoint3::Make(0, -1, 0),
kLightRadius / kLightHeight,
SkShadowFlags::kDirectionalLight_ShadowFlag,
&shadow_bounds); These are results of different rects calculated with old and new implementation:
|
I think that may be a mistake in tactics. This assumes that the old implementation was correct. In particular, when I was using the PhysicalShapeLayer to compute bounds for my DisplayList tests I ran into problems with it not enclosing all of the pixels that were rendered (the DL tests do OOB testing for rendering vs DL.bounds()). I ended up ignoring it and using GetLocalBounds in the shadow utils instead for DL bounds computations. The goal here will be to make sure that the bounds computed encompass the rendering, not that they are compatible with the prior implementation of something. It would be nice if they were no looser than the old implementation as well, for performance. With respect to rendering, we need to decide what the goal is here. Some of the comments linked above talked about not matching the Material spec, and I think we do need to ensure our Material widgets match the material spec. We also need to consider that we have Cupertino widgets that may also use these shadows and need to be compatible with the Cupertino spec. If they are dragging us in 2 different directions with how we interpret various values like elevation and light direction, then maybe we need to add some extra parameters to our shadow parameters, but hopefully they have similar enough shadow specs that we can meet them with the existing parameters. |
I think, people want to see same shadows after this fix. Because this PR edits code that 4 years old. Material specification is not strict, it doesn't provide values, it just say combine shadow from key and ambient lights. I don't know what is the goal. I just fixed the above issues. Now shadows doesn't depend on Maybe we need to invite someone from material design team. Also here are some screenshots |
So the reason the resulting direction is unintuitive is that this case has exposed a bug in the directional lighting code. Rather than
it should be
(This also makes me think that the blur could be
though either way it's sort of a hack. A true directional light wouldn't normally affect blur, since it's infinitely far away.) In any case, with those changes |
Oh, and once I land this fix it probably means that the Web values would have to change, depending on how sharp the lighting angle is. |
Wouldn't |
Yeah, any vector pointing in that direction would work, I just normalized it out of habit. |
We can address the web side in a separate PR. We roll Skia with CanvasKit releases, so this won't take effect immediately. Thanks for the heads up though. |
Sounds good, I'll land the fix tomorrow morning. |
When the Skia fix lands and this PR will have to be rebased to catch it, I think that may also fix the odd error in the Linux Android Scenarios as well. |
Just a status update. I'm on the CC thread for the Skia fix to the directional shadow math and it is actively being worked on. The delays are minor and related to making sure it passes all tests and golden image comparisons. |
The fix has landed: https://skia-review.googlesource.com/c/skia/+/428978 |
Try rebasing to >= c120a50 to check with the fix in place. |
I already rebased with previous commits. My branch's DEPS' skia_revision is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This is a reland of 6789b82 Original change's description: > 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 flutter/engine#27124 (comment) > for more detail. > > Bug: skia:10781 > Change-Id: Ib69a313cb96a532f8d89644e3d69f666a184e897 > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/428880 > Reviewed-by: Brian Salomon <[email protected]> > Commit-Queue: Jim Van Verth <[email protected]> Bug: skia:10781 Change-Id: Ib58d374aa03d0144512e5ded6ccd572c74783607 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/428978 Reviewed-by: Brian Salomon <[email protected]> Commit-Queue: Jim Van Verth <[email protected]>
Shadows incorrectly offset, shifts incrementally. This issue fixed by Skia with Issue 10781: Add orthographic shadow support. We need to add
SkShadowFlags::kDirectionalLight_ShadowFlag
toDrawShadow
.Related Issues
fixes flutter/flutter#28463
fixes flutter/flutter#51237
Pre-launch Checklist
///
).