diff options
-rw-r--r-- | gm/lightingshader.cpp | 6 | ||||
-rw-r--r-- | include/effects/SkPoint3.h | 1 | ||||
-rwxr-xr-x | samplecode/SampleLighting.cpp | 17 | ||||
-rw-r--r-- | src/effects/SkLightingShader.cpp | 95 | ||||
-rw-r--r-- | src/effects/SkLightingShader.h | 18 |
5 files changed, 74 insertions, 63 deletions
diff --git a/gm/lightingshader.cpp b/gm/lightingshader.cpp index ad8823d27d..687968abb6 100644 --- a/gm/lightingshader.cpp +++ b/gm/lightingshader.cpp @@ -105,12 +105,12 @@ public: LightingShaderGM() { this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC)); - fLight.fColor = SkColorSetRGB(0xff, 0xff, 0xff); + fLight.fColor = SkColor3f::Make(1.0f, 1.0f, 1.0f); fLight.fDirection.fX = 0.0f; fLight.fDirection.fY = 0.0f; fLight.fDirection.fZ = 1.0f; - fAmbient = SkColorSetRGB(0x1f, 0x1f, 0x1f); + fAmbient = SkColor3f::Make(0.1f, 0.1f, 0.1f); } protected: @@ -171,7 +171,7 @@ private: SkBitmap fFrustumNormalMap; SkLightingShader::Light fLight; - SkColor fAmbient; + SkColor3f fAmbient; typedef GM INHERITED; }; diff --git a/include/effects/SkPoint3.h b/include/effects/SkPoint3.h index f9b727b998..c086931c08 100644 --- a/include/effects/SkPoint3.h +++ b/include/effects/SkPoint3.h @@ -109,5 +109,6 @@ struct SK_API SkPoint3 { }; typedef SkPoint3 SkVector3; +typedef SkPoint3 SkColor3f; #endif diff --git a/samplecode/SampleLighting.cpp b/samplecode/SampleLighting.cpp index 3cda0c6a56..5b4f2e0931 100755 --- a/samplecode/SampleLighting.cpp +++ b/samplecode/SampleLighting.cpp @@ -20,8 +20,8 @@ public: SkBitmap fDiffuseBitmap; SkBitmap fNormalBitmap; SkScalar fLightAngle; - int fColorFactor; - SkColor fAmbientColor; + SkScalar fColorFactor; + SkColor3f fAmbientColor; LightingView() { SkString diffusePath = GetResourcePath("brickwork-texture.jpg"); @@ -30,15 +30,15 @@ public: SkImageDecoder::DecodeFile(normalPath.c_str(), &fNormalBitmap); fLightAngle = 0.0f; - fColorFactor = 0; + fColorFactor = 0.0f; SkLightingShader::Light light; - light.fColor = SkColorSetRGB(0xff, 0xff, 0xff); + light.fColor = SkColor3f::Make(1.0f, 1.0f, 1.0f); light.fDirection.fX = SkScalarSin(fLightAngle)*SkScalarSin(SK_ScalarPI*0.25f); light.fDirection.fY = SkScalarCos(fLightAngle)*SkScalarSin(SK_ScalarPI*0.25f); light.fDirection.fZ = SkScalarCos(SK_ScalarPI*0.25f); - fAmbientColor = SkColorSetRGB(0x1f, 0x1f, 0x1f); + fAmbientColor = SkColor3f::Make(0.1f, 0.1f, 0.1f); fShader.reset(SkLightingShader::Create(fDiffuseBitmap, fNormalBitmap, light, fAmbientColor, nullptr)); @@ -58,10 +58,13 @@ protected: void onDrawContent(SkCanvas* canvas) override { fLightAngle += 0.015f; - fColorFactor++; + fColorFactor += 0.01f; + if (fColorFactor > 1.0f) { + fColorFactor = 0.0f; + } SkLightingShader::Light light; - light.fColor = SkColorSetRGB(0xff, 0xff, (fColorFactor >> 1) & 0xff); + light.fColor = SkColor3f::Make(1.0f, 1.0f, fColorFactor); light.fDirection.fX = SkScalarSin(fLightAngle)*SkScalarSin(SK_ScalarPI*0.25f); light.fDirection.fY = SkScalarCos(fLightAngle)*SkScalarSin(SK_ScalarPI*0.25f); light.fDirection.fZ = SkScalarCos(SK_ScalarPI*0.25f); diff --git a/src/effects/SkLightingShader.cpp b/src/effects/SkLightingShader.cpp index 7b55626f55..4dcfa527f9 100644 --- a/src/effects/SkLightingShader.cpp +++ b/src/effects/SkLightingShader.cpp @@ -25,8 +25,6 @@ support multiple lights enforce normal map is 4 channel use SkImages instead if SkBitmaps - vec3 for ambient and light-color - add dox for both lighting equation, and how we compute normal from bitmap To Test: non-opaque diffuse textures @@ -51,7 +49,7 @@ public: */ SkLightingShaderImpl(const SkBitmap& diffuse, const SkBitmap& normal, const SkLightingShader::Light& light, - const SkColor ambient, const SkMatrix* localMatrix) + const SkColor3f& ambient, const SkMatrix* localMatrix) : INHERITED(localMatrix) , fDiffuseMap(diffuse) , fNormalMap(normal) @@ -60,8 +58,6 @@ public: if (!fLight.fDirection.normalize()) { fLight.fDirection = SkPoint3::Make(0.0f, 0.0f, 1.0f); } - SkColorSetA(fLight.fColor, 0xFF); - SkColorSetA(fAmbientColor, 0xFF); } bool isOpaque() const override; @@ -103,7 +99,7 @@ private: SkBitmap fDiffuseMap; SkBitmap fNormalMap; SkLightingShader::Light fLight; - SkColor fAmbientColor; // linear (unpremul) color + SkColor3f fAmbientColor; // linear (unpremul) color. Range is 0..1/channel. friend class SkLightingShader; @@ -124,7 +120,8 @@ private: class LightingFP : public GrFragmentProcessor { public: LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& matrix, - SkVector3 lightDir, GrColor lightColor, GrColor ambientColor) + const SkVector3& lightDir, const SkColor3f& lightColor, + const SkColor3f& ambientColor) : fDeviceTransform(kDevice_GrCoordSet, matrix) , fDiffuseTextureAccess(diffuse) , fNormalTextureAccess(normal) @@ -140,8 +137,10 @@ public: class LightingGLFP : public GrGLFragmentProcessor { public: - LightingGLFP() : fLightColor(GrColor_ILLEGAL), fAmbientColor(GrColor_ILLEGAL) { + LightingGLFP() { fLightDir.fX = 10000.0f; + fLightColor.fX = 0.0f; + fAmbientColor.fX = 0.0f; } void emitCode(EmitArgs& args) override { @@ -156,12 +155,12 @@ public: const char* lightColorUniName = NULL; fLightColorUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, + kVec3f_GrSLType, kDefault_GrSLPrecision, "LightColor", &lightColorUniName); const char* ambientColorUniName = NULL; fAmbientColorUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, + kVec3f_GrSLType, kDefault_GrSLPrecision, "AmbientColor", &ambientColorUniName); fpb->codeAppend("vec4 diffuseColor = "); @@ -180,34 +179,30 @@ public: fpb->codeAppendf("vec3 lightDir = normalize(%s);", lightDirUniName); fpb->codeAppend("float NdotL = dot(normal, lightDir);"); // diffuse light - fpb->codeAppendf("vec3 result = %s.rgb*diffuseColor.rgb*NdotL;", lightColorUniName); + fpb->codeAppendf("vec3 result = %s*diffuseColor.rgb*NdotL;", lightColorUniName); // ambient light - fpb->codeAppendf("result += %s.rgb;", ambientColorUniName); + fpb->codeAppendf("result += %s;", ambientColorUniName); fpb->codeAppendf("%s = vec4(result.rgb, diffuseColor.a);", args.fOutputColor); } void setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) override { const LightingFP& lightingFP = proc.cast<LightingFP>(); - SkVector3 lightDir = lightingFP.lightDir(); + const SkVector3& lightDir = lightingFP.lightDir(); if (lightDir != fLightDir) { pdman.set3fv(fLightDirUni, 1, &lightDir.fX); fLightDir = lightDir; } - GrColor lightColor = lightingFP.lightColor(); + const SkColor3f& lightColor = lightingFP.lightColor(); if (lightColor != fLightColor) { - GrGLfloat c[4]; - GrColorToRGBAFloat(lightColor, c); - pdman.set4fv(fLightColorUni, 1, c); + pdman.set3fv(fLightColorUni, 1, &lightColor.fX); fLightColor = lightColor; } - GrColor ambientColor = lightingFP.ambientColor(); + const SkColor3f& ambientColor = lightingFP.ambientColor(); if (ambientColor != fAmbientColor) { - GrGLfloat c[4]; - GrColorToRGBAFloat(ambientColor, c); - pdman.set4fv(fAmbientColorUni, 1, c); + pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX); fAmbientColor = ambientColor; } } @@ -223,10 +218,10 @@ public: SkVector3 fLightDir; GrGLProgramDataManager::UniformHandle fLightDirUni; - GrColor fLightColor; + SkColor3f fLightColor; GrGLProgramDataManager::UniformHandle fLightColorUni; - GrColor fAmbientColor; + SkColor3f fAmbientColor; GrGLProgramDataManager::UniformHandle fAmbientColorUni; }; @@ -242,9 +237,9 @@ public: inout->mulByUnknownFourComponents(); } - SkVector3 lightDir() const { return fLightDir; } - GrColor lightColor() const { return fLightColor; } - GrColor ambientColor() const { return fAmbientColor; } + const SkVector3& lightDir() const { return fLightDir; } + const SkColor3f& lightColor() const { return fLightColor; } + const SkColor3f& ambientColor() const { return fAmbientColor; } private: bool onIsEqual(const GrFragmentProcessor& proc) const override { @@ -261,8 +256,8 @@ private: GrTextureAccess fDiffuseTextureAccess; GrTextureAccess fNormalTextureAccess; SkVector3 fLightDir; - GrColor fLightColor; - GrColor fAmbientColor; + SkColor3f fLightColor; + SkColor3f fAmbientColor; }; //////////////////////////////////////////////////////////////////////////// @@ -341,13 +336,8 @@ bool SkLightingShaderImpl::asFragmentProcessor(GrContext* context, const SkPaint return false; } - GrColor lightColor = GrColorPackRGBA(SkColorGetR(fLight.fColor), SkColorGetG(fLight.fColor), - SkColorGetB(fLight.fColor), SkColorGetA(fLight.fColor)); - GrColor ambientColor = GrColorPackRGBA(SkColorGetR(fAmbientColor), SkColorGetG(fAmbientColor), - SkColorGetB(fAmbientColor), SkColorGetA(fAmbientColor)); - *fp = SkNEW_ARGS(LightingFP, (diffuseTexture, normalTexture, matrix, - fLight.fDirection, lightColor, ambientColor)); + fLight.fDirection, fLight.fColor, fAmbientColor)); *color = GrColorPackA4(paint.getAlpha()); return true; } @@ -400,14 +390,14 @@ SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() { fNormalState->~SkBitmapProcState(); } -static inline int light(int light, int diff, SkScalar NdotL, int ambient) { - int color = int(light * diff * NdotL + 255 * ambient); - if (color <= 0) { +static inline int light(SkScalar light, int diff, SkScalar NdotL, SkScalar ambient) { + SkScalar color = light * diff * NdotL + 255 * ambient; + if (color <= 0.0f) { return 0; - } else if (color >= 255*255) { + } else if (color >= 255.0f) { return 255; } else { - return SkDiv255Round(color); + return (int) color; } } @@ -458,12 +448,12 @@ void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, NdotL = norm.dot(lightShader.fLight.fDirection); // This is all done in linear unpremul color space - r = light(SkColorGetR(lightShader.fLight.fColor), SkColorGetR(diffColor), NdotL, - SkColorGetR(lightShader.fAmbientColor)); - g = light(SkColorGetG(lightShader.fLight.fColor), SkColorGetG(diffColor), NdotL, - SkColorGetG(lightShader.fAmbientColor)); - b = light(SkColorGetB(lightShader.fLight.fColor), SkColorGetB(diffColor), NdotL, - SkColorGetB(lightShader.fAmbientColor)); + r = light(lightShader.fLight.fColor.fX, SkColorGetR(diffColor), NdotL, + lightShader.fAmbientColor.fX); + g = light(lightShader.fLight.fColor.fY, SkColorGetG(diffColor), NdotL, + lightShader.fAmbientColor.fY); + b = light(lightShader.fLight.fColor.fZ, SkColorGetB(diffColor), NdotL, + lightShader.fAmbientColor.fZ); result[i] = SkPreMultiplyARGB(SkColorGetA(diffColor), r, g, b); } @@ -502,9 +492,14 @@ SkFlattenable* SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) { if (!buf.readScalarArray(&light.fDirection.fX, 3)) { return NULL; } - light.fColor = buf.readColor(); + if (!buf.readScalarArray(&light.fColor.fX, 3)) { + return NULL; + } - SkColor ambient = buf.readColor(); + SkColor3f ambient; + if (!buf.readScalarArray(&ambient.fX, 3)) { + return NULL; + } return SkNEW_ARGS(SkLightingShaderImpl, (diffuse, normal, light, ambient, &localMatrix)); } @@ -515,8 +510,8 @@ void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { buf.writeBitmap(fDiffuseMap); buf.writeBitmap(fNormalMap); buf.writeScalarArray(&fLight.fDirection.fX, 3); - buf.writeColor(fLight.fColor); - buf.writeColor(fAmbientColor); + buf.writeScalarArray(&fLight.fColor.fX, 3); + buf.writeScalarArray(&fAmbientColor.fX, 3); } SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, @@ -571,7 +566,7 @@ static bool bitmap_is_too_big(const SkBitmap& bm) { SkShader* SkLightingShader::Create(const SkBitmap& diffuse, const SkBitmap& normal, const SkLightingShader::Light& light, - const SkColor ambient, + const SkColor3f& ambient, const SkMatrix* localMatrix) { if (diffuse.isNull() || bitmap_is_too_big(diffuse) || normal.isNull() || bitmap_is_too_big(normal) || diff --git a/src/effects/SkLightingShader.h b/src/effects/SkLightingShader.h index b85e4318d3..64d41a291e 100644 --- a/src/effects/SkLightingShader.h +++ b/src/effects/SkLightingShader.h @@ -18,7 +18,7 @@ public: struct Light { SkVector3 fDirection; // direction towards the light (+Z is out of the screen). // If degenerate, it will be replaced with (0, 0, 1). - SkColor fColor; // linear (unpremul) color. Note: alpha assumed to be 255. + SkColor3f fColor; // linear (unpremul) color. Range is 0..1 in each channel. }; /** Returns a shader that lights the diffuse and normal maps with a single light. @@ -29,16 +29,28 @@ public: @param diffuse the diffuse bitmap @param normal the normal map @param light the light applied to the normal map - @param ambient the linear (unpremul) ambient light color. Note: alpha assumed to be 255. + @param ambient the linear (unpremul) ambient light color. Range is 0..1/channel. @param localMatrix the matrix mapping the textures to the dest rect NULL will be returned if: either 'diffuse' or 'normal' are empty either 'diffuse' or 'normal' are too big (> 65535 on a side) 'diffuse' and 'normal' aren't the same size + + The lighting equation is currently: + result = LightColor * DiffuseColor * (Normal * LightDir) + AmbientColor + + The normal map is currently assumed to be an 8888 image where the normal at a texel + is retrieved by: + N.x = R-127; + N.y = G-127; + N.z = B-127; + N.normalize(); + The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is + (127, 127, 0). */ static SkShader* Create(const SkBitmap& diffuse, const SkBitmap& normal, - const SkLightingShader::Light& light, const SkColor ambient, + const SkLightingShader::Light& light, const SkColor3f& ambient, const SkMatrix* localMatrix); SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() |