crysis shader系统简单分析

crysis的shader都在Shaders.pak中,把shaders.pak改成shaders.zip解压即可看到所有的shader,除了一些扩展,语法基本上

和hlsl差不了太多.

 


主要的宏定义:
%_LT_LIGHTS //灯光数量
%DYN_BRANCHING  //是否使用动态分支(当%DYN_BRANCHING有效时,通过LightsNum_DB来控制灯光数量而不再使用%_LT_LIGHTS)
%_LT_0_TYPE %_LT_1_TYPE %_LT_2_TYPE %_LT_3_TYPE //分别定义每个灯光的类型
%_RT_FOG
%_RT_ALPHABLEND
%BUMP_MAP
...

也就是说crysis要为每个shader根据宏的不同定义来生成若干个版本,游戏目录中的ShaderCache.pak保存了预先生成好的若干shader。
对于shader 3.0及以上的显卡,通过常量寄存器+static branch来取代宏的方式似乎更加简洁.

RunTime.ext和相关的.ext中定义了对于每个宏应该precache哪些shader

一,fragLib.cfi
fragLib.cfi定义了公用的一些shader函数以及要在每个具体的shader文件中中实现的shader函数原型

通用shader函数原型有主要有:
frag_unify_parameters( inout fragPass pPass ) //每个shader实现根据需求控制使用哪些shader特性
frag_custom_begin(in vert2FragGeneral IN, inout fragCustomPass pPass) 
frag_custom_per_light(in fragCustomPass pPass, inout fragLightPass pLight) //每个shader实现每个灯光的光照算法
...

通用shader函数:
//-----------------------------------------
void frag_unify(inout fragPass pPass, in vert2FragGeneral IN)
{
 ...
 //初始化shader输入参数及一些特性开关,在具体的shader文件中实现
        //////////////////////////////////////////////////////////
 frag_unify_parameters( pPass );
        //////////////////////////////////////////////////////////
 ...
}

//-----------------------------------------
half4 frag_shared_output(inout fragPass pPass)
{
 ...
        frag_quality_setup( pPass );
 ...
 // do custom pass setup
        frag_custom_begin(pPass);
 ...
#if %_LT_LIGHTS
#if %DYN_BRANCHING
 float2 tcLI = LightInfoTC_DB.xy;
 float tcIter = LightInfoTC_DB.z;
   float tcIterParam = LightInfoTC_DB.w;

    //这里其实是通过常量LightsNum_DB来使用static branch,并不是DYANCHING
        //ps的static branch只在ps 2.0a及以上才支持,dynamic branch则在ps3.0及以上才支持

   for (int i=0; i<LightsNum_DB; i++, tcLI.x+=tcIter)
#else
   // Light types
   const int aLType[4] = {%_LT_0_TYPE, %_LT_1_TYPE, %_LT_2_TYPE, %_LT_3_TYPE};       
 #ifdef D3D10
   [unroll]
 #endif
   for (int i=0; i<%_LT_NUM; i++)
#endif
   {   
      float4 WorldLightPos;
#if %DYN_BRANCHING
      // We can't index constants in cycle, so get light/shadow info from the texture
      WorldLightPos = tex2Dlod(LightInfoSampler_DB, float4(tcLI, 0, 0));
      half4 Diffuse = tex2Dlod(LightInfoSampler_DB, float4(tcLI.x+tcIterParam, tcLI.y, 0, 0));
      half4 Specular = Diffuse;
      Specular.xyz *= Diffuse.w;
      half4 ShadowChanMask = tex2Dlod(LightInfoSampler_DB, float4(tcLI.x+tcIterParam*3, tcLI.y, 0, 0));
      float nType = tex2Dlod(LightInfoSampler_DB, float4(tcLI.x+tcIterParam*2, tcLI.y, 0, 0)).w;
#else
      int nType = aLType[i];                             
      WorldLightPos = LGetPosition(i);
      half4 Diffuse = LGetDiffuse(i);
      half4 Specular;
  ...   
           half4 ShadowChanMask = LGetShadowMask(i);   

      // Some optimisations for sun light (per-frame parameters and hardcoded values)   
      if (nType == LT_DIRECTIONAL)
      {
         WorldLightPos = g_PS_SunLightDir;
          ShadowChanMask = float4(1,0,0,0);
  }
  ...

      half fFallOff = 1;
  float3 vLight, vLightWS;       
      if (nType == LT_DIRECTIONAL)
      {     
         vLightWS = WorldLightPos.xyz * 10000.0f;
        vLight = WorldLightPos.xyz;
      }
      else
      {
         vLightWS = WorldLightPos.xyz - pPass.IN.vView.xyz;     
         vLight = normalize(vLightWS.xyz);                                                         // 3 alu
         fFallOff = GetAttenuation(vLightWS.xyz, WorldLightPos.w);                                   // 2 alu
      }
 
#endif
  //计算每个灯光的光照,在具体的shader文件中实现
         //////////////////////////////////////////////////////////
           frag_custom_per_light(pPass, pLight);
         //////////////////////////////////////////////////////////
         ...
        } 
 ...
}

