OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkError.h" | 8 #include "SkError.h" |
9 #include "SkErrorInternals.h" | 9 #include "SkErrorInternals.h" |
10 #include "SkLightingShader.h" | 10 #include "SkLightingShader.h" |
11 #include "SkMatrix.h" | |
11 #include "SkNormalSource.h" | 12 #include "SkNormalSource.h" |
12 #include "SkReadBuffer.h" | 13 #include "SkReadBuffer.h" |
13 #include "SkWriteBuffer.h" | 14 #include "SkWriteBuffer.h" |
14 | 15 |
15 // Genretating vtable | 16 // Genretating vtable |
16 SkNormalSource::~SkNormalSource() {} | 17 SkNormalSource::~SkNormalSource() {} |
17 | 18 |
18 /////////////////////////////////////////////////////////////////////////////// | 19 /////////////////////////////////////////////////////////////////////////////// |
19 | 20 |
20 class NormalMapSourceImpl : public SkNormalSource { | 21 class NormalMapSourceImpl : public SkNormalSource { |
21 public: | 22 public: |
22 NormalMapSourceImpl(sk_sp<SkShader> mapShader, const SkVector &normRotation) | 23 NormalMapSourceImpl(sk_sp<SkShader> mapShader, const SkMatrix& invCTM) |
23 : fMapShader(std::move(mapShader)) | 24 : fMapShader(std::move(mapShader)) |
24 , fNormRotation(normRotation) {} | 25 , fInvCTM(invCTM) {} |
25 | 26 |
26 #if SK_SUPPORT_GPU | 27 #if SK_SUPPORT_GPU |
27 sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, | 28 sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, |
28 const SkMatrix& viewM, | 29 const SkMatrix& viewM, |
29 const SkMatrix* localMatrix, | 30 const SkMatrix* localMatrix, |
30 SkFilterQuality, | 31 SkFilterQuality, |
31 SkSourceGammaTreatment) const override; | 32 SkSourceGammaTreatment) const override; |
32 #endif | 33 #endif |
33 | 34 |
34 SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec, | 35 SkNormalSource::Provider* asProvider(const SkShader::ContextRec& rec, |
(...skipping 16 matching lines...) Expand all Loading... | |
51 | 52 |
52 void fillScanLine(int x, int y, SkPoint3 output[], int count) const over ride; | 53 void fillScanLine(int x, int y, SkPoint3 output[], int count) const over ride; |
53 private: | 54 private: |
54 const NormalMapSourceImpl& fSource; | 55 const NormalMapSourceImpl& fSource; |
55 SkShader::Context* fMapContext; | 56 SkShader::Context* fMapContext; |
56 | 57 |
57 typedef SkNormalSource::Provider INHERITED; | 58 typedef SkNormalSource::Provider INHERITED; |
58 }; | 59 }; |
59 | 60 |
60 sk_sp<SkShader> fMapShader; | 61 sk_sp<SkShader> fMapShader; |
61 SkVector fNormRotation; | 62 SkMatrix fInvCTM; // Inverse of the canvas total matrix, used for rot ating normals. |
62 | 63 |
63 friend class SkNormalSource; | 64 friend class SkNormalSource; |
64 | 65 |
65 typedef SkNormalSource INHERITED; | 66 typedef SkNormalSource INHERITED; |
66 }; | 67 }; |
67 | 68 |
68 //////////////////////////////////////////////////////////////////////////// | 69 //////////////////////////////////////////////////////////////////////////// |
69 | 70 |
70 #if SK_SUPPORT_GPU | 71 #if SK_SUPPORT_GPU |
71 | 72 |
72 #include "GrCoordTransform.h" | 73 #include "GrCoordTransform.h" |
73 #include "GrInvariantOutput.h" | 74 #include "GrInvariantOutput.h" |
74 #include "GrTextureParams.h" | 75 #include "GrTextureParams.h" |
75 #include "glsl/GrGLSLFragmentProcessor.h" | 76 #include "glsl/GrGLSLFragmentProcessor.h" |
76 #include "glsl/GrGLSLFragmentShaderBuilder.h" | 77 #include "glsl/GrGLSLFragmentShaderBuilder.h" |
77 #include "SkGr.h" | 78 #include "SkGr.h" |
78 | 79 |
79 class NormalMapFP : public GrFragmentProcessor { | 80 class NormalMapFP : public GrFragmentProcessor { |
80 public: | 81 public: |
81 NormalMapFP(sk_sp<GrFragmentProcessor> mapFP, const SkVector& normRotation) | 82 NormalMapFP(sk_sp<GrFragmentProcessor> mapFP, const SkMatrix& invCTM) |
82 : fNormRotation(normRotation) { | 83 : fInvCTM(invCTM) { |
83 this->registerChildProcessor(mapFP); | 84 this->registerChildProcessor(mapFP); |
84 | 85 |
85 this->initClassID<NormalMapFP>(); | 86 this->initClassID<NormalMapFP>(); |
86 } | 87 } |
87 | 88 |
88 class GLSLNormalMapFP : public GrGLSLFragmentProcessor { | 89 class GLSLNormalMapFP : public GrGLSLFragmentProcessor { |
89 public: | 90 public: |
90 GLSLNormalMapFP() { | 91 GLSLNormalMapFP() { |
91 fNormRotation.set(0.0f, 0.0f); | 92 fInvCTM.reset(); |
92 } | 93 } |
93 | 94 |
94 void emitCode(EmitArgs& args) override { | 95 void emitCode(EmitArgs& args) override { |
95 | |
96 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; | 96 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; |
97 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | 97 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
98 | 98 |
99 // add uniform | 99 // add uniform |
100 const char* xformUniName = nullptr; | 100 const char* xformUniName = nullptr; |
robertphillips
2016/07/06 16:36:33
It looks like we only use the upper left 2x2 - why
dvonbeck
2016/07/06 18:07:48
Done.
| |
101 fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, | 101 fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat3 3f_GrSLType, |
102 kVec2f_GrSLType, kDefault_GrS LPrecision, | 102 kDefault_GrSLPrecision, "Xfor m", &xformUniName); |
103 "Xform", &xformUniName); | |
104 | 103 |
105 SkString dstNormalColorName("dstNormalColor"); | 104 SkString dstNormalColorName("dstNormalColor"); |
106 this->emitChild(0, nullptr, &dstNormalColorName, args); | 105 this->emitChild(0, nullptr, &dstNormalColorName, args); |
107 fragBuilder->codeAppendf("vec3 normal = %s.rgb - vec3(0.5);", | 106 fragBuilder->codeAppendf("vec3 normal = normalize(%s.rgb - vec3(0.5) );", |
108 dstNormalColorName.c_str()); | 107 dstNormalColorName.c_str()); |
109 | 108 |
110 // TODO: inverse map the light direction vectors in the vertex shade r rather than | 109 // TODO: inverse map the light direction vectors in the vertex shade r rather than |
111 // transforming all the normals here! | 110 // transforming all the normals here! |
112 fragBuilder->codeAppendf( | |
113 "mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);", | |
114 xformUniName, xformUniName, xformUniName, xformUniName); | |
115 | 111 |
robertphillips
2016/07/06 16:36:34
A branch in the shader is expensive !
dvonbeck
2016/07/06 18:07:48
The code seemed to run just fine ignoring the divi
robertphillips
2016/07/06 19:11:14
I would say leave the guard for now. I just wanted
dvonbeck
2016/07/06 19:34:36
Alright! I think it should be fine here considerin
| |
116 fragBuilder->codeAppend("normal = normalize(m*normal);"); | 112 // If there's no x & y components, return (0, 0, +/- 1) instead to a void division by 0 |
117 fragBuilder->codeAppendf("%s = vec4(normal, 0);", args.fOutputColor) ; | 113 fragBuilder->codeAppend( "if (abs(normal.z) > 0.9999) {"); |
robertphillips
2016/07/06 16:36:33
Might as well just set it to (0, 0, 1, 0).
dvonbeck
2016/07/06 18:07:48
Needs to handle (0, 0, -1, 0) as well. I could set
robertphillips
2016/07/06 19:11:14
Okay - leave it as is.
| |
114 fragBuilder->codeAppendf(" %s = normalize(vec4(0.0, 0.0, normal.z , 0.0));", | |
115 args.fOutputColor); | |
116 // Else, Normalizing the transformed X and Y, while keeping constant both Z and the | |
117 // vector's angle in the XY plane. This maintains the "slope" for th e surface while | |
118 // appropriately rotating the normal for any anisotropic scaling tha t occurs. | |
119 // Here, we call scaling factor the number that must divide the tran sformed X and Y so | |
120 // that the normal's length remains equal to 1. | |
121 fragBuilder->codeAppend( "} else {"); | |
122 fragBuilder->codeAppendf(" vec2 transformed = mat2(%s) * normal.x y;", | |
123 xformUniName); | |
124 fragBuilder->codeAppend( " float scalingFactorSquared = " | |
robertphillips
2016/07/06 16:36:34
Using pows for squares seems a bit overkill.
dvonbeck
2016/07/06 18:07:48
Should I be using *?
robertphillips
2016/07/06 19:11:14
Right, I would just have multiplies. The compiler
dvonbeck
2016/07/06 19:34:36
Done.
| |
125 "(pow(transformed.x, 2) + pow(t ransformed.y, 2))" | |
126 "/(1.0 - pow(normal.z, 2));"); | |
127 fragBuilder->codeAppendf(" %s = vec4(transformed*inversesqrt(scal ingFactorSquared)," | |
128 "normal.z, 0.0);", | |
129 args.fOutputColor); | |
130 fragBuilder->codeAppend( "}"); | |
118 } | 131 } |
119 | 132 |
120 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, | 133 static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, |
121 GrProcessorKeyBuilder* b) { | 134 GrProcessorKeyBuilder* b) { |
122 b->add32(0x0); | 135 b->add32(0x0); |
123 } | 136 } |
124 | 137 |
125 protected: | 138 protected: |
126 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { | 139 void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { |
127 const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>(); | 140 const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>(); |
128 | 141 |
129 const SkVector& normRotation = normalMapFP.normRotation(); | 142 const SkMatrix& invCTM = normalMapFP.invCTM(); |
130 if (normRotation != fNormRotation) { | 143 fInvCTM = invCTM; |
131 pdman.set2fv(fXformUni, 1, &normRotation.fX); | 144 pdman.setSkMatrix(fXformUni, fInvCTM); |
132 fNormRotation = normRotation; | |
133 } | |
134 } | 145 } |
135 | 146 |
136 private: | 147 private: |
137 SkVector fNormRotation; | 148 SkMatrix fInvCTM; |
138 GrGLSLProgramDataManager::UniformHandle fXformUni; | 149 GrGLSLProgramDataManager::UniformHandle fXformUni; |
139 }; | 150 }; |
140 | 151 |
141 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { | 152 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { |
142 GLSLNormalMapFP::GenKey(*this, caps, b); | 153 GLSLNormalMapFP::GenKey(*this, caps, b); |
143 } | 154 } |
144 | 155 |
145 const char* name() const override { return "NormalMapFP"; } | 156 const char* name() const override { return "NormalMapFP"; } |
146 | 157 |
147 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { | 158 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { |
148 inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput); | 159 inout->setToUnknown(GrInvariantOutput::ReadInput::kWillNot_ReadInput); |
149 } | 160 } |
150 | 161 |
151 const SkVector& normRotation() const { return fNormRotation; } | 162 const SkMatrix& invCTM() const { return fInvCTM; } |
152 | 163 |
153 private: | 164 private: |
154 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; } | 165 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLNormalMapFP; } |
155 | 166 |
156 bool onIsEqual(const GrFragmentProcessor& proc) const override { | 167 bool onIsEqual(const GrFragmentProcessor& proc) const override { |
157 const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>(); | 168 const NormalMapFP& normalMapFP = proc.cast<NormalMapFP>(); |
158 return fNormRotation == normalMapFP.fNormRotation; | 169 return fInvCTM == normalMapFP.fInvCTM; |
159 } | 170 } |
160 | 171 |
161 SkVector fNormRotation; | 172 SkMatrix fInvCTM; |
162 }; | 173 }; |
163 | 174 |
164 sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor( | 175 sk_sp<GrFragmentProcessor> NormalMapSourceImpl::asFragmentProcessor( |
165 GrContext *context, | 176 GrContext *context, |
166 const SkMatrix &viewM, | 177 const SkMatrix &viewM, |
167 const SkMatrix *localMatrix , | 178 const SkMatrix *localMatrix , |
168 SkFilterQuality filterQuali ty, | 179 SkFilterQuality filterQuali ty, |
169 SkSourceGammaTreatment gamm aTreatment) const { | 180 SkSourceGammaTreatment gamm aTreatment) const { |
170 | 181 |
171 sk_sp<GrFragmentProcessor> mapFP = fMapShader->asFragmentProcessor(context, viewM, | 182 sk_sp<GrFragmentProcessor> mapFP = fMapShader->asFragmentProcessor(context, viewM, |
172 localMatrix, filterQuality, gammaTreatment); | 183 localMatrix, filterQuality, gammaTreatment); |
173 | 184 |
174 return sk_make_sp<NormalMapFP>(std::move(mapFP), fNormRotation); | 185 return sk_make_sp<NormalMapFP>(std::move(mapFP), fInvCTM); |
175 } | 186 } |
176 | 187 |
177 #endif // SK_SUPPORT_GPU | 188 #endif // SK_SUPPORT_GPU |
178 | 189 |
179 //////////////////////////////////////////////////////////////////////////// | 190 //////////////////////////////////////////////////////////////////////////// |
180 | 191 |
181 NormalMapSourceImpl::Provider::Provider(const NormalMapSourceImpl& source, | 192 NormalMapSourceImpl::Provider::Provider(const NormalMapSourceImpl& source, |
182 SkShader::Context* mapContext) | 193 SkShader::Context* mapContext) |
183 : fSource(source) | 194 : fSource(source) |
184 , fMapContext(mapContext) { | 195 , fMapContext(mapContext) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
231 | 242 |
232 fMapContext->shadeSpan(x, y, tmpNormalColors, n); | 243 fMapContext->shadeSpan(x, y, tmpNormalColors, n); |
233 | 244 |
234 for (int i = 0; i < n; i++) { | 245 for (int i = 0; i < n; i++) { |
235 SkPoint3 tempNorm; | 246 SkPoint3 tempNorm; |
236 | 247 |
237 tempNorm.set(SkIntToScalar(SkGetPackedR32(tmpNormalColors[i])) - 127 .0f, | 248 tempNorm.set(SkIntToScalar(SkGetPackedR32(tmpNormalColors[i])) - 127 .0f, |
238 SkIntToScalar(SkGetPackedG32(tmpNormalColors[i])) - 127 .0f, | 249 SkIntToScalar(SkGetPackedG32(tmpNormalColors[i])) - 127 .0f, |
239 SkIntToScalar(SkGetPackedB32(tmpNormalColors[i])) - 127 .0f); | 250 SkIntToScalar(SkGetPackedB32(tmpNormalColors[i])) - 127 .0f); |
240 tempNorm.normalize(); | 251 tempNorm.normalize(); |
241 | 252 |
robertphillips
2016/07/06 16:36:33
There 3 overlength lines here.
dvonbeck
2016/07/06 18:07:48
Done.
| |
242 output[i].fX = fSource.fNormRotation.fX * tempNorm.fX + | 253 if (!SkScalarNearlyEqual(SkScalarAbs(tempNorm.fZ), 1.0f)) { |
243 fSource.fNormRotation.fY * tempNorm.fY; | 254 SkVector transformed = fSource.fInvCTM.mapVector(tempNorm.fX, te mpNorm.fY); |
244 output[i].fY = -fSource.fNormRotation.fY * tempNorm.fX + | 255 |
245 fSource.fNormRotation.fX * tempNorm.fY; | 256 // Normalizing the transformed X and Y, while keeping constant b oth Z and the vector's |
246 output[i].fZ = tempNorm.fZ; | 257 // angle in the XY plane. This maintains the "slope" for the sur face while appropriately |
258 // rotating the normal for any anisotropic scaling that occurs. | |
259 // Here, we call scaling factor the number that must divide the transformed X and Y so | |
260 // that the normal's length remains equal to 1. | |
261 SkScalar scalingFactorSquared = | |
262 (SkScalarSquare(transformed.fX) + SkScalarSquare(transfo rmed.fY)) | |
263 / (1.0f - SkScalarSquare(tempNorm.fZ)); | |
264 SkScalar invScalingFactor = SkScalarInvert(SkScalarSqrt(scalingF actorSquared)); | |
265 | |
266 output[i].fX = transformed.fX * invScalingFactor; | |
267 output[i].fY = transformed.fY * invScalingFactor; | |
268 output[i].fZ = tempNorm.fZ; | |
269 } else { | |
robertphillips
2016/07/06 16:36:34
Might as well just set this to (0, 0, 1) and skip
dvonbeck
2016/07/06 18:07:48
Needs to handle (0, 0, -1) as well. I could set it
robertphillips
2016/07/06 19:11:14
Nope, just leave it as is.
| |
270 output[i] = {0.0f, 0.0f, tempNorm.fZ}; | |
271 output[i].normalize(); | |
272 } | |
273 | |
274 SkASSERT(SkScalarNearlyEqual(output[i].length(), 1.0f)) | |
247 } | 275 } |
248 | 276 |
249 output += n; | 277 output += n; |
250 x += n; | 278 x += n; |
251 count -= n; | 279 count -= n; |
252 } while (count > 0); | 280 } while (count > 0); |
253 } | 281 } |
254 | 282 |
255 //////////////////////////////////////////////////////////////////////////////// | 283 //////////////////////////////////////////////////////////////////////////////// |
256 | 284 |
257 sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) { | 285 sk_sp<SkFlattenable> NormalMapSourceImpl::CreateProc(SkReadBuffer& buf) { |
258 | 286 |
259 sk_sp<SkShader> mapShader = buf.readFlattenable<SkShader>(); | 287 sk_sp<SkShader> mapShader = buf.readFlattenable<SkShader>(); |
260 | 288 |
261 SkVector normRotation = {1,0}; | 289 SkMatrix invCTM; |
262 if (!buf.isVersionLT(SkReadBuffer::kLightingShaderWritesInvNormRotation)) { | 290 buf.readMatrix(&invCTM); |
263 normRotation = buf.readPoint(); | |
264 } | |
265 | 291 |
266 return sk_make_sp<NormalMapSourceImpl>(std::move(mapShader), normRotation); | 292 return sk_make_sp<NormalMapSourceImpl>(std::move(mapShader), invCTM); |
267 } | 293 } |
268 | 294 |
269 void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const { | 295 void NormalMapSourceImpl::flatten(SkWriteBuffer& buf) const { |
270 this->INHERITED::flatten(buf); | 296 this->INHERITED::flatten(buf); |
271 | 297 |
272 buf.writeFlattenable(fMapShader.get()); | 298 buf.writeFlattenable(fMapShader.get()); |
273 buf.writePoint(fNormRotation); | 299 buf.writeMatrix(fInvCTM); |
274 } | 300 } |
275 | 301 |
276 //////////////////////////////////////////////////////////////////////////// | 302 //////////////////////////////////////////////////////////////////////////// |
277 | 303 |
278 sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map, | 304 sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map, con st SkMatrix& ctm) { |
279 const SkVector &normRota tion) { | 305 SkMatrix invCTM; |
280 SkASSERT(SkScalarNearlyEqual(normRotation.lengthSqd(), SK_Scalar1)); | 306 |
281 if (!map) { | 307 if (!ctm.invert(&invCTM) || !map) { |
282 return nullptr; | 308 return nullptr; |
283 } | 309 } |
284 | 310 |
285 return sk_make_sp<NormalMapSourceImpl>(std::move(map), normRotation); | 311 return sk_make_sp<NormalMapSourceImpl>(std::move(map), invCTM); |
286 } | 312 } |
287 | 313 |
288 //////////////////////////////////////////////////////////////////////////// | 314 //////////////////////////////////////////////////////////////////////////// |
289 | 315 |
290 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkNormalSource) | 316 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkNormalSource) |
291 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl) | 317 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(NormalMapSourceImpl) |
292 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 318 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
293 | 319 |
294 //////////////////////////////////////////////////////////////////////////// | 320 //////////////////////////////////////////////////////////////////////////// |
OLD | NEW |