Added distance attenuation and diffuse shading to PointLights
authorvjiaoblack <vjiaoblack@google.com>
Fri, 26 Aug 2016 15:49:46 +0000 (08:49 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 26 Aug 2016 15:49:46 +0000 (08:49 -0700)
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2246463004

Review-Url: https://codereview.chromium.org/2246463004

include/core/SkLights.h
samplecode/SampleShadowing.cpp
src/core/SkLights.cpp
src/core/SkShadowShader.cpp
src/utils/SkShadowPaintFilterCanvas.cpp

index 329e5d3..d8ec87d 100644 (file)
@@ -30,14 +30,16 @@ public:
         Light(const Light& other)
             : fType(other.fType)
             , fColor(other.fColor)
-            , fDirection(other.fDirection)
+            , fDirOrPos(other.fDirOrPos)
+            , fIntensity(other.fIntensity)
             , fShadowMap(other.fShadowMap) {
         }
 
         Light(Light&& other)
             : fType(other.fType)
             , fColor(other.fColor)
-            , fDirection(other.fDirection)
+            , fDirOrPos(other.fDirOrPos)
+            , fIntensity(other.fIntensity)
             , fShadowMap(std::move(other.fShadowMap)) {
         }
 
@@ -47,25 +49,29 @@ public:
 
         static Light MakeDirectional(const SkColor3f& color, const SkVector3& dir) {
             Light light(kDirectional_LightType, color, dir);
-            if (!light.fDirection.normalize()) {
-                light.fDirection.set(0.0f, 0.0f, 1.0f);
+            if (!light.fDirOrPos.normalize()) {
+                light.fDirOrPos.set(0.0f, 0.0f, 1.0f);
             }
             return light;
         }
 
-        static Light MakePoint(const SkColor3f& color, const SkPoint3& pos) {
-            return Light(kPoint_LightType, color, pos);
+        static Light MakePoint(const SkColor3f& color, const SkPoint3& pos, SkScalar intensity) {
+            return Light(kPoint_LightType, color, pos, intensity);
         }
 
         LightType type() const { return fType; }
         const SkColor3f& color() const { return fColor; }
         const SkVector3& dir() const {
             SkASSERT(kDirectional_LightType == fType);
-            return fDirection;
+            return fDirOrPos;
         }
         const SkPoint3& pos() const {
             SkASSERT(kPoint_LightType == fType);
-            return fDirection;
+            return fDirOrPos;
+        }
+        SkScalar intensity() const {
+            SkASSERT(kPoint_LightType == fType);
+            return fIntensity;
         }
 
         void setShadowMap(sk_sp<SkImage> shadowMap) {
@@ -83,7 +89,8 @@ public:
 
             fColor = b.fColor;
             fType = b.fType;
-            fDirection = b.fDirection;
+            fDirOrPos = b.fDirOrPos;
+            fIntensity = b.fIntensity;
             fShadowMap = b.fShadowMap;
             return *this;
         }
@@ -95,8 +102,9 @@ public:
 
             return (fColor     == b.fColor) &&
                    (fType      == b.fType) &&
-                   (fDirection == b.fDirection) &&
-                   (fShadowMap == b.fShadowMap);
+                   (fDirOrPos  == b.fDirOrPos) &&
+                   (fShadowMap == b.fShadowMap) &&
+                   (fIntensity == b.fIntensity);
         }
 
         bool operator!= (const Light& b) { return !(this->operator==(b)); }
@@ -104,16 +112,22 @@ public:
     private:
         LightType   fType;
         SkColor3f   fColor;           // linear (unpremul) color. Range is 0..1 in each channel.
-        SkVector3   fDirection;       // For directional lights, holds the direction towards the
+
+        SkVector3   fDirOrPos;        // For directional lights, holds the direction towards the
                                       // light (+Z is out of the screen).
                                       // If degenerate, it will be replaced with (0, 0, 1).
                                       // For point lights, holds location of point light
+
+        SkScalar    fIntensity;       // For point lights, dictates the light intensity.
+                                      // Simply a multiplier to the final light output value.
         sk_sp<SkImage> fShadowMap;
 
-        Light(LightType type, const SkColor3f& color, const SkVector3& dir) {
+        Light(LightType type, const SkColor3f& color,
+              const SkVector3& dir, SkScalar intensity = 0.0f) {
             fType = type;
             fColor = color;
-            fDirection = dir;
+            fDirOrPos = dir;
+            fIntensity = intensity;
         }
     };
 
index e27b4cf..4892f9c 100644 (file)
 
 class ShadowingView : public SampleView {
 public:
-    ShadowingView() {
-
+    ShadowingView()
+        : fSceneChanged(true)
+        , fLightsChanged(true)
+        , fMoveLight(false)
+        , fClearShadowMaps(false)
+        , fSelectedRectID(-1)
+        , fSelectedSliderID(-1)
+        , fLightDepth(300.0f)  {
         this->setBGColor(0xFFCCCCCC);
-        SkLights::Builder builder;
-        builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.2f, 0.3f, 0.4f),
-                                                     SkVector3::Make(0.2f, 0.05f, 1.0f)));
-        builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.4f, 0.3f, 0.2f),
-                                                     SkVector3::Make(0.05f, 0.2f, 1.0f)));
-        builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.4f, 0.4f, 0.4f)));
-        fLights = builder.finish();
+
+        this->updateLights(200, 200);
 
         fTestRects[0].fColor = 0xFFEE8888;
         fTestRects[0].fDepth = 80;
