zoukankan      html  css  js  c++  java
  • 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 ///

  • 相关阅读:
    使用docker部署微服务
    配置git仓库SSH秘钥,实现免密登录
    windows添加打印机失败
    流媒体之HLS与DASH
    docker安装mysql8.0
    去它的不要找客观原因
    idea提交代码到gitee报错:The requested URL returned error: 403
    使用docker compose微服务编排
    docker安装redis
    OpenGL环境安装
  • 原文地址:https://www.cnblogs.com/corefans/p/1515866.html
Copyright © 2011-2022 走看看