大佬们觉得表面着色器比传统着色器好用吗

想尝试看懂表面着色器代码,虽然effect里的vs和fs写的简单,就几行include,但里面的嵌套也太深了,include的几个文件里又是include,有四五层,是不是函数功能分得有点太细了?

菜鸟实在是疑惑,表面着色器这么复杂的结构,大佬们真的能融会贯通全盘掌握吗?因为我看很多大佬分享的shader教程也还在用传统着色器。

我自己用起来也感觉传统着色器用着更顺手,渲染算法的加减乘除全在一起,一目了然。
菜鸟正入门呢,希望大佬们不吝赐教 :rofl:

本来我就用传统着色器也没啥问题,但是表面着色器和传统着色器版本的toon着色器阴影效果不一样,所以想看懂表面着色器里的算法,在传统着色器里修改实现一下,结果代码实在难看懂。。。下图左边两个立方体用的是表面着色器的toon,右边两个用的是传统着色器的toon。麻烦大佬们有空指导一二,谢谢~
Screenshot 2024-03-11 at 08.52.17

同步一下,用spectorjs查看两种着色器的translated fragment代码(因为原代码里宏定义和include非常多,很难判断哪些代码是有效的,spectorjs里展示的代码肯定是实际运行的代码),从最后的颜色计算部分往前逐一比较,终于发现了计算公式的差异,然后在传统着色器的CCToonShading函数(在legacy/shading-toon文件中)的基础上修改实现了新的shading-toon.chunk,最终实现了相同的阴影效果。

代码如下,注释的代码是原CCToonShading函数中的但现在无用的代码,新增代码有注释说明表面着色器中的来源函数。
只考虑了最简单的场景,没有考虑原代码中各种宏相关的高级渲染需求,仅供参考。

vec4 ToonShading (ToonSurface s) {
  vec3 position;
  HIGHP_VALUE_FROM_STRUCT_DEFINED(position, s.position);
  
  vec3 V = normalize(cc_cameraPos.xyz - position);
  vec3 N = normalize(s.normal);

  vec3 L = normalize(-cc_mainLitDir.xyz);
  float NL = 0.5 * dot(N, L) + 0.5;
  float NH = 0.5 * dot(normalize(V + L), N) + 0.5;
  // vec3 lightColor = cc_mainLitColor.rgb * cc_mainLitColor.w * s.baseStep;

  vec3 diffuse = mix(s.shade1, s.shade2,
    clamp(1.0 + (s.shadeStep - s.shadeFeather - NL) / s.shadeFeather, 0.0, 1.0));

  diffuse = mix(s.baseColor.rgb, diffuse,
    clamp(1.0 + (s.baseStep - s.baseFeather - NL) / s.baseFeather, 0.0, 1.0));

  float specularWeight = 1.0 - pow(s.specular.a, 5.0);
  float specularMask = step(specularWeight + EPSILON_LOWP, NH);
  // vec3 specular = s.specular.rgb * specularMask;

  // vec3 dirlightContrib = diffuse + specular;

  // 表面着色器中没有shadowCover参数,实际效果相当于shadowCover=0.5
  float shadow = 1.0;
  #if CC_RECEIVE_SHADOW && CC_SHADOW_TYPE == CC_SHADOW_MAP
  if(s.shadowCover < NL && cc_mainLitDir.w > 0.0) {
    #if CC_DIR_LIGHT_SHADOW_TYPE == CC_DIR_LIGHT_SHADOW_CASCADED
      shadow = CCCSMFactorBase(position, N, s.shadowBias);
    #endif
    #if CC_DIR_LIGHT_SHADOW_TYPE == CC_DIR_LIGHT_SHADOW_UNIFORM
      shadow = CCShadowFactorBase(CC_SHADOW_POSITION, N, s.shadowBias);
    #endif
  }
  #endif

  // dirlightContrib *= shadow;
  // vec3 finalColor = lightColor * dirlightContrib;
  
  // 以下为新增代码,分两阶段:CCSurfacesLighting和CCSurfacesShading

  // CCSurfacesLighting阶段
  // 设置参数
  vec3 lightmapColor = vec3(0.0);
  // 调用CCSurfacesLightingCalculateColorWithLighting
  vec3 diffuseColorWithLighting = diffuse * s.baseStep;
  // 调用CCSurfacesLightingCalculateDirect
  vec3 irradiance = cc_mainLitColor.xyz * cc_mainLitColor.w;
  vec3 directDiffuse = irradiance;
  vec3 directSpecular = irradiance * specularMask;

  // CCSurfacesShading阶段
  // 设置参数
  float lightmapCoef = 0.0;
  // 设置lightingData.NoL=-1.0f后,调用CCSurfacesLightingCalculateColorWithLighting
  vec3 backDiffuse = mix(s.shade1, s.shade2, 
    clamp(1.0 + (s.shadeStep - s.shadeFeather - 0.0) / s.shadeFeather, 0.0, 1.0));
  backDiffuse = mix(s.shade1, backDiffuse,
    clamp(1.0 + (s.baseStep - s.baseFeather - 0.0) / s.baseFeather, 0.0, 1.0));
  vec3 backLightingDiffuse = backDiffuse * s.baseStep;
  // 计算颜色
  vec3 finalColor = mix(directDiffuse, lightmapColor, lightmapCoef) * 
             mix(backLightingDiffuse, diffuseColorWithLighting, shadow) +
             directSpecular * diffuseColorWithLighting * shadow;

  finalColor += s.emissive;

  return vec4(finalColor, s.baseColor.a);
}
1赞