@@ -50,16 +51,7 @@ public:
         fSliders[2].fOffset = 0.0f;
         fSliders[2].fScale = 0.0025f;
 
-        fSceneChanged = true;
-        fLightsChanged = true;
-
-        fSelectedRect = -1;
-        fSelectedSlider = -1;
-        fMoveLight = false;
-
-        fClearShadowMaps = false;
-
-        fShadowParams.fShadowRadius = 2.0f;
+        fShadowParams.fShadowRadius = 4.0f;
         fShadowParams.fBiasingConstant = 0.3f;
         fShadowParams.fMinVariance = 1024;
         fShadowParams.fType = SkShadowParams::kVariance_ShadowType;
@@ -85,6 +77,9 @@ protected:
                     // the shadow maps will be re-generated according to the new backend.
                     fClearShadowMaps = true;
                     break;
+                case 'q':
+                    fLightDepth += 5.0f;
+                    fMoveLight = true;
                 case 'B':
                     if (SkShadowParams::kVariance_ShadowType == fShadowParams.fType) {
                         fShadowParams.fType = SkShadowParams::kNoBlur_ShadowType;
@@ -94,6 +89,10 @@ protected:
                     }
                     fLightsChanged = true;
                     break;
+                case 'w':
+                    fLightDepth -= 5.0f;
+                    fMoveLight = true;
+                    break;
                 default:
                     break;
             }
@@ -160,12 +159,29 @@ protected:
         return new SkView::Click(this);
     }
 
