Chromium Code Reviews| Index: src/core/SkShadowShader.cpp |
| diff --git a/src/core/SkShadowShader.cpp b/src/core/SkShadowShader.cpp |
| index 5fc992acc14dd790ab86e43e6a761ecc7b7db8bc..9f7ea5ebae4bb64bbcc74bd56e2467edfb2758fb 100644 |
| --- a/src/core/SkShadowShader.cpp |
| +++ b/src/core/SkShadowShader.cpp |
| @@ -26,12 +26,14 @@ public: |
| SkShadowShaderImpl(sk_sp<SkShader> povDepthShader, |
| sk_sp<SkShader> diffuseShader, |
| sk_sp<SkLights> lights, |
| - int diffuseWidth, int diffuseHeight) |
| + int diffuseWidth, int diffuseHeight, |
| + SkShadowType sType) |
| : fPovDepthShader(std::move(povDepthShader)) |
| , fDiffuseShader(std::move(diffuseShader)) |
| , fLights(std::move(lights)) |
| , fDiffuseWidth(diffuseWidth) |
| - , fDiffuseHeight(diffuseHeight) { } |
| + , fDiffuseHeight(diffuseHeight) |
| + , fShType(sType) { } |
| bool isOpaque() const override; |
| @@ -80,6 +82,8 @@ private: |
| int fDiffuseWidth; |
| int fDiffuseHeight; |
| + SkShadowType fShType; |
| + |
| friend class SkShadowShader; |
| typedef SkShader INHERITED; |
| @@ -106,6 +110,7 @@ public: |
| sk_sp<GrFragmentProcessor> diffuse, |
| sk_sp<SkLights> lights, |
| int diffuseWidth, int diffuseHeight, |
| + SkShadowType sType, |
| GrContext* context) { |
| // fuse all ambient lights into a single one |
| @@ -137,6 +142,11 @@ public: |
| fWidth = diffuseWidth; |
| fHeight = diffuseHeight; |
| + fShType = sType; |
| + |
| + |
| +// printf("init: %d\n", sType.fBlurAlgorithm); |
|
jvanverth1
2016/08/12 17:39:09
Remove this or put in #ifdef block (e.g. #ifdef DU
vjiaoblack
2016/08/12 19:07:42
Thanks! Done.
|
| + |
| this->registerChildProcessor(std::move(povDepth)); |
| this->registerChildProcessor(std::move(diffuse)); |
| this->initClassID<ShadowFP>(); |
| @@ -155,6 +165,8 @@ public: |
| int32_t numLights = args.fFp.cast<ShadowFP>().fNumDirLights; |
| SkASSERT(numLights <= SkShadowShader::kMaxNonAmbientLights); |
| + int blurAlgorithm = args.fFp.cast<ShadowFP>().fShType.fBlurAlgorithm; |
| + |
| const char* lightDirUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr}; |
| const char* lightColorUniName[SkShadowShader::kMaxNonAmbientLights] = {nullptr}; |
| @@ -203,6 +215,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 +277,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 +297,70 @@ public: |
| fragBuilder->codeAppendf("vec4 resultDiffuseColor = %s;", diffuseColor.c_str()); |
| - // Essentially, |
| - // diffColor * (ambientLightTot + foreachDirLight(lightColor * (N . L))) |
| + // all the normal vectors point straight up |
| SkString totalLightColor("totalLightColor"); |
| - fragBuilder->codeAppendf("vec3 %s = vec3(0);", totalLightColor.c_str()); |
| + fragBuilder->codeAppendf("vec3 %s = vec3(0,0,0);", totalLightColor.c_str()); |
| + |
| + SkString lightProb("lightProbability"); |
| + fragBuilder->codeAppendf("float %s;", lightProb.c_str()); |
| + fragBuilder->codeAppendf("float variance;"); |
| + fragBuilder->codeAppendf("float d;"); |
| for (int i = 0; i < numLights; i++) { |
| - fragBuilder->codeAppendf("if (%s.b >= %s.b) {", |
| + fragBuilder->codeAppendf("%s = 1;", lightProb.c_str()); |
| + |
| + // 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 == SkShadowType::kVariance_BlurAlgorithm) { |
| + 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("%s = (variance / (variance + d * d));", |
| + lightProb.c_str()); |
| + |
| + SkString clamp("clamp"); |
| + clamp.appendf("%d", i); |
| + |
| + // choosing between light artifacts or correct shape shadows |
| + // linstep |
| + fragBuilder->codeAppendf("float %s = clamp((%s - %s) / (1 - %s), 0, 1);", |
| + clamp.c_str(), lightProb.c_str(), |
| + shBiasUniName, shBiasUniName); |
| + |
| + // different bias types |
| + // sqrt pulls in and makes an edge |
| + // pow2 pushes out |
| + // fragBuilder->codeAppendf("%s = %s * %s * (3.0 - 2.0 * %s);", |
| + // lightProb.c_str(), clamp.c_str(), clamp.c_str(), clamp.c_str()); |
|
jvanverth1
2016/08/12 17:39:09
Line length > 100? And are these commented out lin
vjiaoblack
2016/08/12 19:07:42
I would like to keep them as comments to document
jvanverth1
2016/08/12 19:44:10
Then I would block them out with an #ifdef, just l
|
| + // fragBuilder->codeAppendf("%s = 6 * pow(%s, 5) - 15 * pow(%s, 4) + 10 * pow(%s, 3);", |
| + // lightProb.c_str(), clamp.c_str(), clamp.c_str(), clamp.c_str()); |
| + |
| + fragBuilder->codeAppendf("%s = %s;", |
| + lightProb.c_str(), clamp.c_str()); |
| + } else { |
| + fragBuilder->codeAppendf("if (%s.b >= %s.b) {", |
| + povDepth.c_str(), depthMaps[i].c_str()); |
| + fragBuilder->codeAppendf("%s = 1;", lightProb.c_str()); |
| + fragBuilder->codeAppendf("} else { %s = 0; }", lightProb.c_str()); |
| + } |
| + |
| + // VSM: The curved shadows near plane edges are mostly light bleeding. |
| + fragBuilder->codeAppendf("}"); |
| + |
| + fragBuilder->codeAppendf("%s += dot(vec3(0,0,1), %s) * %s * %s;", |
| totalLightColor.c_str(), |
| lightDirUniName[i], |
| - lightColorUniName[i]); |
| - fragBuilder->codeAppendf("}"); |
| + lightColorUniName[i], |
| + lightProb.c_str()); |
| } |
| - 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 +372,14 @@ public: |
| GrProcessorKeyBuilder* b) { |
| const ShadowFP& shadowFP = proc.cast<ShadowFP>(); |
| b->add32(shadowFP.fNumDirLights); |
| + b->add32(shadowFP.fShType.fBlurAlgorithm); |
| } |
| 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 +403,18 @@ public: |
| } |
| } |
| + SkScalar biasingConstant = shadowFP.shadowType().fBiasingConstant; |
| + if (biasingConstant != fBiasingConstant) { |
| + pdman.set1f(fBiasingConstantUni, biasingConstant); |
| + fBiasingConstant = biasingConstant; |
| + } |
| + |
| + SkScalar minVariance = shadowFP.shadowType().fMinVariance; |
| + if (minVariance != fMinVariance) { |
| + pdman.set1f(fMinVarianceUni, minVariance); |
| + fMinVariance = minVariance; |
| + } |
| + |
| int width = shadowFP.width(); |
| if (width != fWidth) { |
| pdman.set1i(fWidthUni, width); |
| @@ -376,10 +455,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 +495,8 @@ public: |
| int width() const {return fWidth; } |
| int height() const {return fHeight; } |
| + SkShadowType shadowType() const {return fShType; } |
| + |
| private: |
| GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLShadowFP; } |
| @@ -454,6 +538,8 @@ private: |
| int fHeight; |
| int fWidth; |
| + SkShadowType fShType; |
| + |
| SkColor3f fAmbientColor; |
| }; |
| @@ -469,7 +555,7 @@ sk_sp<GrFragmentProcessor> SkShadowShaderImpl::asFragmentProcessor(const AsFPArg |
| std::move(diffuseFP), |
| std::move(fLights), |
| fDiffuseWidth, fDiffuseHeight, |
| - fpargs.fContext); |
| + fShType, fpargs.fContext); |
| return shadowfp; |
| } |
| @@ -626,6 +712,12 @@ sk_sp<SkFlattenable> SkShadowShaderImpl::CreateProc(SkReadBuffer& buf) { |
| sk_sp<SkLights> lights(builder.finish()); |
| + SkShadowType sType; |
| + sType.fMinVariance = buf.readScalar(); |
| + sType.fBiasingConstant = buf.readScalar(); |
| + sType.fBlurAlgorithm = (SkShadowType::BlurAlgorithm) buf.readInt(); |
| + sType.fShadowRadius = buf.readScalar(); |
| + |
| int diffuseWidth = buf.readInt(); |
| int diffuseHeight = buf.readInt(); |
| @@ -635,7 +727,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, |
| + sType); |
| } |
| void SkShadowShaderImpl::flatten(SkWriteBuffer& buf) const { |
| @@ -657,6 +750,11 @@ void SkShadowShaderImpl::flatten(SkWriteBuffer& buf) const { |
| buf.writeImage(light.getShadowMap()); |
| } |
| + buf.writeScalar(fShType.fMinVariance); |
| + buf.writeScalar(fShType.fBiasingConstant); |
| + buf.writeInt(fShType.fBlurAlgorithm); |
| + buf.writeScalar(fShType.fShadowRadius); |
| + |
| buf.writeInt(fDiffuseWidth); |
| buf.writeInt(fDiffuseHeight); |
| @@ -702,7 +800,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, |
| + SkShadowType sType) { |
| if (!povDepthShader || !diffuseShader) { |
| // TODO: Use paint's color in absence of a diffuseShader |
| // TODO: Use a default implementation of normalSource instead |
| @@ -712,7 +811,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, |
| + sType); |
| } |
| /////////////////////////////////////////////////////////////////////////////// |