diff options
-rw-r--r-- | gm/lightingshader2.cpp | 58 | ||||
-rw-r--r-- | include/core/SkLights.h | 14 | ||||
-rw-r--r-- | src/core/SkLightingShader.cpp | 105 |
3 files changed, 124 insertions, 53 deletions
diff --git a/gm/lightingshader2.cpp b/gm/lightingshader2.cpp index 70c9e29f69..5afe2558b9 100644 --- a/gm/lightingshader2.cpp +++ b/gm/lightingshader2.cpp @@ -23,7 +23,7 @@ static SkBitmap make_frustum_normalmap(int texSize) { namespace skiagm { // This GM exercises lighting shaders. Specifically, nullptr arguments, scaling when using -// normal maps, and paint transparency. +// normal maps, paint transparency, zero directional lights, multiple directional lights. class LightingShader2GM : public GM { public: LightingShader2GM() { @@ -40,14 +40,30 @@ protected: } void onOnceBeforeDraw() override { - SkLights::Builder builder; const SkVector3 kLightFromUpperRight = SkVector3::Make(0.788f, 0.394f, 0.473f); + const SkVector3 kLightFromUpperLeft = SkVector3::Make(-0.788f, 0.394f, 0.473f); + // Standard set of lights + SkLights::Builder builder; builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f), kLightFromUpperRight)); builder.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.2f, 0.2f, 0.2f))); fLights = builder.finish(); + // No directional lights + SkLights::Builder builderNoDir; + builderNoDir.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.2f, 0.2f, 0.2f))); + fLightsNoDir = builderNoDir.finish(); + + // Two directional lights + SkLights::Builder builderTwoDir; + builderTwoDir.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 0.0f, 1.0f), + kLightFromUpperRight)); + builderTwoDir.add(SkLights::Light::MakeDirectional(SkColor3f::Make(0.0f, 1.0f, 1.0f), + kLightFromUpperLeft)); + builderTwoDir.add(SkLights::Light::MakeAmbient(SkColor3f::Make(0.2f, 0.2f, 0.2f))); + fLightsTwoDir = builderTwoDir.finish(); + fRect = SkRect::MakeIWH(kTexSize, kTexSize); SkMatrix matrix; SkRect bitmapBounds = SkRect::MakeIWH(kTexSize, kTexSize); @@ -87,7 +103,7 @@ protected: static constexpr int NUM_BOOLEAN_PARAMS = 4; void drawRect(SkCanvas* canvas, SkScalar scaleX, SkScalar scaleY, SkScalar rotate, bool useNormalSource, bool useDiffuseShader, - bool useTranslucentPaint, bool useTranslucentShader) { + bool useTranslucentPaint, bool useTranslucentShader, sk_sp<SkLights> lights) { canvas->save(); this->positionCTM(canvas, scaleX, scaleY, rotate); @@ -113,7 +129,7 @@ protected: } paint.setShader(SkLightingShader::Make(std::move(diffuseShader), std::move(normalSource), - fLights)); + std::move(lights))); canvas->drawRect(fRect, paint); canvas->restore(); @@ -147,7 +163,7 @@ protected: canvas->translate(xPos, yPos); this->drawRect(canvas, 1.0f, 1.0f, 0.f, useNormalSource, useDiffuseShader, - useTranslucentPaint, useTranslucentShader); + useTranslucentPaint, useTranslucentShader, fLights); // Drawing labels canvas->translate(0.0f, SkIntToScalar(kTexSize)); { @@ -191,7 +207,7 @@ protected: canvas->save(); canvas->translate(xPos, yPos); - this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true); + this->drawRect(canvas, 0.6f, 0.6f, 45.0f, true, true, true, true, fLights); canvas->restore(); gridNum++; @@ -204,7 +220,33 @@ protected: canvas->save(); canvas->translate(xPos, yPos); - this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true); + this->drawRect(canvas, 0.6f, 0.4f, 30.0f, true, true, true, true, fLights); + canvas->restore(); + + gridNum++; + } + + // No directional lights test + { + SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; + SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; + + canvas->save(); + canvas->translate(xPos, yPos); + this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsNoDir); + canvas->restore(); + + gridNum++; + } + + // Two directional lights test + { + SkScalar xPos = (gridNum % GRID_COLUMN_NUM) * GRID_CELL_WIDTH; + SkScalar yPos = (gridNum / GRID_COLUMN_NUM) * GRID_CELL_WIDTH; + + canvas->save(); + canvas->translate(xPos, yPos); + this->drawRect(canvas, 1.0f, 1.0f, 0.0f, true, true, false, false, fLightsTwoDir); canvas->restore(); gridNum++; @@ -220,6 +262,8 @@ private: SkRect fRect; sk_sp<SkLights> fLights; + sk_sp<SkLights> fLightsNoDir; + sk_sp<SkLights> fLightsTwoDir; typedef GM INHERITED; }; diff --git a/include/core/SkLights.h b/include/core/SkLights.h index d9ec65b9aa..329e5d387d 100644 --- a/include/core/SkLights.h +++ b/include/core/SkLights.h @@ -87,6 +87,20 @@ public: fShadowMap = b.fShadowMap; return *this; } + + bool operator== (const Light& b) { + if (this == &b) { + return true; + } + + return (fColor == b.fColor) && + (fType == b.fType) && + (fDirection == b.fDirection) && + (fShadowMap == b.fShadowMap); + } + + bool operator!= (const Light& b) { return !(this->operator==(b)); } + private: LightType fType; SkColor3f fColor; // linear (unpremul) color. Range is 0..1 in each channel. diff --git a/src/core/SkLightingShader.cpp b/src/core/SkLightingShader.cpp index 6f3c23399d..8fde8bfd37 100644 --- a/src/core/SkLightingShader.cpp +++ b/src/core/SkLightingShader.cpp @@ -126,11 +126,11 @@ public: for (int i = 0; i < lights->numLights(); ++i) { if (SkLights::Light::kAmbient_LightType == lights->light(i).type()) { fAmbientColor += lights->light(i).color(); - } else { - // TODO: handle more than one of these - fLightColor = lights->light(i).color(); - fLightDir = lights->light(i).dir(); + } else if (SkLights::Light::kDirectional_LightType == lights->light(i).type()) { + fDirectionalLights.push_back(lights->light(i)); // TODO get the handle to the shadow map if there is one + } else { + SkDEBUGFAIL("Unimplemented Light Type passed to LightingFP"); } } @@ -141,8 +141,6 @@ public: class GLSLLightingFP : public GrGLSLFragmentProcessor { public: GLSLLightingFP() { - fLightDir.fX = 10000.0f; - fLightColor.fX = 0.0f; fAmbientColor.fX = 0.0f; } @@ -150,17 +148,26 @@ public: GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - // add uniforms - const char* lightDirUniName = nullptr; - fLightDirUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightDir", &lightDirUniName); - - const char* lightColorUniName = nullptr; - fLightColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightColor", &lightColorUniName); + const LightingFP& lightingFP = args.fFp.cast<LightingFP>(); + + const char *lightDirsUniName = nullptr; + const char *lightColorsUniName = nullptr; + if (lightingFP.fDirectionalLights.count() != 0) { + fLightDirsUni = uniformHandler->addUniformArray( + kFragment_GrShaderFlag, + kVec3f_GrSLType, + kDefault_GrSLPrecision, + "LightDir", + lightingFP.fDirectionalLights.count(), + &lightDirsUniName); + fLightColorsUni = uniformHandler->addUniformArray( + kFragment_GrShaderFlag, + kVec3f_GrSLType, + kDefault_GrSLPrecision, + "LightColor", + lightingFP.fDirectionalLights.count(), + &lightColorsUniName); + } const char* ambientColorUniName = nullptr; fAmbientColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, @@ -174,12 +181,20 @@ public: fragBuilder->codeAppendf("vec3 normal = %s.xyz;", dstNormalName.c_str()); - // TODO: make this a loop and modulate the contribution from each light - // based on the shadow map - fragBuilder->codeAppendf("float NdotL = clamp(dot(normal, %s), 0.0, 1.0);", - lightDirUniName); + fragBuilder->codeAppend( "vec3 result = vec3(0.0);"); + // diffuse light - fragBuilder->codeAppendf("vec3 result = %s*diffuseColor.rgb*NdotL;", lightColorUniName); + if (lightingFP.fDirectionalLights.count() != 0) { + fragBuilder->codeAppendf("for (int i = 0; i < %d; i++) {", + lightingFP.fDirectionalLights.count()); + // TODO: modulate the contribution from each light based on the shadow map + fragBuilder->codeAppendf(" float NdotL = clamp(dot(normal, %s[i]), 0.0, 1.0);", + lightDirsUniName); + fragBuilder->codeAppendf(" result += %s[i]*diffuseColor.rgb*NdotL;", + lightColorsUniName); + fragBuilder->codeAppend("}"); + } + // ambient light fragBuilder->codeAppendf("result += %s * diffuseColor.rgb;", ambientColorUniName); @@ -190,25 +205,27 @@ public: static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { -// const LightingFP& lightingFP = proc.cast<LightingFP>(); - // only one shader generated currently - b->add32(0x0); + const LightingFP& lightingFP = proc.cast<LightingFP>(); + b->add32(lightingFP.fDirectionalLights.count()); } protected: void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { const LightingFP& lightingFP = proc.cast<LightingFP>(); - const SkVector3& lightDir = lightingFP.lightDir(); - if (lightDir != fLightDir) { - pdman.set3fv(fLightDirUni, 1, &lightDir.fX); - fLightDir = lightDir; - } + const SkTArray<SkLights::Light>& directionalLights = lightingFP.directionalLights(); + if (directionalLights != fDirectionalLights) { + SkTArray<SkColor3f> lightDirs(directionalLights.count()); + SkTArray<SkVector3> lightColors(directionalLights.count()); + for (const SkLights::Light& light : directionalLights) { + lightDirs.push_back(light.dir()); + lightColors.push_back(light.color()); + } + + pdman.set3fv(fLightDirsUni, directionalLights.count(), &(lightDirs[0].fX)); + pdman.set3fv(fLightColorsUni, directionalLights.count(), &(lightColors[0].fX)); - const SkColor3f& lightColor = lightingFP.lightColor(); - if (lightColor != fLightColor) { - pdman.set3fv(fLightColorUni, 1, &lightColor.fX); - fLightColor = lightColor; + fDirectionalLights = directionalLights; } const SkColor3f& ambientColor = lightingFP.ambientColor(); @@ -219,11 +236,9 @@ public: } private: - SkVector3 fLightDir; - GrGLSLProgramDataManager::UniformHandle fLightDirUni; - - SkColor3f fLightColor; - GrGLSLProgramDataManager::UniformHandle fLightColorUni; + SkTArray<SkLights::Light> fDirectionalLights; + GrGLSLProgramDataManager::UniformHandle fLightDirsUni; + GrGLSLProgramDataManager::UniformHandle fLightColorsUni; SkColor3f fAmbientColor; GrGLSLProgramDataManager::UniformHandle fAmbientColorUni; @@ -239,8 +254,7 @@ public: inout->mulByUnknownFourComponents(); } - const SkVector3& lightDir() const { return fLightDir; } - const SkColor3f& lightColor() const { return fLightColor; } + const SkTArray<SkLights::Light>& directionalLights() const { return fDirectionalLights; } const SkColor3f& ambientColor() const { return fAmbientColor; } private: @@ -248,14 +262,12 @@ private: bool onIsEqual(const GrFragmentProcessor& proc) const override { const LightingFP& lightingFP = proc.cast<LightingFP>(); - return fLightDir == lightingFP.fLightDir && - fLightColor == lightingFP.fLightColor && + return fDirectionalLights == lightingFP.fDirectionalLights && fAmbientColor == lightingFP.fAmbientColor; } - SkVector3 fLightDir; - SkColor3f fLightColor; - SkColor3f fAmbientColor; + SkTArray<SkLights::Light> fDirectionalLights; + SkColor3f fAmbientColor; }; //////////////////////////////////////////////////////////////////////////// @@ -482,6 +494,7 @@ SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, sk_sp<SkShader> SkLightingShader::Make(sk_sp<SkShader> diffuseShader, sk_sp<SkNormalSource> normalSource, sk_sp<SkLights> lights) { + SkASSERT(lights); if (!normalSource) { normalSource = SkNormalSource::MakeFlat(); } |