Address some SkLightingShader TODOs

This CL:
  switches the light colors to be 3 scalars (SkColor3f)
  adds some dox

Review URL: https://codereview.chromium.org/1265983003
This commit is contained in:
robertphillips 2015-07-31 05:17:24 -07:00 committed by Commit bot
parent 850bbf1bb6
commit a9652ac09e
5 changed files with 74 additions and 63 deletions

View File

@ -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;
};

View File

@ -109,5 +109,6 @@ struct SK_API SkPoint3 {
};
typedef SkPoint3 SkVector3;
typedef SkPoint3 SkColor3f;
#endif

View File

@ -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);

View File

@ -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) ||

View File

@ -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()