Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(629)

Side by Side Diff: samplecode/SampleLighting.cpp

Issue 1212813009: Add normal map sample (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address comments Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « resources/brickwork_normal-map.jpg ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1
2 /*
3 * Copyright 2015 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8 #include "SampleCode.h"
9 #include "Resources.h"
10
11 #include "SkCanvas.h"
12 #include "SkErrorInternals.h"
13 #include "SkGr.h"
14 #include "SkReadBuffer.h"
15 #include "SkShader.h"
16 #include "SkWriteBuffer.h"
17
18 #include "GrFragmentProcessor.h"
19 #include "GrCoordTransform.h"
20 #include "gl/GrGLProcessor.h"
21 #include "gl/builders/GrGLProgramBuilder.h"
22
23 ///////////////////////////////////////////////////////////////////////////////
24
25 struct SkVector3 {
robertphillips 2015/07/08 20:39:24 fX, fY, fZ ?
jvanverth1 2015/07/08 20:54:12 Done.
26 SkScalar x, y, z;
27
28 bool operator==(const SkVector3& other) const {
29 return x == other.x && y == other.y && z == other.z;
30 }
31
32 bool operator!=(const SkVector3& other) const {
33 return !(*this == other);
34 }
35 };
36
37 class LightingShader : public SkShader {
38 public:
39 struct Light {
40 SkVector3 fDirection;
41 SkColor fColor; // assumed to be linear color
42 };
43
44 LightingShader(const SkBitmap& diffuse, const SkBitmap& normal, const Light& light,
45 const SkColor ambient)
46 : fDiffuseMap(diffuse)
47 , fNormalMap(normal)
48 , fLight(light)
49 , fAmbientColor(ambient) {}
50
51 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(LightingShader);
52
53 void flatten(SkWriteBuffer& buf) const override {
54 buf.writeBitmap(fDiffuseMap);
55 buf.writeBitmap(fNormalMap);
56 buf.writeScalarArray(&fLight.fDirection.x, 3);
57 buf.writeColor(fLight.fColor);
58 buf.writeColor(fAmbientColor);
59 }
60
61 bool asFragmentProcessor(GrContext*, const SkPaint& paint, const SkMatrix& v iewM,
62 const SkMatrix* localMatrix, GrColor* color,
63 GrFragmentProcessor** fp) const override;
64
65 SkShader::BitmapType asABitmap(SkBitmap* bitmap, SkMatrix* matrix,
66 SkShader::TileMode* xy) const override {
67 if (bitmap) {
68 *bitmap = fDiffuseMap;
69 }
70 if (matrix) {
71 matrix->reset();
72 }
73 if (xy) {
74 xy[0] = kClamp_TileMode;
75 xy[1] = kClamp_TileMode;
76 }
77 return kDefault_BitmapType;
78 }
79
80 #ifndef SK_IGNORE_TO_STRING
81 void toString(SkString* str) const override {
82 str->appendf("LightingShader: ()");
83 }
84 #endif
85
86 void setLight(const Light& light) { fLight = light; }
87
88 private:
89 SkBitmap fDiffuseMap;
90 SkBitmap fNormalMap;
91 Light fLight;
92 SkColor fAmbientColor;
93 };
94
95 SkFlattenable* LightingShader::CreateProc(SkReadBuffer& buf) {
96 SkBitmap diffuse;
97 if (!buf.readBitmap(&diffuse)) {
98 return NULL;
99 }
100 diffuse.setImmutable();
101
102 SkBitmap normal;
103 if (!buf.readBitmap(&normal)) {
104 return NULL;
105 }
106 normal.setImmutable();
107
108 Light light;
109 if (!buf.readScalarArray(&light.fDirection.x, 3)) {
110 return NULL;
111 }
112 light.fColor = buf.readColor();
113
114 SkColor ambient = buf.readColor();
115
116 return SkNEW_ARGS(LightingShader, (diffuse, normal, light, ambient));
117 }
118
119 ////////////////////////////////////////////////////////////////////////////
120
121 class LightingFP : public GrFragmentProcessor {
122 public:
123 LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& matrix,
124 SkVector3 lightDir, GrColor lightColor, GrColor ambientColor)
125 : fDiffuseTextureAccess(diffuse)
126 , fNormalTextureAccess(normal)
127 , fDeviceTransform(kDevice_GrCoordSet, matrix)
128 , fLightDir(lightDir)
129 , fLightColor(lightColor)
130 , fAmbientColor(ambientColor) {
131 this->addCoordTransform(&fDeviceTransform);
132 this->addTextureAccess(&fDiffuseTextureAccess);
133 this->addTextureAccess(&fNormalTextureAccess);
134
135 this->initClassID<LightingFP>();
136 }
137
138 class LightingGLFP : public GrGLFragmentProcessor {
139 public:
140 LightingGLFP() : fLightColor(GrColor_ILLEGAL) {
141 fLightDir.x = 10000.0f;
142 }
143
144 void emitCode(GrGLFPBuilder* builder,
145 const GrFragmentProcessor& fp,
146 const char* outputColor,
147 const char* inputColor,
148 const TransformedCoordsArray& coords,
149 const TextureSamplerArray& samplers) override {
150
151 GrGLFragmentBuilder* fpb = builder->getFragmentShaderBuilder();
152
153 // add uniforms
154 const char* lightDirUniName = NULL;
155 fLightDirUni = builder->addUniform(GrGLProgramBuilder::kFragment_Vis ibility,
156 kVec3f_GrSLType, kDefault_GrSLPre cision,
157 "LightDir", &lightDirUniName);
158
159 const char* lightColorUniName = NULL;
160 fLightColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_V isibility,
161 kVec4f_GrSLType, kDefault_GrSLP recision,
162 "LightColor", &lightColorUniNam e);
163
164 const char* ambientColorUniName = NULL;
165 fAmbientColorUni = builder->addUniform(GrGLProgramBuilder::kFragment _Visibility,
166 kVec4f_GrSLType, kDefault_GrS LPrecision,
167 "AmbientColor", &ambientColor UniName);
168
169 fpb->codeAppend("vec4 diffuseColor = ");
170 fpb->appendTextureLookupAndModulate(inputColor, samplers[0],
171 coords[0].c_str(), coords[0].get Type());
172 fpb->codeAppend(";");
173
174 fpb->codeAppend("vec4 normalColor = ");
175 fpb->appendTextureLookup(samplers[1], coords[0].c_str(), coords[0].g etType());
176 fpb->codeAppend(";");
177
178 fpb->codeAppend("vec3 normal = normalize(2.0*(normalColor.rgb - vec3 (0.5)));");
179 fpb->codeAppendf("vec3 lightDir = normalize(%s);", lightDirUniName);
180 fpb->codeAppend("float NdotL = dot(normal, lightDir);");
181 // diffuse light
182 fpb->codeAppendf("vec3 result = %s.rgb*diffuseColor.rgb*NdotL;", lig htColorUniName);
183 // ambient light
184 fpb->codeAppendf("result += %s.rgb;", ambientColorUniName);
185 fpb->codeAppendf("%s = vec4(result.rgb, diffuseColor.a);", outputCol or);
186 }
187
188 void setData(const GrGLProgramDataManager& pdman, const GrProcessor& pro c) override {
189 const LightingFP& lightingFP = proc.cast<LightingFP>();
190
191 SkVector3 lightDir = lightingFP.lightDir();
192 if (lightDir != fLightDir) {
193 pdman.set3fv(fLightDirUni, 1, &lightDir.x);
194 fLightDir = lightDir;
195 }
196
197 GrColor lightColor = lightingFP.lightColor();
198 if (lightColor != fLightColor) {
199 GrGLfloat c[4];
200 GrColorToRGBAFloat(lightColor, c);
201 pdman.set4fv(fLightColorUni, 1, c);
202 fLightColor = lightColor;
203 }
204
205 GrColor ambientColor = lightingFP.ambientColor();
206 if (ambientColor != fAmbientColor) {
207 GrGLfloat c[4];
208 GrColorToRGBAFloat(ambientColor, c);
209 pdman.set4fv(fAmbientColorUni, 1, c);
210 fAmbientColor = ambientColor;
211 }
212 }
213
214 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
robertphillips 2015/07/08 20:39:24 tab over ?
jvanverth1 2015/07/08 20:54:12 Done.
215 GrProcessorKeyBuilder* b) {
216 // const LightingFP& lightingFP = proc.cast<LightingFP>();
217 // only one shader generated currently
218 b->add32(0x0);
219 }
220
221 private:
222 SkVector3 fLightDir;
223 GrGLProgramDataManager::UniformHandle fLightDirUni;
224
225 GrColor fLightColor;
226 GrGLProgramDataManager::UniformHandle fLightColorUni;
227
228 GrColor fAmbientColor;
229 GrGLProgramDataManager::UniformHandle fAmbientColorUni;
230 };
231
232 GrGLFragmentProcessor* createGLInstance() const override {
233
robertphillips 2015/07/08 20:39:24 extra \n ?
jvanverth1 2015/07/08 20:54:12 Done.
234 return SkNEW(LightingGLFP);
235 }
236
237 void getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) con st override {
238 LightingGLFP::GenKey(*this, caps, b);
239 }
240
241 const char* name() const override { return "LightingFP"; }
242
243 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
244 inout->mulByUnknownFourComponents();
245 }
246
247 SkVector3 lightDir() const { return fLightDir; }
248 GrColor lightColor() const { return fLightColor; }
249 GrColor ambientColor() const { return fAmbientColor; }
250
251 private:
252 bool onIsEqual(const GrFragmentProcessor& proc) const override {
253 const LightingFP& lightingFP = proc.cast<LightingFP>();
254 return fDeviceTransform == lightingFP.fDeviceTransform &&
robertphillips 2015/07/08 20:39:24 line up?
jvanverth1 2015/07/08 20:54:11 Done.
255 fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess &&
256 fNormalTextureAccess == lightingFP.fNormalTextureAccess &&
257 fLightDir == lightingFP.fLightDir &&
258 fLightColor == lightingFP.fLightColor &&
259 fAmbientColor == lightingFP.fAmbientColor;
260 }
261
262 GrCoordTransform fDeviceTransform;
263 GrTextureAccess fDiffuseTextureAccess;
264 GrTextureAccess fNormalTextureAccess;
265 SkVector3 fLightDir;
266 GrColor fLightColor;
267 GrColor fAmbientColor;
268 };
269
270 bool LightingShader::asFragmentProcessor(GrContext* context, const SkPaint& pain t,
271 const SkMatrix& viewM, const SkMatrix* localMatrix,
272 GrColor* color, GrFragmentProcessor** f p) const {
273 // we assume diffuse and normal maps have same width and height
274 // TODO: support different sizes
275 SkASSERT(fDiffuseMap.width() == fNormalMap.width() &&
276 fDiffuseMap.height() == fNormalMap.height());
277 SkMatrix matrix;
278 matrix.setIDiv(fDiffuseMap.width(), fDiffuseMap.height());
279
280 SkMatrix lmInverse;
281 if (!this->getLocalMatrix().invert(&lmInverse)) {
282 return false;
283 }
284 if (localMatrix) {
285 SkMatrix inv;
286 if (!localMatrix->invert(&inv)) {
287 return false;
288 }
289 lmInverse.postConcat(inv);
290 }
291 matrix.preConcat(lmInverse);
292
293 // Must set wrap and filter on the sampler before requesting a texture. In t wo places below
294 // we check the matrix scale factors to determine how to interpret the filte r quality setting.
295 // This completely ignores the complexity of the drawVertices case where exp licit local coords
296 // are provided by the caller.
297 GrTextureParams::FilterMode textureFilterMode = GrTextureParams::kBilerp_Fil terMode;
298 switch (paint.getFilterQuality()) {
299 case kNone_SkFilterQuality:
300 textureFilterMode = GrTextureParams::kNone_FilterMode;
301 break;
302 case kLow_SkFilterQuality:
303 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
304 break;
305 case kMedium_SkFilterQuality:{
306 SkMatrix matrix;
307 matrix.setConcat(viewM, this->getLocalMatrix());
308 if (matrix.getMinScale() < SK_Scalar1) {
309 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
310 } else {
311 // Don't trigger MIP level generation unnecessarily.
312 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
313 }
314 break;
315 }
316 case kHigh_SkFilterQuality:
317 default:
318 SkErrorInternals::SetError(kInvalidPaint_SkError,
319 "Sorry, I don't understand the filtering "
320 "mode you asked for. Falling back to "
321 "MIPMaps.");
322 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
323 break;
324
325 }
326
327 // TODO: support other tile modes
328 GrTextureParams params(kClamp_TileMode, textureFilterMode);
329 SkAutoTUnref<GrTexture> diffuseTexture(GrRefCachedBitmapTexture(context, fDi ffuseMap, &params));
330 if (!diffuseTexture) {
331 SkErrorInternals::SetError(kInternalError_SkError,
332 "Couldn't convert bitmap to texture.");
333 return false;
334 }
335
336 SkAutoTUnref<GrTexture> normalTexture(GrRefCachedBitmapTexture(context, fNor malMap, &params));
337 if (!normalTexture) {
338 SkErrorInternals::SetError(kInternalError_SkError,
339 "Couldn't convert bitmap to texture.");
340 return false;
341 }
342
343 GrColor lightColor = GrColorPackRGBA(SkColorGetR(fLight.fColor), SkColorGetG (fLight.fColor),
344 SkColorGetB(fLight.fColor), SkColorGetA (fLight.fColor));
345 GrColor ambientColor = GrColorPackRGBA(SkColorGetR(fAmbientColor), SkColorGe tG(fAmbientColor),
346 SkColorGetB(fAmbientColor), SkColorGe tA(fAmbientColor));
347
348 *fp = SkNEW_ARGS(LightingFP, (diffuseTexture, normalTexture, matrix,
349 fLight.fDirection, lightColor, ambientColor));
350 *color = GrColorPackA4(paint.getAlpha());
351 return true;
352 }
353
354 ////////////////////////////////////////////////////////////////////////////
355
356 class LightingView : public SampleView {
357 public:
358 SkAutoTUnref<LightingShader> fShader;
359 SkBitmap fDiffuseBitmap;
360 SkBitmap fNormalBitmap;
361 SkScalar fLightAngle;
362 int fColorFactor;
363
364 LightingView() {
365 SkString diffusePath = GetResourcePath("brickwork-texture.jpg");
366 SkImageDecoder::DecodeFile(diffusePath.c_str(), &fDiffuseBitmap);
367 SkString normalPath = GetResourcePath("brickwork_normal-map.jpg");
368 SkImageDecoder::DecodeFile(normalPath.c_str(), &fNormalBitmap);
369
370 fLightAngle = 0.0f;
371 fColorFactor = 0;
372
373 LightingShader::Light light;
374 light.fColor = SkColorSetRGB(0xff, 0xff, 0xff);
375 light.fDirection.x = 0;
376 light.fDirection.y = SkScalarSin(fLightAngle);
377 light.fDirection.z = SkScalarCos(fLightAngle);
378
379 SkColor ambient = SkColorSetRGB(0x1f, 0x1f, 0x1f);
380
381 fShader.reset(SkNEW_ARGS(LightingShader, (fDiffuseBitmap, fNormalBitmap, light, ambient)));
382 }
383
384 virtual ~LightingView() {}
385
386 protected:
387 // overrides from SkEventSink
388 bool onQuery(SkEvent* evt) override {
389 if (SampleCode::TitleQ(*evt)) {
390 SampleCode::TitleR(evt, "Lighting");
391 return true;
392 }
393 return this->INHERITED::onQuery(evt);
394 }
395
396 void onDrawContent(SkCanvas* canvas) override {
397 fLightAngle += 0.015f;
398 fColorFactor++;
399
400 LightingShader::Light light;
401 light.fColor = SkColorSetRGB(0xff, 0xff, (fColorFactor >> 1) & 0xff);
robertphillips 2015/07/08 20:39:24 .785 -> SK_ScalarPI/4 ?
jvanverth1 2015/07/08 20:54:11 Done.
402 light.fDirection.x = SkScalarSin(fLightAngle)*SkScalarSin(0.785f);
403 light.fDirection.y = SkScalarCos(fLightAngle)*SkScalarSin(0.785f);
404 light.fDirection.z = SkScalarCos(0.785f);
405
406 fShader.get()->setLight(light);
407
408 SkPaint paint;
409 paint.setShader(fShader);
410 paint.setColor(SK_ColorBLACK);
411
robertphillips 2015/07/08 20:39:24 r = SkRect::MakeWH(fDiffuseBitmap.width(), fDiffus
jvanverth1 2015/07/08 20:54:12 Done.
412 SkRect r;
413 int w = fDiffuseBitmap.width();
414 int h = fDiffuseBitmap.height();
415 r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
416
417 canvas->drawRect(r, paint);
418
419 // so we're constantly updating
420 this->inval(NULL);
421 }
422
423 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) ove rride {
424 this->inval(NULL);
425 return this->INHERITED::onFindClickHandler(x, y, modi);
426 }
427
428 private:
429 typedef SampleView INHERITED;
430 };
431
432 //////////////////////////////////////////////////////////////////////////////
433
434 static SkView* MyFactory() { return new LightingView; }
435 static SkViewRegister reg(MyFactory);
OLDNEW
« no previous file with comments | « resources/brickwork_normal-map.jpg ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698