//-----------------------------------------------------------------------------------
/**
*/
二,具体的shader实现
如HumanSkin.cfx

void frag_unify_parameters( inout fragPass pPass )
{
  //这些变量编译后是用作常量呢还是临时变量?推测应该是使用临时变量
  pPass.bRenormalizeNormal = true;
 
#if %BUMP_DIFFUSE 
  pPass.bDiffuseBump = true;
#endif

}

//灯光类型在frag_shared_output已经处理了,好象只支持point light和direct light?
void frag_custom_per_light(inout fragPass pPass, inout fragLightPass pLight)
{   
  if (pPass.bDiffuseBump )
  {
    pLight.fNdotL = dot(pPass.vNormalDiffuse.xyz, pLight.vLight.xyz);             
  }
  ... 
  if( pPass.nQuality == QUALITY_HIGH )
  {
    cDiffuse = saturate( lerp( cSubSurface.xyz*(pLight.fOcclShadow*0.5+0.5), pLight.fOcclShadow * lerp(pLight.fNdotL, 1, DiffusionAmount), fWrappedNdotL) );  
  }
  else
  {
    cDiffuse = fWrappedNdotL * pLight.fOcclShadow;
  }
  ...
}

////////////////////////////////////////////////////////
//注意:frag_unify_parameters等函数在上面已经被重定义
#include "fragLib.cfi"
////////////////////////////////////////////////////////
///////////////// pixel shader //////////////////

pixout SkinPS(vert2FragGeneral IN)
{
  pixout OUT = (pixout) 0; 
   
  // Initialize fragPass structure
  fragPass pPass = (fragPass) 0;

 //////////////////////////////////////////////////
  //在fragLib.cfi中定义!
  frag_unify(pPass, IN); 
 //////////////////////////////////////////////////

 //////////////////////////////////////////////////
  //frag_shared_output在fragLib.cfi中定义!
  half4 cFinal = frag_shared_output(pPass);
 //////////////////////////////////////////////////         


  HDROutput(OUT, cFinal, 1);
 
  return OUT; 
}
 
//////////////////////////////// techniques ////////////////

technique General
<
  string Script =
        "TechniqueZ=ZPass;"
        "TechniqueMotionBlur=MotionBlurPass;"
        //"TechniqueDetail=DetailPass;"       
        "TechniqueCaustics=CausticsPass;"
#ifndef %DISABLE_RAIN_PASS
        "TechniqueRainPass=RainPass;"
#endif
        "TechniqueCustomRender=CustomRenderPass;"
        "TechniqueShadowGen=ShadowGen;"
#ifdef D3D10
        "TechniqueShadowGenDX10=ShadowGenGS;"
#endif
        "TechniqueShadowPass=ShadowPass;"       
>
{
  pass p0
  {
    VertexShader = compile vs_Auto SkinVS() GeneralVS;
    PixelShader = compile ps_Auto SkinPS() GeneralPS;
   
    ZEnable = true;
    ZWriteEnable = true;   
    CullMode = Back;
  }    
}

//////////////////////////////// Common techniques ////////////////

#include "CommonZPass.cfi"
//include "CommonDetailPass.cfi"
#include "CommonCausticsPass.cfi"
#include "CommonMotionBlurPass.cfi"
#include "CommonViewsPass.cfi"
#ifndef %DISABLE_RAIN_PASS
 #include "CommonRainPass.cfi"
#endif
#include "ShadowCommon.cfi"
#include "CommonShadowGenPass.cfi"
#ifdef D3D10
#include "CommonShadowGenPassGS.cfi"
#endif
#include "CommonShadowPass.cfi"


/////////////////////// eof ///

 

 

 

posted on 2009-07-02 22:25  chunlin  阅读(1337)  评论(1编辑  收藏  举报

导航