[svg] Implement distant light sources for specular lighting
https://www.w3.org/TR/SVG11/filters.html#feDistantLightElement (specular lighting only in this CL) Tests filters-specular-01-f and filters-light-02-f should be passing now. Note that our filters-light-02 result matches the behavior of Chrome and Firefox, but is different than the official W3C png. We currently think the test is somewhat poorly written, so we are comfortable matching the output of Chrome and Firefox. Bug: skia:10841 Change-Id: Id9517c8594a3826e5d98685d1e7d1d1b3d3cdf51 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/402582 Reviewed-by: Florin Malita <fmalita@chromium.org> Commit-Queue: Tyler Denniston <tdenniston@google.com>
This commit is contained in:
parent
0d174586c4
commit
f208f81e1d
@ -11,6 +11,7 @@
|
||||
#include "modules/svg/include/SkSVGFe.h"
|
||||
#include "modules/svg/include/SkSVGTypes.h"
|
||||
|
||||
class SkSVGFeDistantLight;
|
||||
class SkSVGFePointLight;
|
||||
|
||||
class SkSVGFeLighting : public SkSVGFe {
|
||||
@ -33,6 +34,10 @@ protected:
|
||||
sk_sp<SkImageFilter> onMakeImageFilter(const SkSVGRenderContext&,
|
||||
const SkSVGFilterContext&) const final;
|
||||
|
||||
virtual sk_sp<SkImageFilter> makeDistantLight(const SkSVGRenderContext&,
|
||||
const SkSVGFilterContext&,
|
||||
const SkSVGFeDistantLight*) const = 0;
|
||||
|
||||
virtual sk_sp<SkImageFilter> makePointLight(const SkSVGRenderContext&,
|
||||
const SkSVGFilterContext&,
|
||||
const SkSVGFePointLight*) const = 0;
|
||||
@ -61,6 +66,10 @@ public:
|
||||
protected:
|
||||
bool parseAndSetAttribute(const char*, const char*) override;
|
||||
|
||||
sk_sp<SkImageFilter> makeDistantLight(const SkSVGRenderContext&,
|
||||
const SkSVGFilterContext&,
|
||||
const SkSVGFeDistantLight*) const final;
|
||||
|
||||
sk_sp<SkImageFilter> makePointLight(const SkSVGRenderContext&,
|
||||
const SkSVGFilterContext&,
|
||||
const SkSVGFePointLight*) const final;
|
||||
|
@ -39,9 +39,12 @@ sk_sp<SkImageFilter> SkSVGFeLighting::onMakeImageFilter(const SkSVGRenderContext
|
||||
const SkSVGFilterContext& fctx) const {
|
||||
for (const auto& child : fChildren) {
|
||||
switch (child->tag()) {
|
||||
case SkSVGTag::kFeDistantLight:
|
||||
return this->makeDistantLight(
|
||||
ctx, fctx, static_cast<const SkSVGFeDistantLight*>(child.get()));
|
||||
case SkSVGTag::kFePointLight:
|
||||
return this->makePointLight(ctx, fctx,
|
||||
static_cast<const SkSVGFePointLight*>(child.get()));
|
||||
return this->makePointLight(
|
||||
ctx, fctx, static_cast<const SkSVGFePointLight*>(child.get()));
|
||||
default:
|
||||
// Ignore unknown children, such as <desc> elements
|
||||
break;
|
||||
@ -88,6 +91,33 @@ bool SkSVGFeSpecularLighting::parseAndSetAttribute(const char* n, const char* v)
|
||||
SkSVGAttributeParser::parse<SkSVGNumberType>("specularExponent", n, v));
|
||||
}
|
||||
|
||||
sk_sp<SkImageFilter> SkSVGFeSpecularLighting::makeDistantLight(
|
||||
const SkSVGRenderContext& ctx,
|
||||
const SkSVGFilterContext& fctx,
|
||||
const SkSVGFeDistantLight* light) const {
|
||||
const auto computeDirection = [](float azimuth, float elevation) -> SkPoint3 {
|
||||
// Computing direction from azimuth+elevation is two 3D rotations:
|
||||
// - Rotate [1,0,0] about y axis first (elevation)
|
||||
// - Rotate result about z axis (azimuth)
|
||||
// Which is just the first column vector in the 3x3 matrix Rz*Ry.
|
||||
const float azimuthRad = SkDegreesToRadians(azimuth);
|
||||
const float elevationRad = SkDegreesToRadians(elevation);
|
||||
const float sinAzimuth = sinf(azimuthRad), cosAzimuth = cosf(azimuthRad);
|
||||
const float sinElevation = sinf(elevationRad), cosElevation = cosf(elevationRad);
|
||||
return SkPoint3::Make(cosAzimuth * cosElevation, sinAzimuth * cosElevation, sinElevation);
|
||||
};
|
||||
|
||||
const SkPoint3 dir = computeDirection(light->getAzimuth(), light->getElevation());
|
||||
return SkImageFilters::DistantLitSpecular(
|
||||
this->resolveXYZ(ctx, fctx, dir.fX, dir.fY, dir.fZ),
|
||||
this->resolveLightingColor(ctx),
|
||||
this->getSurfaceScale(),
|
||||
fSpecularConstant,
|
||||
fSpecularExponent,
|
||||
fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
|
||||
this->resolveFilterSubregion(ctx, fctx));
|
||||
}
|
||||
|
||||
sk_sp<SkImageFilter> SkSVGFeSpecularLighting::makePointLight(const SkSVGRenderContext& ctx,
|
||||
const SkSVGFilterContext& fctx,
|
||||
const SkSVGFePointLight* light) const {
|
||||
|
Loading…
Reference in New Issue
Block a user