Torque3D Documentation / _generateds / advancedLightingFeaturesGLSL.cpp

advancedLightingFeaturesGLSL.cpp

Engine/source/lighting/advanced/glsl/advancedLightingFeaturesGLSL.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "lighting/advanced/glsl/advancedLightingFeaturesGLSL.h"
 26
 27#include "lighting/advanced/advancedLightBinManager.h"
 28#include "shaderGen/langElement.h"
 29#include "shaderGen/shaderOp.h"
 30#include "shaderGen/conditionerFeature.h"
 31#include "renderInstance/renderDeferredMgr.h"
 32#include "materials/processedMaterial.h"
 33#include "materials/materialFeatureTypes.h"
 34
 35
 36void DeferredRTLightingFeatGLSL::processPixMacros( Vector<GFXShaderMacro> &macros, 
 37                                                   const MaterialFeatureData &fd  )
 38{
 39   // Skip deferred features, and use forward shading instead
 40   if ( !fd.features[MFT_isDeferred] )
 41   {
 42      Parent::processPixMacros( macros, fd );
 43      return;
 44   }
 45
 46   // Pull in the uncondition method for the light info buffer
 47   NamedTexTarget *texTarget = NamedTexTarget::find( AdvancedLightBinManager::smBufferName );
 48   if ( texTarget && texTarget->getConditioner() )
 49   {
 50      ConditionerMethodDependency *unconditionMethod = texTarget->getConditioner()->getConditionerMethodDependency(ConditionerFeature::UnconditionMethod);
 51      unconditionMethod->createMethodMacro( String::ToLower( AdvancedLightBinManager::smBufferName ) + "Uncondition", macros );
 52      addDependency(unconditionMethod);
 53   }
 54}
 55
 56void DeferredRTLightingFeatGLSL::processVert(   Vector<ShaderComponent*> &componentList, 
 57                                                const MaterialFeatureData &fd )
 58{
 59   // Skip deferred features, and use forward shading instead
 60   if ( !fd.features[MFT_isDeferred] )
 61   {
 62      Parent::processVert( componentList, fd );
 63      return;
 64   }
 65
 66   // Pass screen space position to pixel shader to compute a full screen buffer uv
 67   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 68   Var *ssPos = connectComp->getElement( RT_TEXCOORD );
 69   ssPos->setName( "screenspacePos" );
 70   ssPos->setStructName( "OUT" );
 71   ssPos->setType( "vec4" );
 72
 73   Var *outPosition = (Var*) LangElement::find( "gl_Position" );
 74   AssertFatal( outPosition, "No gl_Position, ohnoes." );
 75
 76   output = new GenOp( "   @ = @;\r\n", ssPos, outPosition );
 77}
 78
 79void DeferredRTLightingFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
 80                                             const MaterialFeatureData &fd )
 81{
 82   // Skip deferred features, and use forward shading instead
 83   if ( !fd.features[MFT_isDeferred] )
 84   {
 85      Parent::processPix( componentList, fd );
 86      return;
 87   }
 88
 89   MultiLine *meta = new MultiLine;
 90
 91   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 92   Var *ssPos = connectComp->getElement( RT_TEXCOORD );
 93   ssPos->setName( "screenspacePos" );
 94   ssPos->setStructName( "IN" );
 95   ssPos->setType( "vec4" );
 96
 97   Var *uvScene = new Var;
 98   uvScene->setType( "vec2" );
 99   uvScene->setName( "uvScene" );
100   LangElement *uvSceneDecl = new DecOp( uvScene );
101
102   String rtParamName = String::ToString( "rtParams%s", "diffuseLightingBuffer" );
103   Var *rtParams = (Var*) LangElement::find( rtParamName );
104   if( !rtParams )
105   {
106      rtParams = new Var;
107      rtParams->setType( "vec4" );
108      rtParams->setName( rtParamName );
109      rtParams->uniform = true;
110      rtParams->constSortPos = cspPass;
111   }
112
113   meta->addStatement( new GenOp( "   @ = @.xy / @.w;\r\n", uvSceneDecl, ssPos, ssPos ) ); // get the screen coord... its -1 to +1
114   meta->addStatement( new GenOp( "   @ = ( @ + 1.0 ) / 2.0;\r\n", uvScene, uvScene ) ); // get the screen coord to 0 to 1
115   meta->addStatement( new GenOp( "   @.y = 1.0 - @.y;\r\n", uvScene, uvScene ) ); // flip the y axis 
116   meta->addStatement( new GenOp( "   @ = ( @ * @.zw ) + @.xy;\r\n", uvScene, uvScene, rtParams, rtParams) ); // scale it down and offset it to the rt size
117
118   // create texture var
119   Var *lightInfoBuffer = new Var;
120   lightInfoBuffer->setType( "sampler2D" );
121   lightInfoBuffer->setName( "diffuseLightingBuffer" );
122   lightInfoBuffer->uniform = true;
123   lightInfoBuffer->sampler = true;
124   lightInfoBuffer->constNum = Var::getTexUnitNum();     // used as texture unit num here
125
126   // Declare the RTLighting variables in this feature, they will either be assigned
127   // in this feature, or in the tonemap/lightmap feature
128   Var *d_lightcolor = new Var( "d_lightcolor", "vec3" );
129   meta->addStatement( new GenOp( "   @;\r\n", new DecOp( d_lightcolor ) ) );
130
131   Var *d_NL_Att = new Var( "d_NL_Att", "float" );
132   meta->addStatement( new GenOp( "   @;\r\n", new DecOp( d_NL_Att ) ) );
133
134   Var *d_specular = new Var( "d_specular", "float" );
135   meta->addStatement( new GenOp( "   @;\r\n", new DecOp( d_specular ) ) );
136   
137
138   // Perform the uncondition here.
139   String unconditionLightInfo = String::ToLower( AdvancedLightBinManager::smBufferName ) + "Uncondition";
140   meta->addStatement( new GenOp( avar( "   %s(tex2D(@, @), @, @, @);\r\n", 
141      unconditionLightInfo.c_str() ), lightInfoBuffer, uvScene, d_lightcolor, d_NL_Att, d_specular ) );
142   
143   // This is kind of weak sauce
144   if( !fd.features[MFT_VertLit] && !fd.features[MFT_ToneMap] && !fd.features[MFT_LightMap] && !fd.features[MFT_SubSurface] )
145      meta->addStatement( new GenOp( "   @;\r\n", assignColor( new GenOp( "vec4(@, 1.0)", d_lightcolor ), Material::Mul ) ) );
146
147   output = meta;
148}
149
150ShaderFeature::Resources DeferredRTLightingFeatGLSL::getResources( const MaterialFeatureData &fd )
151{
152   // Skip deferred features, and use forward shading instead
153   if ( !fd.features[MFT_isDeferred] )
154      return Parent::getResources( fd );
155
156   // HACK: See DeferredRTLightingFeatGLSL::setTexData.
157   mLastTexIndex = 0;
158
159   Resources res; 
160   res.numTex = 1;
161   res.numTexReg = 1;
162   return res;
163}
164
165void DeferredRTLightingFeatGLSL::setTexData( Material::StageData &stageDat,
166                                             const MaterialFeatureData &fd, 
167                                             RenderPassData &passData, 
168                                             U32 &texIndex )
169{
170   // Skip deferred features, and use forward shading instead
171   if ( !fd.features[MFT_isDeferred] )
172   {
173      Parent::setTexData( stageDat, fd, passData, texIndex );
174      return;
175   }
176
177   NamedTexTarget *texTarget = NamedTexTarget::find( AdvancedLightBinManager::smBufferName );
178   if( texTarget )
179   {
180      // HACK: We store this for use in DeferredRTLightingFeatGLSL::processPix()
181      // which cannot deduce the texture unit itself.
182      mLastTexIndex = texIndex;
183
184      passData.mTexType[ texIndex ] = Material::TexTarget;      
185      passData.mSamplerNames[ texIndex ]= "diffuseLightingBuffer";
186      passData.mTexSlot[ texIndex++ ].texTarget = texTarget;
187   }
188}
189
190
191void DeferredBumpFeatGLSL::processVert(   Vector<ShaderComponent*> &componentList, 
192                                          const MaterialFeatureData &fd )
193{
194   if( fd.features[MFT_DeferredConditioner] )
195   {
196      // There is an output conditioner active, so we need to supply a transform
197      // to the pixel shader. 
198      MultiLine *meta = new MultiLine;
199
200      // We need the view to tangent space transform in the pixel shader.
201      getOutViewToTangent( componentList, meta, fd );
202
203      const bool useTexAnim = fd.features[MFT_TexAnim];
204      // Make sure there are texcoords
205      if( !fd.features[MFT_Parallax] && !fd.features[MFT_DiffuseMap])
206      {
207
208         getOutTexCoord(   "texCoord", 
209                           "vec2", 
210                           useTexAnim, 
211                           meta, 
212                           componentList );
213      }
214
215      const bool useFoliageTexCoord = fd.features[MFT_Foliage];
216
217      if ( fd.features.hasFeature( MFT_DetailNormalMap ) )
218            addOutDetailTexCoord( componentList, 
219                                  meta,
220                                  useTexAnim, useFoliageTexCoord);
221
222      output = meta;
223   }
224   else if (   fd.materialFeatures[MFT_NormalsOut] || 
225               !fd.features[MFT_isDeferred] || 
226               !fd.features[MFT_RTLighting] )
227   {
228      Parent::processVert( componentList, fd );
229      return;
230   }
231   else
232   {
233      output = NULL;
234   }
235}
236
237void DeferredBumpFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 
238                                       const MaterialFeatureData &fd )
239{
240   // NULL output in case nothing gets handled
241   output = NULL;
242
243   if( fd.features[MFT_DeferredConditioner] )
244   {
245      MultiLine *meta = new MultiLine;
246
247      Var *viewToTangent = getInViewToTangent( componentList );
248
249      // create texture var
250      Var *bumpMap = getNormalMapTex();
251      Var *texCoord = getInTexCoord( "texCoord", "vec2", componentList );
252      LangElement *texOp = new GenOp( "tex2D(@, @)", bumpMap, texCoord );
253
254      // create bump normal
255      Var *bumpNorm = new Var;
256      bumpNorm->setName( "bumpNormal" );
257      bumpNorm->setType( "vec4" );
258
259      LangElement *bumpNormDecl = new DecOp( bumpNorm );
260      meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) );
261
262      // If we have a detail normal map we add the xy coords of
263      // it to the base normal map.  This gives us the effect we
264      // want with few instructions and minial artifacts.
265      if ( fd.features.hasFeature( MFT_DetailNormalMap ) )
266      {
267         bumpMap = new Var;
268         bumpMap->setType( "sampler2D" );
269         bumpMap->setName( "detailBumpMap" );
270         bumpMap->uniform = true;
271         bumpMap->sampler = true;
272         bumpMap->constNum = Var::getTexUnitNum();
273
274         texCoord = getInTexCoord( "detCoord", "vec2", componentList );
275         texOp = new GenOp( "tex2D(@, @)", bumpMap, texCoord );
276
277         Var *detailBump = new Var;
278         detailBump->setName( "detailBump" );
279         detailBump->setType( "vec4" );
280         meta->addStatement( expandNormalMap( texOp, new DecOp( detailBump ), detailBump, fd ) );
281
282         Var *detailBumpScale = new Var;
283         detailBumpScale->setType( "float" );
284         detailBumpScale->setName( "detailBumpStrength" );
285         detailBumpScale->uniform = true;
286         detailBumpScale->constSortPos = cspPass;
287         meta->addStatement( new GenOp( "   @.xy += @.xy * @;\r\n", bumpNorm, detailBump, detailBumpScale ) );
288      }
289
290      // This var is read from GBufferConditionerGLSL and 
291      // used in the deferred output.
292      //
293      // By using the 'half' type here we get a bunch of partial
294      // precision optimized code on further operations on the normal
295      // which helps alot on older Geforce cards.
296      //
297      Var *gbNormal = new Var;
298      gbNormal->setName( "gbNormal" );
299      gbNormal->setType( "half3" );
300      LangElement *gbNormalDecl = new DecOp( gbNormal );
301
302      // Normalize is done later... 
303      // Note: The reverse mul order is intentional. Affine matrix.
304      meta->addStatement( new GenOp( "   @ = half3(tMul( @.xyz, @ ));\r\n", gbNormalDecl, bumpNorm, viewToTangent ) );
305
306      output = meta;
307      return;
308   }
309
310   else if (fd.features[MFT_AccuMap])
311   {
312      Var *bumpSample = (Var *)LangElement::find("bumpSample");
313      if (bumpSample == NULL)
314      {
315         MultiLine *meta = new MultiLine;
316
317         Var *texCoord = getInTexCoord("texCoord", "vec2", componentList);
318
319         Var *bumpMap = getNormalMapTex();
320
321         bumpSample = new Var;
322         bumpSample->setType("vec4");
323         bumpSample->setName("bumpSample");
324         LangElement *bumpSampleDecl = new DecOp(bumpSample);
325
326         meta->addStatement(new GenOp("   @ = tex2D(@, @);\r\n", bumpSampleDecl, bumpMap, texCoord));
327
328         if (fd.features.hasFeature(MFT_DetailNormalMap))
329         {
330            bumpMap = (Var*)LangElement::find("detailBumpMap");
331            if (!bumpMap) {
332               bumpMap = new Var;
333               bumpMap->setType("sampler2D");
334               bumpMap->setName("detailBumpMap");
335               bumpMap->uniform = true;
336               bumpMap->sampler = true;
337               bumpMap->constNum = Var::getTexUnitNum();
338            }
339
340            texCoord = getInTexCoord("detCoord", "vec2", componentList);
341            LangElement *texOp = new GenOp("tex2D(@, @)", bumpMap, texCoord);
342
343            Var *detailBump = new Var;
344            detailBump->setName("detailBump");
345            detailBump->setType("vec4");
346            meta->addStatement(expandNormalMap(texOp, new DecOp(detailBump), detailBump, fd));
347
348            Var *detailBumpScale = new Var;
349            detailBumpScale->setType("float");
350            detailBumpScale->setName("detailBumpStrength");
351            detailBumpScale->uniform = true;
352            detailBumpScale->constSortPos = cspPass;
353            meta->addStatement(new GenOp("   @.xy += @.xy * @;\r\n", bumpSample, detailBump, detailBumpScale));
354         }
355
356         output = meta;
357
358         return;
359      }
360   }
361   else if (   fd.materialFeatures[MFT_NormalsOut] || 
362               !fd.features[MFT_isDeferred] || 
363               !fd.features[MFT_RTLighting] )
364   {
365      Parent::processPix( componentList, fd );
366      return;
367   }
368   else if (!fd.features[MFT_OrmMap] )
369   {
370      Var *bumpSample = (Var *)LangElement::find( "bumpSample" );
371      if( bumpSample == NULL )
372      {
373         Var *texCoord = getInTexCoord( "texCoord", "vec2", componentList );
374
375         Var *bumpMap = getNormalMapTex();
376
377         bumpSample = new Var;
378         bumpSample->setType( "vec4" );
379         bumpSample->setName( "bumpSample" );
380         LangElement *bumpSampleDecl = new DecOp( bumpSample );
381
382         output = new GenOp( "   @ = tex2D(@, @);\r\n", bumpSampleDecl, bumpMap, texCoord );
383         return;
384      }
385   }
386
387   output = NULL;
388}
389
390ShaderFeature::Resources DeferredBumpFeatGLSL::getResources( const MaterialFeatureData &fd )
391{
392   if (  fd.materialFeatures[MFT_NormalsOut] || 
393         !fd.features[MFT_isDeferred] || 
394         fd.features[MFT_Parallax] ||
395         !fd.features[MFT_RTLighting] )
396      return Parent::getResources( fd );
397
398   Resources res; 
399   if(!fd.features[MFT_OrmMap])
400   {
401      res.numTex = 1;
402      res.numTexReg = 1;
403
404      if (  fd.features[MFT_DeferredConditioner] &&
405            fd.features.hasFeature( MFT_DetailNormalMap ) )
406      {
407         res.numTex += 1;
408         if ( !fd.features.hasFeature( MFT_DetailMap ) )
409            res.numTexReg += 1;
410      }
411   }
412
413   return res;
414}
415
416void DeferredBumpFeatGLSL::setTexData( Material::StageData &stageDat,
417                                       const MaterialFeatureData &fd, 
418                                       RenderPassData &passData, 
419                                       U32 &texIndex )
420{
421   if (  fd.materialFeatures[MFT_NormalsOut] || 
422         !fd.features[MFT_isDeferred] || 
423         !fd.features[MFT_RTLighting] )
424   {
425      Parent::setTexData( stageDat, fd, passData, texIndex );
426      return;
427   }
428
429   if (!fd.features[MFT_DeferredConditioner] && fd.features[MFT_AccuMap])
430   {
431      passData.mTexType[texIndex] = Material::Bump;
432      passData.mSamplerNames[texIndex] = "bumpMap";
433      passData.mTexSlot[texIndex++].texObject = stageDat.getTex(MFT_NormalMap);
434
435      if (fd.features.hasFeature(MFT_DetailNormalMap))
436      {
437         passData.mTexType[texIndex] = Material::DetailBump;
438         passData.mSamplerNames[texIndex] = "detailBumpMap";
439         passData.mTexSlot[texIndex++].texObject = stageDat.getTex(MFT_DetailNormalMap);
440      }
441   }
442   else if (!fd.features[MFT_Parallax] && !fd.features[MFT_OrmMap] &&
443         ( fd.features[MFT_DeferredConditioner]) )
444   {
445      passData.mTexType[ texIndex ] = Material::Bump;
446      passData.mSamplerNames[ texIndex ] = "bumpMap";
447      passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_NormalMap );
448
449      if (  fd.features[MFT_DeferredConditioner] &&
450            fd.features.hasFeature( MFT_DetailNormalMap ) )
451      {
452         passData.mTexType[ texIndex ] = Material::DetailBump;
453         passData.mSamplerNames[ texIndex ] = "detailBumpMap";
454         passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_DetailNormalMap );
455      }
456   }
457}
458
459
460ShaderFeature::Resources DeferredMinnaertGLSL::getResources( const MaterialFeatureData &fd )
461{
462   Resources res;
463   if( fd.features[MFT_isDeferred] && fd.features[MFT_RTLighting] )
464   {
465      res.numTex = 1;
466      res.numTexReg = 1;
467   }
468   return res;
469}
470
471void DeferredMinnaertGLSL::setTexData( Material::StageData &stageDat,
472                                       const MaterialFeatureData &fd, 
473                                       RenderPassData &passData, 
474                                       U32 &texIndex )
475{
476   if( fd.features[MFT_isDeferred] && fd.features[MFT_RTLighting] )
477   {
478      NamedTexTarget *texTarget = NamedTexTarget::find(RenderDeferredMgr::BufferName);
479      if ( texTarget )
480      {
481         passData.mTexType[texIndex] = Material::TexTarget;
482         passData.mSamplerNames[texIndex] = "deferredBuffer";
483         passData.mTexSlot[ texIndex++ ].texTarget = texTarget;
484      }
485   }
486}
487
488void DeferredMinnaertGLSL::processPixMacros( Vector<GFXShaderMacro> &macros, 
489                                             const MaterialFeatureData &fd  )
490{
491   if( fd.features[MFT_isDeferred] && fd.features[MFT_RTLighting] )
492   {
493      // Pull in the uncondition method for the g buffer
494      NamedTexTarget *texTarget = NamedTexTarget::find( RenderDeferredMgr::BufferName );
495      if ( texTarget && texTarget->getConditioner() )
496      {
497         ConditionerMethodDependency *unconditionMethod = texTarget->getConditioner()->getConditionerMethodDependency(ConditionerFeature::UnconditionMethod);
498         unconditionMethod->createMethodMacro( String::ToLower(RenderDeferredMgr::BufferName) + "Uncondition", macros );
499         addDependency(unconditionMethod);
500      }
501   }
502}
503
504void DeferredMinnaertGLSL::processVert(   Vector<ShaderComponent*> &componentList,
505                                          const MaterialFeatureData &fd )
506{
507   // If there is no deferred information, bail on this feature
508   if( !fd.features[MFT_isDeferred] || !fd.features[MFT_RTLighting] )
509   {
510      output = NULL;
511      return;
512   }
513
514   // Make sure we pass the world space position to the
515   // pixel shader so we can calculate a view vector.
516   MultiLine *meta = new MultiLine;
517   addOutWsPosition( componentList, fd.features[MFT_UseInstancing], meta );
518   output = meta;
519}
520
521void DeferredMinnaertGLSL::processPix( Vector<ShaderComponent*> &componentList, 
522                                       const MaterialFeatureData &fd )
523{
524   // If there is no deferred information, bail on this feature
525   if( !fd.features[MFT_isDeferred] || !fd.features[MFT_RTLighting] )
526   {
527      output = NULL;
528      return;
529   }
530
531   Var *minnaertConstant = new Var;
532   minnaertConstant->setType( "float" );
533   minnaertConstant->setName( "minnaertConstant" );
534   minnaertConstant->uniform = true;
535   minnaertConstant->constSortPos = cspPotentialPrimitive;
536
537   // create texture var
538   Var *deferredBuffer = new Var;
539   deferredBuffer->setType( "sampler2D" );
540   deferredBuffer->setName( "deferredBuffer" );
541   deferredBuffer->uniform = true;
542   deferredBuffer->sampler = true;
543   deferredBuffer->constNum = Var::getTexUnitNum();     // used as texture unit num here
544
545   // Texture coord
546   Var *uvScene = (Var*) LangElement::find( "uvScene" );
547   AssertFatal(uvScene != NULL, "Unable to find UVScene, no RTLighting feature?");
548
549   MultiLine *meta = new MultiLine;
550
551   // Get the world space view vector.
552   Var *wsViewVec = getWsView( getInWsPosition( componentList ), meta );
553
554   String unconditionDeferredMethod = String::ToLower(RenderDeferredMgr::BufferName) + "Uncondition";
555
556   Var *d_NL_Att = (Var*)LangElement::find( "d_NL_Att" );
557
558   meta->addStatement( new GenOp( avar( "   vec4 normalDepth = %s(@, @);\r\n", unconditionDeferredMethod.c_str() ), deferredBuffer, uvScene ) );
559   meta->addStatement( new GenOp( "   float vDotN = dot(normalDepth.xyz, @);\r\n", wsViewVec ) );
560   meta->addStatement( new GenOp( "   float Minnaert = pow( @, @) * pow(vDotN, 1.0 - @);\r\n", d_NL_Att, minnaertConstant, minnaertConstant ) );
561   meta->addStatement( new GenOp( "   @;\r\n", assignColor( new GenOp( "vec4(Minnaert, Minnaert, Minnaert, 1.0)" ), Material::Mul ) ) );
562
563   output = meta;
564}
565
566
567void DeferredSubSurfaceGLSL::processPix(  Vector<ShaderComponent*> &componentList, 
568                                          const MaterialFeatureData &fd )
569{
570
571   Var *subSurfaceParams = new Var;
572   subSurfaceParams->setType( "vec4" );
573   subSurfaceParams->setName( "subSurfaceParams" );
574   subSurfaceParams->uniform = true;
575   subSurfaceParams->constSortPos = cspPotentialPrimitive;
576
577   Var *d_lightcolor = (Var*)LangElement::find( "d_lightcolor" );
578   Var *d_NL_Att = (Var*)LangElement::find( "d_NL_Att" );
579
580   MultiLine *meta = new MultiLine;
581   Var* targ = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::DefaultTarget));
582   if (fd.features[MFT_isDeferred])
583   {
584      targ = (Var*)LangElement::find(getOutputTargetVarName(ShaderFeature::RenderTarget3));
585      meta->addStatement(new GenOp("   @.rgb += @.rgb*@.a;\r\n", targ, subSurfaceParams, subSurfaceParams));
586      output = meta;
587      return;
588   }
589
590   output = meta;
591}
592