bumpHLSL.cpp

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