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); |
} |
/////////////////////////////////////////////////////////////////////////////// |