/* * Copyright 2021 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkBlendMode.h" #include "include/core/SkCanvas.h" #include "include/core/SkColor.h" #include "include/core/SkM44.h" #include "include/core/SkMatrix.h" #include "include/core/SkPaint.h" #include "include/core/SkPicture.h" #include "include/core/SkPictureRecorder.h" #include "include/core/SkRect.h" #include "include/core/SkRefCnt.h" #include "include/core/SkSamplingOptions.h" #include "include/core/SkScalar.h" #include "include/core/SkShader.h" #include "include/core/SkSize.h" #include "include/core/SkString.h" #include "include/core/SkTileMode.h" #include "include/effects/SkRuntimeEffect.h" #include "include/private/base/SkAssert.h" #include "include/private/base/SkPoint_impl.h" #include "include/private/base/SkTPin.h" #include "modules/skottie/src/Adapter.h" #include "modules/skottie/src/SkottiePriv.h" #include "modules/skottie/src/SkottieValue.h" #include "modules/skottie/src/effects/Effects.h" #include "modules/sksg/include/SkSGNode.h" #include "modules/sksg/include/SkSGRenderNode.h" #include <array> #include <cmath> #include <cstdio> #include <utility> #include <vector> namespace skjson { class ArrayValue; } namespace sksg { class InvalidationController; } namespace skottie::internal { namespace { // This shader maps its child shader onto a sphere. To simplify things, we set it up such that: // // - the sphere is centered at origin and has r == 1 // - the eye is positioned at (0,0,eye_z), where eye_z is chosen to visually match AE // - the POI for a given pixel is on the z = 0 plane (x,y,0) // - we're only rendering inside the projected circle, which guarantees a quadratic solution // // Effect stages: // // 1) ray-cast to find the sphere intersection (selectable front/back solution); // given the sphere geometry, this is also the normal // 2) rotate the normal // 3) UV-map the sphere // 4) scale uv to source size and sample // 5) apply lighting model // // Note: the current implementation uses two passes for two-side ("full") rendering, on the // assumption that in practice most textures are opaque and two-side mode is infrequent; // if this proves to be problematic, we could expand the implementation to blend both sides // in one pass. // static constexpr char gSphereSkSL[] = … ; // CC Sphere uses a Phong-like lighting model: // // - "ambient" controls the intensity of the texture color // - "diffuse" controls a multiplicative mix of texture and light color // - "specular" controls a light color specular component // - "roughness" is the specular exponent reciprocal // - "light intensity" modulates the diffuse and specular components (but not ambient) // - "light height" and "light direction" specify the light source position in spherical coords // // Implementation-wise, light intensity/height/direction are all combined into l_vec. // For efficiency, we fall back to a stripped-down shader (ambient-only) when the diffuse & specular // components are not used. // // TODO: "metal" and "reflective" parameters are ignored. static constexpr char gBasicLightSkSL[] = … ; static constexpr char gFancyLightSkSL[] = … ; static sk_sp<SkRuntimeEffect> sphere_fancylight_effect() { … } static sk_sp<SkRuntimeEffect> sphere_basiclight_effect() { … } class SphereNode final : public sksg::CustomRenderNode { … }; class SphereAdapter final : public DiscardableAdapterBase<SphereAdapter, SphereNode> { … }; } // namespace sk_sp<sksg::RenderNode> EffectBuilder::attachSphereEffect( const skjson::ArrayValue& jprops, sk_sp<sksg::RenderNode> layer) const { … } } // namespace skottie::internal