From: vjiaoblack Date: Fri, 26 Aug 2016 15:49:46 +0000 (-0700) Subject: Added distance attenuation and diffuse shading to PointLights X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~106^2~708 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=56f33ea2acb39ebb041340a8ab7564facb95afce;p=platform%2Fupstream%2FlibSkiaSharp.git Added distance attenuation and diffuse shading to PointLights BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2246463004 Review-Url: https://codereview.chromium.org/2246463004 --- diff --git a/include/core/SkLights.h b/include/core/SkLights.h index 329e5d3..d8ec87d 100644 --- a/include/core/SkLights.h +++ b/include/core/SkLights.h @@ -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 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 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; } }; diff --git a/samplecode/SampleShadowing.cpp b/samplecode/SampleShadowing.cpp index e27b4cf..4892f9c 100644 --- a/samplecode/SampleShadowing.cpp +++ b/samplecode/SampleShadowing.cpp @@ -15,16 +15,17 @@ 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 fPicture; SkShadowParams fShadowParams; diff --git a/src/core/SkLights.cpp b/src/core/SkLights.cpp index a172de4..7d8f9ed 100644 --- a/src/core/SkLights.cpp +++ b/src/core/SkLights.cpp @@ -29,6 +29,10 @@ sk_sp SkLights::MakeFromBuffer(SkReadBuffer& buf) { if (!buf.readScalarArray(&dirOrPos.fX, 3)) { return nullptr; } + SkScalar intensity = 0.0f; + if (isPoint) { + intensity = buf.readScalar(); + } sk_sp depthMap; bool hasShadowMap = buf.readBool(); @@ -39,7 +43,7 @@ sk_sp 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) { diff --git a/src/core/SkShadowShader.cpp b/src/core/SkShadowShader.cpp index 9ad23b7..49f1b01 100644 --- a/src/core/SkShadowShader.cpp +++ b/src/core/SkShadowShader.cpp @@ -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(shadowMap->asTextureRef(context, + fTexture[fNumNonAmbLights] = sk_sp(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(); + + SkASSERT(shadowFP.fNumNonAmbLights <= SkShadowShader::kMaxNonAmbientLights); // add uniforms - int32_t numLights = args.fFp.cast().fNumDirLights; + int32_t numLights = shadowFP.fNumNonAmbLights; SkASSERT(numLights <= SkShadowShader::kMaxNonAmbientLights); - int blurAlgorithm = args.fFp.cast().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(); - 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(); - 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(); - 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 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); } } diff --git a/src/utils/SkShadowPaintFilterCanvas.cpp b/src/utils/SkShadowPaintFilterCanvas.cpp index 2a090b7..e430870 100644 --- a/src/utils/SkShadowPaintFilterCanvas.cpp +++ b/src/utils/SkShadowPaintFilterCanvas.cpp @@ -51,6 +51,10 @@ bool SkShadowPaintFilterCanvas::onFilter(SkTCopyOnFirstWrite* 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();