+    void updateLights(int x, int y) {
+        SkLights::Builder builder;
+        builder.add(SkLights::Light::MakePoint(SkColor3f::Make(0.2f, 0.4f, 0.6f),
+                                               SkVector3::Make(x - 50,
+                                                               350 - y,
+                                                               fLightDepth),
+                                               1024));
+        builder.add(SkLights::Light::MakePoint(SkColor3f::Make(0.6f, 0.4f, 0.2f),
+                                               SkVector3::Make(x + 50,
+                                                               450 - y,
+                                                               fLightDepth),
+                                               1024));
+        builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.2f, 0.2f, 0.2f),
+                                                     SkVector3::Make(0.2f, 0.2f, 1.0f)));
+        fLights = builder.finish();
+    }
+
     void updateFromSelectedSlider() {
-        SkScalar newValue = fSliders[fSelectedSlider].fGeometry.fLeft *
-                            fSliders[fSelectedSlider].fScale +
-                            fSliders[fSelectedSlider].fOffset;
+        SkScalar newValue = fSliders[fSelectedSliderID].fGeometry.fLeft *
+                            fSliders[fSelectedSliderID].fScale +
+                            fSliders[fSelectedSliderID].fOffset;
 
-        switch (fSelectedSlider) {
+        switch (fSelectedSliderID) {
             case 0:
                 fShadowParams.fShadowRadius = newValue;
                 break;
@@ -189,24 +205,7 @@ protected:
 
         if (fMoveLight) {
             if (dx != 0 || dy != 0) {
-                float recipX = 1.0f / kWidth;
-                float recipY = 1.0f / kHeight;
-
-                SkLights::Builder builder;
-                builder.add(SkLights::Light::MakeDirectional(
-                        SkColor3f::Make(0.2f, 0.3f, 0.4f),
-                        SkVector3::Make(0.2f + (200.0f - x) * recipX,
-                                        0.05f + (200.0f - y) * recipY,
-                                        1.0f)));
-                builder.add(SkLights::Light::MakeDirectional(
-                        SkColor3f::Make(0.4f, 0.3f, 0.2f),
-                        SkVector3::Make(0.05f + (200.0f - x) * recipX,
-                                        0.2f + (200.0f - y) * recipY,
-                                        1.0f)));
-                builder.add(SkLights::Light::MakeAmbient(
-                        SkColor3f::Make(0.4f, 0.4f, 0.4f)));
-                fLights = builder.finish();
-
+                this->updateLights(x, y);
                 fLightsChanged = true;
                 this->inval(nullptr);
             }
@@ -214,21 +213,21 @@ protected:
         }
 
         if (click->fState == Click::State::kUp_State) {
-            fSelectedRect = -1;
-            fSelectedSlider = -1;
+            fSelectedRectID = -1;
+            fSelectedSliderID = -1;
             return true;
         }
 
-        if (fSelectedRect > -1) {
-            fTestRects[fSelectedRect].fGeometry.offset(dx, dy);
+        if (fSelectedRectID > -1) {
+            fTestRects[fSelectedRectID].fGeometry.offset(dx, dy);
 
             fSceneChanged = true;
             this->inval(nullptr);
             return true;
         }
 
-        if (fSelectedSlider > -1) {
-            fSliders[fSelectedSlider].fGeometry.offset(dx, 0);
+        if (fSelectedSliderID > -1) {
+            fSliders[fSelectedSliderID].fGeometry.offset(dx, 0);
 
             this->updateFromSelectedSlider();
 
@@ -240,7 +239,7 @@ protected:
         // assume last elements are highest
         for (int i = kNumTestRects - 1; i >= 0; i--) {
             if (fTestRects[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
-                fSelectedRect = i;
+                fSelectedRectID = i;
                 fTestRects[i].fGeometry.offset(dx, dy);
 
                 fSceneChanged = true;
@@ -251,7 +250,7 @@ protected:
 
         for (int i = 0; i <= kNumSliders; i++) {
             if (fSliders[i].fGeometry.contains(SkRect::MakeXYWH(x, y, 1, 1))) {
-                fSelectedSlider = i;
+                fSelectedSliderID = i;
                 fSliders[i].fGeometry.offset(dx, 0);
 
                 this->updateFromSelectedSlider();
@@ -273,24 +272,26 @@ private:
     static const int kWidth = 400;
     static const int kHeight = 400;
 
+    bool fSceneChanged;
+    bool fLightsChanged;
+    bool fMoveLight;
+    bool fClearShadowMaps;
+
     struct {
         SkRect  fGeometry;
         int     fDepth;
         SkColor fColor;
     } fTestRects[kNumTestRects];
-    int fSelectedRect;
+    int fSelectedRectID;
 
     struct {
         SkRect   fGeometry;
         SkScalar fOffset;
         SkScalar fScale;
     } fSliders[kNumSliders];
-    int fSelectedSlider;
+    int fSelectedSliderID;
 
-    bool fClearShadowMaps;
-    bool fMoveLight;
-    bool fSceneChanged;
-    bool fLightsChanged;
+    SkScalar fLightDepth;
 
     sk_sp<SkPicture> fPicture;
     SkShadowParams fShadowParams;
index a172de4..7d8f9ed 100644 (file)
@@ -29,6 +29,10 @@ sk_sp<SkLights> SkLights::MakeFromBuffer(SkReadBuffer& buf) {
             if (!buf.readScalarArray(&dirOrPos.fX, 3)) {
                 return nullptr;
             }
+            SkScalar intensity = 0.0f;
+            if (isPoint) {
+                intensity = buf.readScalar();
+            }
 
             sk_sp<SkImage> depthMap;
             bool hasShadowMap = buf.readBool();
@@ -39,7 +43,7 @@ sk_sp<SkLights> SkLights::MakeFromBuffer(SkReadBuffer& buf) {
             }
 
             if (isPoint) {
-                Light light = Light::MakePoint(color, dirOrPos);
+                Light light = Light::MakePoint(color, dirOrPos, intensity);
                 light.setShadowMap(depthMap);
                 builder.add(light);
             } else {
@@ -66,7 +70,12 @@ void SkLights::flatten(SkWriteBuffer& buf) const {
         buf.writeBool(isPoint);
         buf.writeScalarArray(&light.color().fX, 3);
         if (!isAmbient) {
-            buf.writeScalarArray(&light.dir().fX, 3);
+            if (isPoint) {
+                buf.writeScalarArray(&light.pos().fX, 3);
+                buf.writeScalar(light.intensity());
+            } else {
+                buf.writeScalarArray(&light.dir().fX, 3);
+            }
             bool hasShadowMap = light.getShadowMap() != nullptr;
             buf.writeBool(hasShadowMap);
             if (hasShadowMap) {
index 9ad23b7..49f1b01 100644 (file)
@@ -114,26 +114,35 @@ public:
         // fuse all ambient lights into a single one
         fAmbientColor.set(0.0f, 0.0f, 0.0f);
 
-        fNumDirLights = 0; // refers to directional lights.
+        fNumNonAmbLights = 0; // count of non-ambient lights
         for (int i = 0; i < lights->numLights(); ++i) {
             if (SkLights::Light::kAmbient_LightType == lights->light(i).type()) {
                 fAmbientColor += lights->light(i).color();
-            } else if (fNumDirLights < SkShadowShader::kMaxNonAmbientLights) {
-                fLightColor[fNumDirLights] = lights->light(i).color();
-                fLightDir[fNumDirLights] = lights->light(i).dir();
+            } else if (fNumNonAmbLights < SkShadowShader::kMaxNonAmbientLights) {
+                fLightColor[fNumNonAmbLights] = lights->light(i).color();
+                if (lights->light(i).type() == SkLights::Light::kPoint_LightType) {
+                    fLightDirOrPos[fNumNonAmbLights] = lights->light(i).pos();
+                    fLightIntensity[fNumNonAmbLights] = lights->light(i).intensity();
+                } else {
+                    fLightDirOrPos[fNumNonAmbLights] = lights->light(i).dir();
+                    fLightIntensity[fNumNonAmbLights] = 0.0f;
+                }
+                fIsPointLight[fNumNonAmbLights] =
+                         SkLights::Light::kPoint_LightType == lights->light(i).type();
+
                 SkImage_Base* shadowMap = ((SkImage_Base*)lights->light(i).getShadowMap());
 
                 // gets deleted when the ShadowFP is destroyed, and frees the GrTexture*
-                fTexture[fNumDirLights] = sk_sp<GrTexture>(shadowMap->asTextureRef(context,
+                fTexture[fNumNonAmbLights] = sk_sp<GrTexture>(shadowMap->asTextureRef(context,
                                                            GrTextureParams::ClampNoFilter(),
                                                            SkSourceGammaTreatment::kIgnore));
-                fDepthMapAccess[fNumDirLights].reset(fTexture[fNumDirLights].get());
-                this->addTextureAccess(&fDepthMapAccess[fNumDirLights]);
+                fDepthMapAccess[fNumNonAmbLights].reset(fTexture[fNumNonAmbLights].get());
+                this->addTextureAccess(&fDepthMapAccess[fNumNonAmbLights]);
 
-                fDepthMapHeight[fNumDirLights] = shadowMap->height();
-                fDepthMapWidth[fNumDirLights] = shadowMap->width();
+                fDepthMapHeight[fNumNonAmbLights] = shadowMap->height();
+                fDepthMapWidth[fNumNonAmbLights] = shadowMap->width();
 
-                fNumDirLights++;
+                fNumNonAmbLights++;
             }
         }
 
@@ -152,51 +161,54 @@ public:
         GLSLShadowFP() { }
 
         void emitCode(EmitArgs& args) override {
-
             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
+            const ShadowFP& shadowFP = args.fFp.cast<ShadowFP>();
+
+            SkASSERT(shadowFP.fNumNonAmbLights <= SkShadowShader::kMaxNonAmbientLights);
 
             // add uniforms
-            int32_t numLights = args.fFp.cast<ShadowFP>().fNumDirLights;
+            int32_t numLights = shadowFP.fNumNonAmbLights;
             SkASSERT(numLights <= SkShadowShader::kMaxNonAmbientLights);
 
-            int blurAlgorithm = args.fFp.cast<ShadowFP>().fShadowParams.fType;
+            int blurAlgorithm = shadowFP.fShadowParams.fType;
 
-            const char* lightDirUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
+            const char* lightDirOrPosUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
             const char* lightColorUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
+            const char* lightIntensityUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
 
-            const char* depthMapWidthUniName[SkShadowShader::kMaxNonAmbientLights]
-                    = {nullptr};
-            const char* depthMapHeightUniName[SkShadowShader::kMaxNonAmbientLights]
-                    = {nullptr};
+            const char* depthMapWidthUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
+            const char* depthMapHeightUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
 
-            SkString lightDirUniNameBase("lightDir");
-            SkString lightColorUniNameBase("lightColor");
-
-            SkString depthMapWidthUniNameBase("dmapWidth");
-            SkString depthMapHeightUniNameBase("dmapHeight");
-
-            for (int i = 0; i < numLights; i++) {
-                SkString lightDirUniNameStr(lightDirUniNameBase);
-                lightDirUniNameStr.appendf("%d", i);
-                SkString lightColorUniNameStr(lightColorUniNameBase);
+            for (int i = 0; i < shadowFP.fNumNonAmbLights; i++) {
+                SkString lightDirOrPosUniNameStr("lightDir");
+                lightDirOrPosUniNameStr.appendf("%d", i);
+                SkString lightColorUniNameStr("lightColor");
                 lightColorUniNameStr.appendf("%d", i);
+                SkString lightIntensityUniNameStr("lightIntensity");
+                lightIntensityUniNameStr.appendf("%d", i);
 
-                SkString depthMapWidthUniNameStr(depthMapWidthUniNameBase);
+                SkString depthMapWidthUniNameStr("dmapWidth");
                 depthMapWidthUniNameStr.appendf("%d", i);
-                SkString depthMapHeightUniNameStr(depthMapHeightUniNameBase);
+                SkString depthMapHeightUniNameStr("dmapHeight");
                 depthMapHeightUniNameStr.appendf("%d", i);
 
-                fLightDirUni[i] = uniformHandler->addUniform(kFragment_GrShaderFlag,
+                fLightDirOrPosUni[i] = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                              kVec3f_GrSLType,
                                                              kDefault_GrSLPrecision,
-                                                             lightDirUniNameStr.c_str(),
-                                                             &lightDirUniName[i]);
+                                                             lightDirOrPosUniNameStr.c_str(),
+                                                             &lightDirOrPosUniName[i]);
                 fLightColorUni[i] = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                                kVec3f_GrSLType,
                                                                kDefault_GrSLPrecision,
                                                                lightColorUniNameStr.c_str(),
                                                                &lightColorUniName[i]);
+                fLightIntensityUni[i] =
+                        uniformHandler->addUniform(kFragment_GrShaderFlag,
+                                                   kFloat_GrSLType,
+                                                   kDefault_GrSLPrecision,
+                                                   lightIntensityUniNameStr.c_str(),
+                                                   &lightIntensityUniName[i]);
 
                 fDepthMapWidthUni[i]  = uniformHandler->addUniform(kFragment_GrShaderFlag,
                                                    kInt_GrSLType,
@@ -234,7 +246,6 @@ public:
                                                     kDefault_GrSLPrecision,
                                                     "height", &heightUniName);
 
-
             SkString povDepth("povDepth");
             this->emitChild(0, nullptr, &povDepth, args);
 
@@ -243,15 +254,20 @@ public:
 
             SkString depthMaps[SkShadowShader::kMaxNonAmbientLights];
 
-            for (int i = 0; i < numLights; i++) {
+            // Multiply by 255 to transform from sampler coordinates to world
+            // coordinates (since 1 channel is 0xFF)
+            fragBuilder->codeAppendf("vec3 worldCor = vec3(vMatrixCoord_0_1_Stage0 * "
+                                                     "vec2(%s, %s), %s.b * 255);",
+                                     widthUniName, heightUniName, povDepth.c_str());
+
+            // Applies the offset indexing that goes from our view space into the light's space.
+            for (int i = 0; i < shadowFP.fNumNonAmbLights; i++) {
                 SkString povCoord("povCoord");
                 povCoord.appendf("%d", i);
 
                 // vMatrixCoord_0_1_Stage0 is the texture sampler coordinates.
                 // povDepth.b * 255 scales it to 0 - 255, bringing it to world space,
-                // and the / 400 brings it back to a sampler coordinate, 0 - 1
-                // The 400 comes from the shadowmaps GM.
-                // TODO use real shadowmaps size
+                // and the / vec2(width, height) brings it back to a sampler coordinate
                 SkString offset("offset");
                 offset.appendf("%d", i);
 
@@ -261,20 +277,36 @@ public:
                 SkString scaleOffsetVec("scaleOffsetVec");
                 scaleOffsetVec.appendf("%d", i);
 
-                fragBuilder->codeAppendf("vec2 %s = vec2(%s) * povDepth.b * 255 / 400;\n",
-                                         offset.c_str(), lightDirUniName[i]);
-
-                fragBuilder->codeAppendf("vec2 %s = (vec2(%s, %s) / vec2(%s, %s));\n",
+                fragBuilder->codeAppendf("vec2 %s;", offset.c_str());
+
+                if (shadowFP.fIsPointLight[i]) {
+                    fragBuilder->codeAppendf("vec3 fragToLight%d = %s - worldCor;",
+                                             i, lightDirOrPosUniName[i]);
+                    fragBuilder->codeAppendf("float distsq%d = dot(fragToLight%d, fragToLight%d);"
+                                             "fragToLight%d = normalize(fragToLight%d);",
+                                             i, i, i, i, i);
+                    fragBuilder->codeAppendf("%s = -vec2(%s.x - worldCor.x, worldCor.y - %s.y)*"
+                                                    "(povDepth.b) / vec2(%s, %s);",
+                                             offset.c_str(), lightDirOrPosUniName[i],
+                                             lightDirOrPosUniName[i],
+                                             widthUniName, heightUniName);
+                } else {
+                    fragBuilder->codeAppendf("%s = vec2(%s) * povDepth.b * 255 / vec2(%s, %s);",
+                                             offset.c_str(), lightDirOrPosUniName[i],
+                                             widthUniName, heightUniName);
+                }
+                fragBuilder->codeAppendf("vec2 %s = (vec2(%s, %s) / vec2(%s, %s));",
                                          scaleVec.c_str(),
                                          widthUniName, heightUniName,
                                          depthMapWidthUniName[i], depthMapHeightUniName[i]);
 
                 fragBuilder->codeAppendf("vec2 %s = 1 - %s;\n",
-                                         scaleOffsetVec.c_str(), scaleVec.c_str());
+                                         scaleOffsetVec.c_str(),
+                                         scaleVec.c_str());
 
                 fragBuilder->codeAppendf("vec2 %s = (vMatrixCoord_0_1_Stage0 + "
-                                                 "vec2(%s.x, 0 - %s.y)) "
-                                                 " * %s + vec2(0,1) * %s;\n",
+                                                   "vec2(%s.x, 0 - %s.y)) "
+                                                   " * %s + vec2(0,1) * %s;",
                                          povCoord.c_str(), offset.c_str(), offset.c_str(),
                                          scaleVec.c_str(), scaleOffsetVec.c_str());
 
@@ -282,7 +314,6 @@ public:
                                                  povCoord.c_str(),
                                                  kVec2f_GrSLType);
 
-
             }
 
             const char* ambientColorUniName = nullptr;
@@ -300,47 +331,61 @@ public:
             fragBuilder->codeAppendf("float d;");
 
             for (int i = 0; i < numLights; i++) {
-                fragBuilder->codeAppendf("lightProbability = 1;");
-
-                // 1/512 is less than half a pixel; imperceptible
-                fragBuilder->codeAppendf("if (%s.b <= %s.b + 1/512) {",
-                                         povDepth.c_str(), depthMaps[i].c_str());
-                if (blurAlgorithm == SkShadowParams::kVariance_ShadowType) {
-                    fragBuilder->codeAppendf("vec2 moments = vec2(%s.b * 255,  %s.g * 255 * 256 );",
-                                             depthMaps[i].c_str(), depthMaps[i].c_str());
-
-                    // variance biasing lessens light bleeding
-                    fragBuilder->codeAppendf("variance = max(moments.y - (moments.x * moments.x),"
-                                                     "%s);", minVarianceUniName);
-
-                    fragBuilder->codeAppendf("d = (%s.b * 255) - moments.x;", povDepth.c_str());
-                    fragBuilder->codeAppendf("lightProbability = "
-                                             "(variance / (variance + d * d));");
-
-                    SkString clamp("clamp");
-                    clamp.appendf("%d", i);
-
-                    // choosing between light artifacts or correct shape shadows
-                    // linstep
-                    fragBuilder->codeAppendf("float %s = clamp((lightProbability - %s) /"
-                                                              "(1 - %s), 0, 1);",
-                                             clamp.c_str(), shBiasUniName, shBiasUniName);
+                if (!shadowFP.isPointLight(i)) {
+                    fragBuilder->codeAppendf("lightProbability = 1;");
 
-                    fragBuilder->codeAppendf("lightProbability = %s;", clamp.c_str());
-                } else {
-                    fragBuilder->codeAppendf("if (%s.b >= %s.b) {",
+                    // 1/512 is less than half a pixel; imperceptible
+                    fragBuilder->codeAppendf("if (%s.b <= %s.b + 1/512) {",
                                              povDepth.c_str(), depthMaps[i].c_str());
-                    fragBuilder->codeAppendf("lightProbability = 1;");
-                    fragBuilder->codeAppendf("} else { lightProbability = 0; }");
+                    if (blurAlgorithm == SkShadowParams::kVariance_ShadowType) {
+                        fragBuilder->codeAppendf("vec2 moments%d = vec2(%s.b * 255,"
+                                                                       "%s.g * 255 * 256 );",
+                                                 i, depthMaps[i].c_str(), depthMaps[i].c_str());
+
+                        // variance biasing lessens light bleeding
+                        fragBuilder->codeAppendf("variance = max(moments%d.y - "
+                                                                "(moments%d.x * moments%d.x),"
+                                                                "%s);", i, i, i,
+                                                 minVarianceUniName);
+
+                        fragBuilder->codeAppendf("d = (%s.b * 255) - moments%d.x;",
+                                                 povDepth.c_str(), i);
+                        fragBuilder->codeAppendf("lightProbability = "
+                                                         "(variance / (variance + d * d));");
+
+                        SkString clamp("clamp");
+                        clamp.appendf("%d", i);
+
+                        // choosing between light artifacts or correct shape shadows
+                        // linstep
+                        fragBuilder->codeAppendf("float %s = clamp((lightProbability - %s) /"
+                                                         "(1 - %s), 0, 1);",
+                                                 clamp.c_str(), shBiasUniName, shBiasUniName);
+
+                        fragBuilder->codeAppendf("lightProbability = %s;", clamp.c_str());
+                    } else {
+                        fragBuilder->codeAppendf("if (%s.b >= %s.b) {",
+                                                 povDepth.c_str(), depthMaps[i].c_str());
+                        fragBuilder->codeAppendf("lightProbability = 1;");
+                        fragBuilder->codeAppendf("} else { lightProbability = 0; }");
+                    }
+
+                    // VSM: The curved shadows near plane edges are artifacts from blurring
+                    fragBuilder->codeAppendf("}");
+                    fragBuilder->codeAppendf("%s += dot(vec3(0,0,1), %s) * %s * "
+                                                   "lightProbability;",
+                                             totalLightColor.c_str(),
+                                             lightDirOrPosUniName[i],
+                                             lightColorUniName[i]);
+                } else {
+                    // fragToLight%d.z is equal to the fragToLight dot the surface normal.
+                    fragBuilder->codeAppendf("%s += max(fragToLight%d.z, 0) * %s /"
+                                                   "(1 + distsq%d / (%s * %s));",
+                                             totalLightColor.c_str(), i,
+                                             lightColorUniName[i], i,
+                                             lightIntensityUniName[i],
+                                             lightIntensityUniName[i]);
                 }
-
-                // VSM: The curved shadows near plane edges are mostly light bleeding.
-                fragBuilder->codeAppendf("}");
-
-                fragBuilder->codeAppendf("%s += dot(vec3(0,0,1), %s) * %s * lightProbability;",
-                                         totalLightColor.c_str(),
-                                         lightDirUniName[i],
-                                         lightColorUniName[i]);
             }
 
             fragBuilder->codeAppendf("%s += %s;", totalLightColor.c_str(), ambientColorUniName);
@@ -354,7 +399,12 @@ public:
         static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
                            GrProcessorKeyBuilder* b) {
             const ShadowFP& shadowFP = proc.cast<ShadowFP>();
-            b->add32(shadowFP.fNumDirLights);
+            b->add32(shadowFP.fNumNonAmbLights);
+            int isPL = 0;
+            for (int i = 0; i < SkShadowShader::kMaxNonAmbientLights; i++) {
+                isPL = isPL | ((shadowFP.fIsPointLight[i] ? 1 : 0) << i);
+            }
+            b->add32(isPL);
             b->add32(shadowFP.fShadowParams.fType);
         }
 
@@ -362,18 +412,25 @@ public:
         void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
             const ShadowFP &shadowFP = proc.cast<ShadowFP>();
 
-            for (int i = 0; i < shadowFP.fNumDirLights; i++) {
-                const SkVector3& lightDir = shadowFP.lightDir(i);
-                if (lightDir != fLightDir[i]) {
-                    pdman.set3fv(fLightDirUni[i], 1, &lightDir.fX);
-                    fLightDir[i] = lightDir;
+            for (int i = 0; i < shadowFP.numLights(); i++) {
+                const SkVector3& lightDirOrPos = shadowFP.lightDirOrPos(i);
+                if (lightDirOrPos != fLightDirOrPos[i]) {
+                    pdman.set3fv(fLightDirOrPosUni[i], 1, &lightDirOrPos.fX);
+                    fLightDirOrPos[i] = lightDirOrPos;
                 }
+
                 const SkColor3f& lightColor = shadowFP.lightColor(i);
                 if (lightColor != fLightColor[i]) {
                     pdman.set3fv(fLightColorUni[i], 1, &lightColor.fX);
                     fLightColor[i] = lightColor;
                 }
 
+                SkScalar lightIntensity = shadowFP.lightIntensity(i);
+                if (lightIntensity != fLightIntensity[i]) {
+                    pdman.set1f(fLightIntensityUni[i], lightIntensity);
+                    fLightIntensity[i] = lightIntensity;
+                }
+
                 int depthMapWidth = shadowFP.depthMapWidth(i);
                 if (depthMapWidth != fDepthMapWidth[i]) {
                     pdman.set1i(fDepthMapWidthUni[i], depthMapWidth);
@@ -417,14 +474,18 @@ public:
         }
 
     private:
-        SkVector3 fLightDir[SkShadowShader::kMaxNonAmbientLights];
+        SkVector3 fLightDirOrPos[SkShadowShader::kMaxNonAmbientLights];
         GrGLSLProgramDataManager::UniformHandle
-                fLightDirUni[SkShadowShader::kMaxNonAmbientLights];
+                fLightDirOrPosUni[SkShadowShader::kMaxNonAmbientLights];
 
         SkColor3f fLightColor[SkShadowShader::kMaxNonAmbientLights];
         GrGLSLProgramDataManager::UniformHandle
                 fLightColorUni[SkShadowShader::kMaxNonAmbientLights];
 
+        SkScalar fLightIntensity[SkShadowShader::kMaxNonAmbientLights];
+        GrGLSLProgramDataManager::UniformHandle
+                fLightIntensityUni[SkShadowShader::kMaxNonAmbientLights];
+
         int fDepthMapWidth[SkShadowShader::kMaxNonAmbientLights];
         GrGLSLProgramDataManager::UniformHandle
                 fDepthMapWidthUni[SkShadowShader::kMaxNonAmbientLights];
@@ -456,23 +517,31 @@ public:
     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
         inout->mulByUnknownFourComponents();
     }
-    int32_t numLights() const { return fNumDirLights; }
+    int32_t numLights() const { return fNumNonAmbLights; }
     const SkColor3f& ambientColor() const { return fAmbientColor; }
-    const SkVector3& lightDir(int i) const {
-        SkASSERT(i < fNumDirLights);
-        return fLightDir[i];
+    bool isPointLight(int i) const {
+        SkASSERT(i < fNumNonAmbLights);
+        return fIsPointLight[i];
+    }
+    const SkVector3& lightDirOrPos(int i) const {
+        SkASSERT(i < fNumNonAmbLights);
+        return fLightDirOrPos[i];
     }
     const SkVector3& lightColor(int i) const {
-        SkASSERT(i < fNumDirLights);
+        SkASSERT(i < fNumNonAmbLights);
         return fLightColor[i];
     }
+    SkScalar lightIntensity(int i) const {
+        SkASSERT(i < fNumNonAmbLights);
+        return fLightIntensity[i];
+    }
 
     int depthMapWidth(int i) const {
-        SkASSERT(i < fNumDirLights);
+        SkASSERT(i < fNumNonAmbLights);
         return fDepthMapWidth[i];
     }
     int depthMapHeight(int i) const {
-        SkASSERT(i < fNumDirLights);
+        SkASSERT(i < fNumNonAmbLights);
         return fDepthMapHeight[i];
     }
     int width() const {return fWidth; }
@@ -485,7 +554,8 @@ private:
 
     bool onIsEqual(const GrFragmentProcessor& proc) const override {
         const ShadowFP& shadowFP = proc.cast<ShadowFP>();
-        if (fAmbientColor != shadowFP.fAmbientColor || fNumDirLights != shadowFP.fNumDirLights) {
+        if (fAmbientColor != shadowFP.fAmbientColor ||
+            fNumNonAmbLights != shadowFP.fNumNonAmbLights) {
             return false;
         }
 
@@ -493,9 +563,11 @@ private:
             return false;
         }
 
-        for (int i = 0; i < fNumDirLights; i++) {
-            if (fLightDir[i] != shadowFP.fLightDir[i] ||
-                fLightColor[i] != shadowFP.fLightColor[i]) {
+        for (int i = 0; i < fNumNonAmbLights; i++) {
+            if (fLightDirOrPos[i] != shadowFP.fLightDirOrPos[i] ||
+                fLightColor[i] != shadowFP.fLightColor[i] ||
+                fLightIntensity[i] != shadowFP.fLightIntensity[i] ||
+                fIsPointLight[i] != shadowFP.fIsPointLight[i]) {
                 return false;
             }
 
@@ -508,10 +580,12 @@ private:
         return true;
     }
 
-    int              fNumDirLights;
+    int              fNumNonAmbLights;
 
-    SkVector3        fLightDir[SkShadowShader::kMaxNonAmbientLights];
+    bool             fIsPointLight[SkShadowShader::kMaxNonAmbientLights];
+    SkVector3        fLightDirOrPos[SkShadowShader::kMaxNonAmbientLights];
     SkColor3f        fLightColor[SkShadowShader::kMaxNonAmbientLights];
+    SkScalar         fLightIntensity[SkShadowShader::kMaxNonAmbientLights];
     GrTextureAccess  fDepthMapAccess[SkShadowShader::kMaxNonAmbientLights];
     sk_sp<GrTexture> fTexture[SkShadowShader::kMaxNonAmbientLights];
 
@@ -630,11 +704,19 @@ void SkShadowShaderImpl::ShadowShaderContext::shadeSpan(int x, int y,
                     accum.fX += light.color().fX * SkColorGetR(diffColor);
                     accum.fY += light.color().fY * SkColorGetG(diffColor);
                     accum.fZ += light.color().fZ * SkColorGetB(diffColor);
-                } else {
+                } else if (SkLights::Light::kDirectional_LightType == light.type()) {
                     // scaling by fZ accounts for lighting direction
-                    accum.fX += light.color().makeScale(light.dir().fZ).fX * SkColorGetR(diffColor);
-                    accum.fY += light.color().makeScale(light.dir().fZ).fY * SkColorGetG(diffColor);
-                    accum.fZ += light.color().makeScale(light.dir().fZ).fZ * SkColorGetB(diffColor);
+                    accum.fX += light.color().makeScale(light.dir().fZ).fX *
+                                                        SkColorGetR(diffColor);
+                    accum.fY += light.color().makeScale(light.dir().fZ).fY *
+                                                        SkColorGetG(diffColor);
+                    accum.fZ += light.color().makeScale(light.dir().fZ).fZ *
+                                                        SkColorGetB(diffColor);
+                } else {
+                    // TODO: do point lights for raster, currently treated like ambient
+                    accum.fX += light.color().fX * SkColorGetR(diffColor);
+                    accum.fY += light.color().fY * SkColorGetG(diffColor);
+                    accum.fZ += light.color().fZ * SkColorGetB(diffColor);
                 }
             }
 
index 2a090b7..e430870 100644 (file)
@@ -51,6 +51,10 @@ bool SkShadowPaintFilterCanvas::onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Ty
 SkISize SkShadowPaintFilterCanvas::ComputeDepthMapSize(const SkLights::Light& light, int maxDepth,
                                                        int width, int height) {
     SkASSERT(light.type() != SkLights::Light::kAmbient_LightType);
+    if (light.type() != SkLights::Light::kDirectional_LightType) {
+        return SkISize::Make(width *2 , height * 2);
+    }
+
     int dMapWidth = SkMin32(maxDepth * fabs(light.dir().fX) + width,
                             width * 2);
     int dMapHeight = SkMin32(maxDepth * fabs(light.dir().fY) + height,
@@ -75,7 +79,7 @@ void SkShadowPaintFilterCanvas::updateMatrix() {
 
     //  It is up to the user to set the 0th light in fLights to
     //  the light the want to render the depth map with.
-    if (this->fLights->light(0).type() != SkLights::Light::kAmbient_LightType) {
+    if (this->fLights->light(0).type() == SkLights::Light::kDirectional_LightType) {
         const SkVector3& lightDir = this->fLights->light(0).dir();
         SkScalar x = lightDir.fX * this->getZ();
         SkScalar y = lightDir.fY * this->getZ();