{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/uwa-answer-urp-brdf-formula-difference/",
  "atlas": "https://www.pystone.net/?node=uwa-answer-urp-brdf-formula-difference#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/uwa-answer-urp-brdf-formula-difference.md",
  "context": "https://www.pystone.net/notes/uwa-answer-urp-brdf-formula-difference.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:uwa-answer-urp-brdf-formula-difference",
  "slug": "uwa-answer-urp-brdf-formula-difference",
  "title": "URP的BRDF计算的疑惑，与论文中的公式不一样？",
  "type": "note",
  "visibility": "public",
  "idStability": "rename-stable",
  "author": {
    "name": "石心.Yong"
  },
  "publisher": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "aliases": [],
  "summary": "URP的BRDF计算的疑惑，与论文中的公式不一样？",
  "contentRole": "source",
  "sourceType": "source",
  "sourceMetadata": {
    "author": "石心.Yong"
  },
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "external_source",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "c831b2e4fea93d3987fd8bec169afbd1b67663352de757ca1d800022af3259fa",
  "assets": [
    {
      "reference": "assets/607fdebf6bb31032f97913ba/01.png",
      "url": "/media/e2462ead63c8f7948a3c.png",
      "mediaType": "image/png",
      "contentHash": "e2462ead63c8f7948a3c28f1b5ac609226efb7746732c15e8713f680cfeda71c",
      "byteLength": 33091,
      "width": 672,
      "height": 377
    },
    {
      "reference": "assets/607fdebf6bb31032f97913ba/02.png",
      "url": "/media/d999f6d659a7dd8ae6de.png",
      "mediaType": "image/png",
      "contentHash": "d999f6d659a7dd8ae6de62f4c084126bb419d8d11bb16119116d3623dba4f702",
      "byteLength": 308820,
      "width": 1004,
      "height": 684
    },
    {
      "reference": "assets/607fdebf6bb31032f97913ba/03.png",
      "url": "/media/127b94ebb48cbf77d19f.png",
      "mediaType": "image/png",
      "contentHash": "127b94ebb48cbf77d19f1e061c845c0f49ee09b644c8bc78d4e9628f63cbac6f",
      "byteLength": 312484,
      "width": 1004,
      "height": 663
    },
    {
      "reference": "assets/607fdebf6bb31032f97913ba/04.png",
      "url": "/media/61b63131c32322bf3e20.png",
      "mediaType": "image/png",
      "contentHash": "61b63131c32322bf3e20a47822e3db97b776f407ae3079cfc0ffb407fdedbd44",
      "byteLength": 69382,
      "width": 560,
      "height": 420
    },
    {
      "reference": "assets/607fdebf6bb31032f97913ba/05.png",
      "url": "/media/bcb0b95a61ac0d56af70.png",
      "mediaType": "image/png",
      "contentHash": "bcb0b95a61ac0d56af702f9ff2bc9c7d309f2252a67fe6048314f1020a32be35",
      "byteLength": 65468,
      "width": 560,
      "height": 420
    },
    {
      "reference": "assets/607fdebf6bb31032f97913ba/06.png",
      "url": "/media/3c568ca67b1cf0415d78.png",
      "mediaType": "image/png",
      "contentHash": "3c568ca67b1cf0415d787fe528b3365add73767eed436f08cd1b23b6a025eb21",
      "byteLength": 264250,
      "width": 1154,
      "height": 389
    },
    {
      "reference": "assets/607fdebf6bb31032f97913ba/07.png",
      "url": "/media/da39e0794065b525a9ad.png",
      "mediaType": "image/png",
      "contentHash": "da39e0794065b525a9ad688f3f5b97f122336df14bbdd034c51af149aecad93d",
      "byteLength": 305027,
      "width": 736,
      "height": 393
    }
  ],
  "headings": [
    {
      "depth": 1,
      "text": "URP的BRDF计算的疑惑，与论文中的公式不一样？",
      "anchor": "urp的brdf计算的疑惑与论文中的公式不一样",
      "citation": "https://www.pystone.net/notes/uwa-answer-urp-brdf-formula-difference/#urp%E7%9A%84brdf%E8%AE%A1%E7%AE%97%E7%9A%84%E7%96%91%E6%83%91%E4%B8%8E%E8%AE%BA%E6%96%87%E4%B8%AD%E7%9A%84%E5%85%AC%E5%BC%8F%E4%B8%8D%E4%B8%80%E6%A0%B7"
    },
    {
      "depth": 2,
      "text": "问题",
      "anchor": "问题",
      "citation": "https://www.pystone.net/notes/uwa-answer-urp-brdf-formula-difference/#%E9%97%AE%E9%A2%98"
    },
    {
      "depth": 2,
      "text": "我的回答",
      "anchor": "我的回答",
      "citation": "https://www.pystone.net/notes/uwa-answer-urp-brdf-formula-difference/#%E6%88%91%E7%9A%84%E5%9B%9E%E7%AD%94"
    },
    {
      "depth": 2,
      "text": "来源与关系",
      "anchor": "来源与关系",
      "citation": "https://www.pystone.net/notes/uwa-answer-urp-brdf-formula-difference/#%E6%9D%A5%E6%BA%90%E4%B8%8E%E5%85%B3%E7%B3%BB"
    }
  ],
  "claims": [],
  "outgoing": [
    {
      "id": "note:my-uwa-answers",
      "title": "我的 UWA 问答",
      "url": "https://www.pystone.net/notes/my-uwa-answers/",
      "atlas": "https://www.pystone.net/?node=my-uwa-answers#knowledge-atlas",
      "label": "我的 UWA 问答",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "上位集合：我的 UWA 问答",
      "citation": "https://www.pystone.net/notes/uwa-answer-urp-brdf-formula-difference/#%E6%9D%A5%E6%BA%90%E4%B8%8E%E5%85%B3%E7%B3%BB"
    }
  ],
  "incoming": [
    {
      "id": "note:my-uwa-answers",
      "title": "我的 UWA 问答",
      "url": "https://www.pystone.net/notes/my-uwa-answers/",
      "atlas": "https://www.pystone.net/?node=my-uwa-answers#knowledge-atlas",
      "label": "我的 UWA 问答",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "2021-04-23：URP的BRDF计算的疑惑，与论文中的公式不一样？（终端平台、渲染模块）",
      "citation": "https://www.pystone.net/notes/my-uwa-answers/#2021"
    },
    {
      "id": "note:game-graphics-and-runtime",
      "title": "游戏图形与运行时",
      "url": "https://www.pystone.net/notes/game-graphics-and-runtime/",
      "atlas": "https://www.pystone.net/?node=game-graphics-and-runtime#knowledge-atlas",
      "label": "游戏图形与运行时",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "我的UWA问答中的“2021-04-23 - URP的BRDF计算的疑惑，与论文中的公式不一样？”导航项",
      "citation": "https://www.pystone.net/notes/game-graphics-and-runtime/#%E6%88%91%E7%9A%84uwa%E9%97%AE%E7%AD%94"
    }
  ],
  "contentMarkdown": "# URP的BRDF计算的疑惑，与论文中的公式不一样？\n\n> [!note] 我的 UWA 问答\n> 本文收录我在 UWA 问答发表的公开回答。问题内容归原提问者；回答保留当时语境，技术结论可能受 Unity 版本、平台和项目条件限制。\n\n## 问题\n\n最近在看URP shader的时候发现个问题，不知道是不是我理解的不对\n\n首先贴代码\n\n先是URP的Lighting.hlsl里初始化BRDF的部分\n\n```\ninline void InitializeBRDFData(half3 albedo, half metallic, half3 specular, half smoothness, half alpha, out BRDFData outBRDFData)\n\n{\n\n#ifdef _SPECULAR_SETUP\n\n    half reflectivity = ReflectivitySpecular(specular);\n\n    half oneMinusReflectivity = 1.0 - reflectivity;\n\n    outBRDFData.diffuse = albedo * (half3(1.0h, 1.0h, 1.0h) - specular);\n\n    outBRDFData.specular = specular;\n\n#else\n\n    half oneMinusReflectivity = OneMinusReflectivityMetallic(metallic);\n\n    half reflectivity = 1.0 - oneMinusReflectivity;\n\n    outBRDFData.diffuse = albedo * oneMinusReflectivity;\n\n    outBRDFData.specular = lerp(kDieletricSpec.rgb, albedo, metallic);\n\n#endif\n\n    outBRDFData.grazingTerm = saturate(smoothness + reflectivity);\n\n    outBRDFData.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);\n\n    outBRDFData.roughness = max(PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness), HALF_MIN);\n\n    outBRDFData.roughness2 = outBRDFData.roughness * outBRDFData.roughness;\n\n    outBRDFData.normalizationTerm = outBRDFData.roughness * 4.0h + 2.0h;\n\n    outBRDFData.roughness2MinusOne = outBRDFData.roughness2 - 1.0h;\n\n#ifdef _ALPHAPREMULTIPLY_ON\n\n    outBRDFData.diffuse *= alpha;\n\n    alpha = alpha * oneMinusReflectivity + reflectivity;\n\n#endif\n\n}\n```\n\n按照我的理解\n\noutBRDFData.perceptualRoughness 是我们说的粗糙度\n\noutBRDFData.roughness 是粗糙度的平方\n\noutBRDFData.roughness2 是粗糙度的4次方\n\n再看URP的Lighting.hlsl里计算BRDF的部分\n\n```\n// Based on Minimalist CookTorrance BRDF\n\n// Implementation is slightly different from original derivation: http://www.thetenthplanet.de/archives/255\n\n//\n\n// * NDF [Modified] GGX\n\n// * Modified Kelemen and Szirmay-Kalos for Visibility term\n\n// * Fresnel approximated with 1/LdotH\n\nhalf3 DirectBDRF(BRDFData brdfData, half3 normalWS, half3 lightDirectionWS, half3 viewDirectionWS)\n\n{\n\n#ifndef _SPECULARHIGHLIGHTS_OFF\n\n    float3 halfDir = SafeNormalize(float3(lightDirectionWS) + float3(viewDirectionWS));\n\n    float NoH = saturate(dot(normalWS, halfDir));\n\n    half LoH = saturate(dot(lightDirectionWS, halfDir));\n\n    // GGX Distribution multiplied by combined approximation of Visibility and Fresnel\n\n    // BRDFspec = (D * V * F) / 4.0\n\n    // D = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2\n\n    // V * F = 1.0 / ( LoH^2 * (roughness + 0.5) )\n\n    // See \"Optimizing PBR for Mobile\" from Siggraph 2015 moving mobile graphics course\n\n    // https://community.arm.com/events/1155\n\n    // Final BRDFspec = roughness^2 / ( NoH^2 * (roughness^2 - 1) + 1 )^2 * (LoH^2 * (roughness + 0.5) * 4.0)\n\n    // We further optimize a few light invariant terms\n\n    // brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD.\n\n    float d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001f;\n\n    half LoH2 = LoH * LoH;\n\n    half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);\n\n    // On platforms where half actually means something, the denominator has a risk of overflow\n\n    // clamp below was added specifically to \"fix\" that, but dx compiler (we convert bytecode to metal/gles)\n\n    // sees that specularTerm have only non-negative terms, so it skips max(0,..) in clamp (leaving only min(100,...))\n\n#if defined (SHADER_API_MOBILE) || defined (SHADER_API_SWITCH)\n\n    specularTerm = specularTerm - HALF_MIN;\n\n    specularTerm = clamp(specularTerm, 0.0, 100.0); // Prevent FP16 overflow on mobiles\n\n#endif\n\n    half3 color = specularTerm * brdfData.specular + brdfData.diffuse;\n\n    return color;\n\n#else\n\n    return brdfData.diffuse;\n\n#endif\n\n}\n```\n\n这里最终的公式是BRDFspec = roughness2 / ( NoH2 *(roughness**2 - 1) + 1 )**2* (LoH^2 *(roughness + 0.5)* 4.0)\n\n然后看unity 2015年的论文，也就是代码里写的那个地址https://community.arm.com/events/1155\n\n![BRDF.png](assets/607fdebf6bb31032f97913ba/01.png)\n\n代码里的roughness实际上是图里roughness的平方，为了防止混淆，下面用roughness(c)和roughness(n)来表示\n\nroughness(c)=roughness(n)^2\n\n看到这里我产生了疑问，论文里roughness(n) + 0.5这一步，对应到代码里，应该是roughness(c)^0.5+0.5才对，而URP代码里直接用了roughness(c)+0.5。\n\n我想问下是我理解的不对，还是URP的shader写错了。\n\n- 提问者：金喆\n- 提问时间：2021-04-22 00:13:51\n\n## 我的回答\n\n讲一下不太成熟的看法哈。我这边的结论是：\n\n- 用平方(roughness(n)^2)加0.5是合理的；\n- 用一次方或者是平方差别不大。\n\nSIGGRAPH 报告中最初V*F函数如下：\n\n![image.png](assets/607fdebf6bb31032f97913ba/02.png)\n\n实际使用的V*F函数是对上述函数的一个近似，使用图像相近的函数进行优化：\n\n![image.png](assets/607fdebf6bb31032f97913ba/03.png)\n\n笔者对取一次放和取平方的函数图像进行了绘制如下：\n\n![image.png](assets/607fdebf6bb31032f97913ba/04.png)\n\n![image.png](assets/607fdebf6bb31032f97913ba/05.png)\n\n两个图像差别不大，而从走势上看，取平方似乎更最接近最初的 V*F (Modified KSK and Schlick Fresnel depend on L*H)\n\n![image.png](assets/607fdebf6bb31032f97913ba/06.png)\n\n笔者修改了Lighting.hlsl的代码，使用一次方： outBRDFData.normalizationTerm = outBRDFData.perceptualRoughness* 4.0h + 2.0h;\n\n将使用roughness(n) + 0.5 和使用roughness(n)^2 + 0.5 的材质绘制在同一个屏幕上如下，两者几乎没有差别：\n\n![image.png](assets/607fdebf6bb31032f97913ba/07.png)\n\n根据图形学第一定律：**如果它看起来是对的，那么它就是对的**，所以理解成两个都对应该也可以。那么，是不是在差距不大的情况下就不必深究了。\n\n- 回答时间：2021-04-23 15:15:26\n- 最后更新：2021-04-23 15:24:43\n- 采纳状态：已采纳\n\n## 来源与关系\n\n- 上位集合：[[10-计算机、信息技术与工程/05-游戏图形与运行时/我的UWA问答/我的UWA问答|我的 UWA 问答]]\n- UWA 标签：终端平台、渲染模块\n- 原始问题：[URP的BRDF计算的疑惑，与论文中的公式不一样？](https://answer.uwa4d.com/question/607fdebf6bb31032f97913ba)\n- 源页最后更新：2021-04-23 07:15:26\n"
}
