| Index: src/core/SkShadowShader.cpp
|
| diff --git a/src/core/SkShadowShader.cpp b/src/core/SkShadowShader.cpp
|
| index 804258321a80f9ab0bd20b7ffa995878ab079b17..9ad23b7c17ab60e5d1b959580bea710a3a168659 100644
|
| --- a/src/core/SkShadowShader.cpp
|
| +++ b/src/core/SkShadowShader.cpp
|
| @@ -5,11 +5,9 @@
|
| * found in the LICENSE file.
|
| */
|
|
|
| -
|
| -#include "SkLights.h"
|
| +#include "SkCanvas.h"
|
| #include "SkReadBuffer.h"
|
| #include "SkShadowShader.h"
|
| -#include "SkPoint3.h"
|
|
|
| ////////////////////////////////////////////////////////////////////////////
|
| #ifdef SK_EXPERIMENTAL_SHADOWING
|
| @@ -26,12 +24,14 @@ public:
|
| SkShadowShaderImpl(sk_sp<SkShader> povDepthShader,
|
| sk_sp<SkShader> diffuseShader,
|
| sk_sp<SkLights> lights,
|
| - int diffuseWidth, int diffuseHeight)
|
| + int diffuseWidth, int diffuseHeight,
|
| + const SkShadowParams& params)
|
| : fPovDepthShader(std::move(povDepthShader))
|
| , fDiffuseShader(std::move(diffuseShader))
|
| , fLights(std::move(lights))
|
| , fDiffuseWidth(diffuseWidth)
|
| - , fDiffuseHeight(diffuseHeight) { }
|
| + , fDiffuseHeight(diffuseHeight)
|
| + , fShadowParams(params) { }
|
|
|
| bool isOpaque() const override;
|
|
|
| @@ -80,6 +80,8 @@ private:
|
| int fDiffuseWidth;
|
| int fDiffuseHeight;
|
|
|
| + SkShadowParams fShadowParams;
|
| +
|
| friend class SkShadowShader;
|
|
|
| typedef SkShader INHERITED;
|
| @@ -106,6 +108,7 @@ public:
|
| sk_sp<GrFragmentProcessor> diffuse,
|
| sk_sp<SkLights> lights,
|
| int diffuseWidth, int diffuseHeight,
|
| + const SkShadowParams& params,
|
| GrContext* context) {
|
|
|
| // fuse all ambient lights into a single one
|
| @@ -137,7 +140,9 @@ public:
|
| fWidth = diffuseWidth;
|
| fHeight = diffuseHeight;
|
|
|
| - this->registerChildProcessor(std::move(povDepth));
|
| + fShadowParams = params;
|
| +
|
| + this->registerChildProcessor(std::move(povDepth));
|
| this->registerChildProcessor(std::move(diffuse));
|
| this->initClassID<ShadowFP>();
|
| }
|
| @@ -155,6 +160,8 @@ public:
|
| int32_t numLights = args.fFp.cast<ShadowFP>().fNumDirLights;
|
| SkASSERT(numLights <= SkShadowShader::kMaxNonAmbientLights);
|
|
|
| + int blurAlgorithm = args.fFp.cast<ShadowFP>().fShadowParams.fType;
|
| +
|
| const char* lightDirUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
|
| const char* lightColorUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr};
|
|
|
| @@ -203,6 +210,17 @@ public:
|
| &depthMapHeightUniName[i]);
|
| }
|
|
|
| + const char* shBiasUniName = nullptr;
|
| + const char* minVarianceUniName = nullptr;
|
| +
|
| + fBiasingConstantUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
| + kFloat_GrSLType,
|
| + kDefault_GrSLPrecision,
|
| + "shadowBias", &shBiasUniName);
|
| + fMinVarianceUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
| + kFloat_GrSLType,
|
| + kDefault_GrSLPrecision,
|
| + "minVariance", &minVarianceUniName);
|
|
|
| const char* widthUniName = nullptr;
|
| const char* heightUniName = nullptr;
|
| @@ -254,17 +272,17 @@ public:
|
| fragBuilder->codeAppendf("vec2 %s = 1 - %s;\n",
|
| 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;\n",
|
| povCoord.c_str(), offset.c_str(), offset.c_str(),
|
| scaleVec.c_str(), scaleOffsetVec.c_str());
|
|
|
| fragBuilder->appendTextureLookup(&depthMaps[i], args.fTexSamplers[i],
|
| povCoord.c_str(),
|
| kVec2f_GrSLType);
|
| +
|
| +
|
| }
|
|
|
| const char* ambientColorUniName = nullptr;
|
| @@ -274,25 +292,58 @@ public:
|
|
|
| fragBuilder->codeAppendf("vec4 resultDiffuseColor = %s;", diffuseColor.c_str());
|
|
|
| - // Essentially,
|
| - // diffColor * (ambientLightTot + foreachDirLight(lightColor * (N . L)))
|
| SkString totalLightColor("totalLightColor");
|
| - fragBuilder->codeAppendf("vec3 %s = vec3(0);", totalLightColor.c_str());
|
| + fragBuilder->codeAppendf("vec3 %s = vec3(0,0,0);", totalLightColor.c_str());
|
| +
|
| + fragBuilder->codeAppendf("float lightProbability;");
|
| + fragBuilder->codeAppendf("float variance;");
|
| + fragBuilder->codeAppendf("float d;");
|
|
|
| for (int i = 0; i < numLights; i++) {
|
| - fragBuilder->codeAppendf("if (%s.b >= %s.b) {",
|
| + 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());
|
| - // Note that dot(vec3(0,0,1), %s) == %s.z * %s
|
| - fragBuilder->codeAppendf("%s += %s.z * %s;",
|
| + 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);
|
| +
|
| + 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 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("}");
|
| }
|
|
|
| - fragBuilder->codeAppendf("%s += %s;",
|
| - totalLightColor.c_str(),
|
| - ambientColorUniName);
|
| + fragBuilder->codeAppendf("%s += %s;", totalLightColor.c_str(), ambientColorUniName);
|
|
|
| fragBuilder->codeAppendf("resultDiffuseColor *= vec4(%s, 1);",
|
| totalLightColor.c_str());
|
| @@ -304,15 +355,14 @@ public:
|
| GrProcessorKeyBuilder* b) {
|
| const ShadowFP& shadowFP = proc.cast<ShadowFP>();
|
| b->add32(shadowFP.fNumDirLights);
|
| + b->add32(shadowFP.fShadowParams.fType);
|
| }
|
|
|
| protected:
|
| void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
|
| const ShadowFP &shadowFP = proc.cast<ShadowFP>();
|
|
|
| - fNumDirLights = shadowFP.numLights();
|
| -
|
| - for (int i = 0; i < fNumDirLights; i++) {
|
| + 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);
|
| @@ -336,6 +386,18 @@ public:
|
| }
|
| }
|
|
|
| + SkScalar biasingConstant = shadowFP.shadowParams().fBiasingConstant;
|
| + if (biasingConstant != fBiasingConstant) {
|
| + pdman.set1f(fBiasingConstantUni, biasingConstant);
|
| + fBiasingConstant = biasingConstant;
|
| + }
|
| +
|
| + SkScalar minVariance = shadowFP.shadowParams().fMinVariance;
|
| + if (minVariance != fMinVariance) {
|
| + pdman.set1f(fMinVarianceUni, minVariance);
|
| + fMinVariance = minVariance;
|
| + }
|
| +
|
| int width = shadowFP.width();
|
| if (width != fWidth) {
|
| pdman.set1i(fWidthUni, width);
|
| @@ -376,10 +438,13 @@ public:
|
| int fHeight;
|
| GrGLSLProgramDataManager::UniformHandle fHeightUni;
|
|
|
| + SkScalar fBiasingConstant;
|
| + GrGLSLProgramDataManager::UniformHandle fBiasingConstantUni;
|
| + SkScalar fMinVariance;
|
| + GrGLSLProgramDataManager::UniformHandle fMinVarianceUni;
|
| +
|
| SkColor3f fAmbientColor;
|
| GrGLSLProgramDataManager::UniformHandle fAmbientColorUni;
|
| -
|
| - int fNumDirLights;
|
| };
|
|
|
| void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
|
| @@ -413,6 +478,8 @@ public:
|
| int width() const {return fWidth; }
|
| int height() const {return fHeight; }
|
|
|
| + const SkShadowParams& shadowParams() const {return fShadowParams; }
|
| +
|
| private:
|
| GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLShadowFP; }
|
|
|
| @@ -454,6 +521,8 @@ private:
|
| int fHeight;
|
| int fWidth;
|
|
|
| + SkShadowParams fShadowParams;
|
| +
|
| SkColor3f fAmbientColor;
|
| };
|
|
|
| @@ -469,7 +538,7 @@ sk_sp<GrFragmentProcessor> SkShadowShaderImpl::asFragmentProcessor(const AsFPArg
|
| std::move(diffuseFP),
|
| std::move(fLights),
|
| fDiffuseWidth, fDiffuseHeight,
|
| - fpargs.fContext);
|
| + fShadowParams, fpargs.fContext);
|
| return shadowfp;
|
| }
|
|
|
| @@ -594,6 +663,12 @@ sk_sp<SkFlattenable> SkShadowShaderImpl::CreateProc(SkReadBuffer& buf) {
|
|
|
| sk_sp<SkLights> lights = SkLights::MakeFromBuffer(buf);
|
|
|
| + SkShadowParams params;
|
| + params.fMinVariance = buf.readScalar();
|
| + params.fBiasingConstant = buf.readScalar();
|
| + params.fType = (SkShadowParams::ShadowType) buf.readInt();
|
| + params.fShadowRadius = buf.readScalar();
|
| +
|
| int diffuseWidth = buf.readInt();
|
| int diffuseHeight = buf.readInt();
|
|
|
| @@ -603,7 +678,8 @@ sk_sp<SkFlattenable> SkShadowShaderImpl::CreateProc(SkReadBuffer& buf) {
|
| return sk_make_sp<SkShadowShaderImpl>(std::move(povDepthShader),
|
| std::move(diffuseShader),
|
| std::move(lights),
|
| - diffuseWidth, diffuseHeight);
|
| + diffuseWidth, diffuseHeight,
|
| + params);
|
| }
|
|
|
| void SkShadowShaderImpl::flatten(SkWriteBuffer& buf) const {
|
| @@ -611,6 +687,11 @@ void SkShadowShaderImpl::flatten(SkWriteBuffer& buf) const {
|
|
|
| fLights->flatten(buf);
|
|
|
| + buf.writeScalar(fShadowParams.fMinVariance);
|
| + buf.writeScalar(fShadowParams.fBiasingConstant);
|
| + buf.writeInt(fShadowParams.fType);
|
| + buf.writeScalar(fShadowParams.fShadowRadius);
|
| +
|
| buf.writeInt(fDiffuseWidth);
|
| buf.writeInt(fDiffuseHeight);
|
|
|
| @@ -656,7 +737,8 @@ SkShader::Context* SkShadowShaderImpl::onCreateContext(const ContextRec& rec,
|
| sk_sp<SkShader> SkShadowShader::Make(sk_sp<SkShader> povDepthShader,
|
| sk_sp<SkShader> diffuseShader,
|
| sk_sp<SkLights> lights,
|
| - int diffuseWidth, int diffuseHeight) {
|
| + int diffuseWidth, int diffuseHeight,
|
| + const SkShadowParams& params) {
|
| if (!povDepthShader || !diffuseShader) {
|
| // TODO: Use paint's color in absence of a diffuseShader
|
| // TODO: Use a default implementation of normalSource instead
|
| @@ -666,7 +748,8 @@ sk_sp<SkShader> SkShadowShader::Make(sk_sp<SkShader> povDepthShader,
|
| return sk_make_sp<SkShadowShaderImpl>(std::move(povDepthShader),
|
| std::move(diffuseShader),
|
| std::move(lights),
|
| - diffuseWidth, diffuseHeight);
|
| + diffuseWidth, diffuseHeight,
|
| + params);
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|