bumpGLSL.cpp

Engine/source/shaderGen/GLSL/bumpGLSL.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 "shaderGen/GLSL/bumpGLSL.h"
 26
 27#include "shaderGen/shaderOp.h"
 28#include "gfx/gfxDevice.h"
 29#include "materials/matInstance.h"
 30#include "materials/processedMaterial.h"
 31#include "materials/materialFeatureTypes.h"
 32#include "shaderGen/shaderGenVars.h"
 33#include "shaderGen/shaderGen.h"
 34
 35void BumpFeatGLSL::processVert(  Vector<ShaderComponent*> &componentList, 
 36                                 const MaterialFeatureData &fd )
 37{
 38   MultiLine *meta = new MultiLine;
 39   output = meta;
 40   
 41   const bool useTexAnim = fd.features[MFT_TexAnim];
 42
 43   // Output the texture coord.
 44   getOutTexCoord(   "texCoord", 
 45                     "vec2", 
 46                     useTexAnim, 
 47                     meta, 
 48                     componentList );
 49
 50   const bool useFoliageTexCoord = fd.features[MFT_Foliage];
 51
 52   if ( fd.features.hasFeature( MFT_DetailNormalMap ) )
 53      addOutDetailTexCoord( componentList, 
 54                              meta,
 55                              useTexAnim, useFoliageTexCoord);
 56   
 57   // Also output the worldToTanget transform which
 58   // we use to create the world space normal.
 59   getOutWorldToTangent( componentList, meta, fd );
 60}
 61
 62void BumpFeatGLSL::processPix(   Vector<ShaderComponent*> &componentList, 
 63                                 const MaterialFeatureData &fd )
 64{
 65   MultiLine *meta = new MultiLine;
 66   output = meta;
 67
 68   // Get the texture coord.
 69   Var *texCoord = getInTexCoord( "texCoord", "vec2", componentList );
 70
 71   // Sample the bumpmap.
 72   Var *bumpMap = getNormalMapTex();
 73   LangElement *texOp = NULL;
 74   
 75   //Handle atlased textures
 76   // http://www.infinity-universe.com/Infinity/index.php?option=com_content&task=view&id=65&Itemid=47
 77   if(fd.features[MFT_NormalMapAtlas])
 78   {
 79      // This is a big block of code, so put a comment in the shader code
 80      meta->addStatement( new GenOp( "   // Atlased texture coordinate calculation (see BumpFeat*LSL for details)\r\n") );
 81      
 82      Var *atlasedTex = new Var;
 83      atlasedTex->setName("atlasedBumpCoord");
 84      atlasedTex->setType( "vec2" );
 85      LangElement *atDecl = new DecOp(atlasedTex);
 86      
 87      // Parameters of the texture atlas
 88      Var *atParams  = new Var;
 89      atParams->setType( "float4" );
 90      atParams->setName("bumpAtlasParams");
 91      atParams->uniform = true;
 92      atParams->constSortPos = cspPotentialPrimitive;
 93      
 94      // Parameters of the texture (tile) this object is using in the atlas
 95      Var *tileParams  = new Var;
 96      tileParams->setType( "float4" );
 97      tileParams->setName("bumpAtlasTileParams");
 98      tileParams->uniform = true;
 99      tileParams->constSortPos = cspPotentialPrimitive;
100      
101      const bool is_sm3 = (GFX->getPixelShaderVersion() > 2.0f);
102      if(is_sm3)
103      {
104         // Figure out the mip level
105         meta->addStatement( new GenOp( "   float2 _dx_bump = ddx(@ * @.z);\r\n", texCoord, atParams ) );
106         meta->addStatement( new GenOp( "   float2 _dy_bump = ddy(@ * @.z);\r\n", texCoord, atParams ) );
107         meta->addStatement( new GenOp( "   float mipLod_bump = 0.5 * log2(max(dot(_dx_bump, _dx_bump), dot(_dy_bump, _dy_bump)));\r\n"));
108         meta->addStatement( new GenOp( "   mipLod_bump = clamp(mipLod_bump, 0.0, @.w);\r\n", atParams));
109         
110         // And the size of the mip level
111         meta->addStatement(new GenOp("   float mipPixSz_bump = pow(2.0, @.w - mipLod_bump);\r\n", atParams));
112         meta->addStatement( new GenOp( "   float2 mipSz_bump = mipPixSz_bump / @.xy;\r\n", atParams ) );
113      }
114      else
115      {
116         meta->addStatement(new GenOp("   float2 mipSz = float2(1.0, 1.0);\r\n"));
117      }
118      
119      // Tiling mode
120      if( true ) // Wrap
121         meta->addStatement( new GenOp( "   @ = frac(@);\r\n", atDecl, texCoord ) );
122      else       // Clamp
123         meta->addStatement(new GenOp("   @ = saturate(@);\r\n", atDecl, texCoord));
124      
125      // Finally scale/offset, and correct for filtering
126      meta->addStatement( new GenOp( "   @ = @ * ((mipSz_bump * @.xy - 1.0) / mipSz_bump) + 0.5 / mipSz_bump + @.xy * @.xy;\r\n", 
127                                   atlasedTex, atlasedTex, atParams, atParams, tileParams));
128      
129      // Add a newline
130      meta->addStatement(new GenOp( "\r\n"));
131      
132      if(is_sm3)
133      {
134         texOp = new GenOp( "tex2Dlod(@, float4(@, 0.0, mipLod_bump))", bumpMap, texCoord );
135      }
136      else
137      {
138         texOp = new GenOp( "tex2D(@, @)", bumpMap, texCoord );
139      }
140   }
141   else
142   {
143      texOp = new GenOp( "tex2D(@, @)", bumpMap, texCoord );
144   }
145      
146   Var *bumpNorm = new Var( "bumpNormal", "float4" );
147   meta->addStatement( expandNormalMap( texOp, new DecOp( bumpNorm ), bumpNorm, fd ) );
148
149   // If we have a detail normal map we add the xy coords of
150   // it to the base normal map.  This gives us the effect we
151   // want with few instructions and minial artifacts.
152   if ( fd.features.hasFeature( MFT_DetailNormalMap ) )
153   {
154      bumpMap = new Var;
155      bumpMap->setType( "sampler2D" );
156      bumpMap->setName( "detailBumpMap" );
157      bumpMap->uniform = true;
158      bumpMap->sampler = true;
159      bumpMap->constNum = Var::getTexUnitNum();
160      
161      texCoord = getInTexCoord( "detCoord", "vec2", componentList );
162      texOp = new GenOp( "tex2D(@, @)", bumpMap, texCoord );
163      
164      Var *detailBump = new Var;
165      detailBump->setName( "detailBump" );
166      detailBump->setType( "float4" );
167      meta->addStatement( expandNormalMap( texOp, new DecOp( detailBump ), detailBump, fd ) );
168      
169      Var *detailBumpScale = new Var;
170      detailBumpScale->setType( "float" );
171      detailBumpScale->setName( "detailBumpStrength" );
172      detailBumpScale->uniform = true;
173      detailBumpScale->constSortPos = cspPass;
174      meta->addStatement( new GenOp( "   @.xy += @.xy * @;\r\n", bumpNorm, detailBump, detailBumpScale ) );
175   }
176   
177   // We transform it into world space by reversing the 
178   // multiplication by the worldToTanget transform.
179   Var *wsNormal = new Var( "wsNormal", "vec3" );
180   Var *worldToTanget = getInWorldToTangent( componentList );
181   meta->addStatement( new GenOp( "   @ = normalize( tMul( @.xyz, @ ) );\r\n", new DecOp( wsNormal ), bumpNorm, worldToTanget ) );
182}
183
184ShaderFeature::Resources BumpFeatGLSL::getResources( const MaterialFeatureData &fd )
185{
186   Resources res; 
187
188   // If we have no parallax then we bring on the normal tex.
189   if ( !fd.features[MFT_Parallax] )
190      res.numTex = 1;
191
192   // Only the parallax or diffuse map will add texture
193   // coords other than us.
194   if (  !fd.features[MFT_Parallax] &&
195         !fd.features[MFT_DiffuseMap] &&
196         !fd.features[MFT_OverlayMap] &&
197         !fd.features[MFT_DetailMap] )
198      res.numTexReg++;
199
200   // We pass the world to tanget space transform.
201   res.numTexReg += 3;
202
203   // Do we have detail normal mapping?
204   if ( fd.features[MFT_DetailNormalMap] )
205   {
206      res.numTex++;
207      if ( !fd.features[MFT_DetailMap] )
208         res.numTexReg++;
209   }
210      
211   return res;
212}
213
214void BumpFeatGLSL::setTexData(   Material::StageData &stageDat,
215                                 const MaterialFeatureData &fd,
216                                 RenderPassData &passData,
217                                 U32 &texIndex )
218{
219   // If we had a parallax feature then it takes
220   // care of hooking up the normal map texture.
221   if ( fd.features[MFT_Parallax] )
222      return;
223
224   if ( fd.features[MFT_NormalMap] )
225   {
226      passData.mTexType[ texIndex ] = Material::Bump;
227      passData.mSamplerNames[ texIndex ] = "bumpMap";
228      passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_NormalMap );
229   }
230   
231   if ( fd.features[ MFT_DetailNormalMap ] )
232   {
233      passData.mTexType[ texIndex ] = Material::DetailBump;
234      passData.mSamplerNames[ texIndex ] = "detailBumpMap";
235      passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_DetailNormalMap );
236   }
237}
238
239
240ParallaxFeatGLSL::ParallaxFeatGLSL()
241   : mIncludeDep(ShaderGen::smCommonShaderPath + String("/gl/torque.glsl" ))
242{
243   addDependency( &mIncludeDep );
244}
245
246Var* ParallaxFeatGLSL::_getUniformVar( const char *name, const char *type, ConstantSortPosition csp )
247{
248   Var *theVar = (Var*)LangElement::find( name );
249   if ( !theVar )
250   {
251      theVar = new Var;
252      theVar->setType( type );
253      theVar->setName( name );
254      theVar->uniform = true;
255      theVar->constSortPos = csp;
256   }
257   
258   return theVar;
259}
260
261void ParallaxFeatGLSL::processVert( Vector<ShaderComponent*> &componentList, 
262                                   const MaterialFeatureData &fd )
263{
264   AssertFatal( GFX->getPixelShaderVersion() >= 2.0, 
265      "ParallaxFeatGLSL::processVert - We don't support SM 1.x!" );
266   
267   MultiLine *meta = new MultiLine;
268   
269   // Add the texture coords.
270   getOutTexCoord(   "texCoord", 
271                     "vec2", 
272                  fd.features[MFT_TexAnim], 
273                  meta, 
274                  componentList );
275   
276   // Grab the input position.
277   Var *inPos = (Var*)LangElement::find( "inPosition" );
278   if ( !inPos )
279      inPos = (Var*)LangElement::find( "position" );
280   
281   // Get the object space eye position and the 
282   // object to tangent space transform.
283   Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPrimitive );
284   Var *objToTangentSpace = getOutObjToTangentSpace( componentList, meta, fd );
285   
286   // Now send the negative view vector in tangent space to the pixel shader.
287   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
288   Var *outNegViewTS = connectComp->getElement( RT_TEXCOORD );
289   outNegViewTS->setName( "outNegViewTS" );
290   outNegViewTS->setStructName( "OUT" );
291   outNegViewTS->setType( "vec3" );
292   meta->addStatement( new GenOp( "   @ = tMul( @, float3( @.xyz - @ ) );\r\n", 
293      outNegViewTS, objToTangentSpace, inPos, eyePos ) );
294
295   // If we have texture anim matrix the tangent
296   // space view vector may need to be rotated.
297   Var *texMat = (Var*)LangElement::find( "texMat" );
298   if ( texMat )
299   {
300      meta->addStatement( new GenOp( "   @ = tMul(@, float4(@,0)).xyz;\r\n",
301         outNegViewTS, texMat, outNegViewTS ) );
302   }
303   
304   output = meta;
305}
306
307void ParallaxFeatGLSL::processPix(  Vector<ShaderComponent*> &componentList, 
308                                  const MaterialFeatureData &fd )
309{
310   AssertFatal( GFX->getPixelShaderVersion() >= 2.0, 
311      "ParallaxFeatGLSL::processPix - We don't support SM 1.x!" );
312   
313   MultiLine *meta = new MultiLine;
314   
315   // Order matters... get this first!
316   Var *texCoord = getInTexCoord( "texCoord", "vec2", componentList );
317   
318   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
319   
320   // We need the negative tangent space view vector
321   // as in parallax mapping we step towards the camera.
322   Var *negViewTS = (Var*)LangElement::find( "negViewTS" );
323   if ( !negViewTS )
324   {
325      Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" );
326      if ( !inNegViewTS )
327      {
328         inNegViewTS = connectComp->getElement( RT_TEXCOORD );
329         inNegViewTS->setName( "outNegViewTS" );
330         inNegViewTS->setStructName( "IN" );
331         inNegViewTS->setType( "vec3" );
332      }
333      
334      negViewTS = new Var( "negViewTS", "vec3" );
335      meta->addStatement( new GenOp( "   @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) );
336   }
337   
338   // Get the rest of our inputs.
339   Var *parallaxInfo = _getUniformVar( "parallaxInfo", "float", cspPotentialPrimitive );
340   Var *normalMap = getNormalMapTex();
341   
342   // Call the library function to do the rest.
343   if (fd.features.hasFeature(MFT_IsBC3nm, getProcessIndex()))
344   {
345      meta->addStatement(new GenOp("   @.xy += parallaxOffsetDxtnm( @, @.xy, @, @ );\r\n",
346      texCoord, normalMap, texCoord, negViewTS, parallaxInfo));
347   }
348   else
349   {
350      meta->addStatement(new GenOp("   @.xy += parallaxOffset( @, @.xy, @, @ );\r\n",
351      texCoord, normalMap, texCoord, negViewTS, parallaxInfo));
352   }
353   
354   // TODO: Fix second UV maybe?
355   
356   output = meta;
357}
358
359ShaderFeature::Resources ParallaxFeatGLSL::getResources( const MaterialFeatureData &fd )
360{
361   AssertFatal( GFX->getPixelShaderVersion() >= 2.0, 
362      "ParallaxFeatGLSL::getResources - We don't support SM 1.x!" );
363   
364   Resources res;
365   
366   // We add the outViewTS to the outputstructure.
367   res.numTexReg = 1;
368   
369   // If this isn't a deferred then we will be
370   // creating the normal map here.
371   if ( !fd.features.hasFeature( MFT_DeferredConditioner ) )
372      res.numTex = 1;
373   
374   return res;
375}
376
377void ParallaxFeatGLSL::setTexData(  Material::StageData &stageDat,
378                                  const MaterialFeatureData &fd,
379                                  RenderPassData &passData,
380                                  U32 &texIndex )
381{
382   AssertFatal( GFX->getPixelShaderVersion() >= 2.0, 
383      "ParallaxFeatGLSL::setTexData - We don't support SM 1.x!" );
384   
385   GFXTextureObject *tex = stageDat.getTex( MFT_NormalMap );
386   if ( tex )
387   {
388      passData.mSamplerNames[ texIndex ] = "bumpMap";
389      passData.mTexType[ texIndex ] = Material::Bump;
390      passData.mTexSlot[ texIndex++ ].texObject = tex;
391   }
392}
393
394
395void NormalsOutFeatGLSL::processVert(  Vector<ShaderComponent*> &componentList, 
396                                     const MaterialFeatureData &fd )
397{
398   // If we have normal maps then we can count
399   // on it to generate the world space normal.
400   if ( fd.features[MFT_NormalMap] )
401      return;
402   
403   MultiLine *meta = new MultiLine;
404   output = meta;
405   
406   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
407   
408   Var *outNormal = connectComp->getElement( RT_TEXCOORD );
409   outNormal->setName( "wsNormal" );
410   outNormal->setStructName( "OUT" );
411   outNormal->setType( "vec3" );
412   
413   // Find the incoming vertex normal.
414   Var *inNormal = (Var*)LangElement::find( "normal" );   
415   if ( inNormal )
416   {
417      // Transform the normal to world space.
418      Var *objTrans = getObjTrans( componentList, fd.features[MFT_UseInstancing], meta );
419      meta->addStatement( new GenOp( "   @ = tMul( @, normalize( vec4(@, 0.0) ) ).xyz;\r\n", outNormal, objTrans, inNormal ) );
420   }
421   else
422   {
423      // If we don't have a vertex normal... just pass the
424      // camera facing normal to the pixel shader.
425      meta->addStatement( new GenOp( "   @ = float3( 0.0, 0.0, 1.0 );\r\n", outNormal ) );
426   }
427}
428
429void NormalsOutFeatGLSL::processPix(   Vector<ShaderComponent*> &componentList, 
430                                    const MaterialFeatureData &fd )
431{
432   MultiLine *meta = new MultiLine;
433   output = meta;
434   
435   Var *wsNormal = (Var*)LangElement::find( "wsNormal" );
436   if ( !wsNormal )
437   {
438      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
439      wsNormal = connectComp->getElement( RT_TEXCOORD );
440      wsNormal->setName( "wsNormal" );
441      wsNormal->setStructName( "IN" );
442      wsNormal->setType( "vec3" );
443      
444      // If we loaded the normal its our resposibility
445      // to normalize it... the interpolators won't.
446      //
447      // Note we cast to half here to get partial precision
448      // optimized code which is an acceptable loss of
449      // precision for normals and performs much better
450      // on older Geforce cards.
451      //
452      meta->addStatement( new GenOp( "   @ = normalize( half3( @ ) );\r\n", wsNormal, wsNormal ) );      
453   }
454   
455   LangElement *normalOut;
456   Var *outColor = (Var*)LangElement::find( "col" );
457   if ( outColor && !fd.features[MFT_AlphaTest] )
458      normalOut = new GenOp( "float4( ( -@ + 1 ) * 0.5, @.a )", wsNormal, outColor );
459   else
460      normalOut = new GenOp( "float4( ( -@ + 1 ) * 0.5, 1 )", wsNormal );
461   
462   meta->addStatement( new GenOp( "   @;\r\n", 
463                                 assignColor( normalOut, Material::None ) ) );
464}
465