请选择 进入手机版 | 继续访问电脑版

查看: 144|回复: 8

[求助] UnityStandardBRDF中GGX的实现疑问

[复制链接]

1

主题

2

帖子

45

贡献

初级UU族—1级

Rank: 1

积分
45
发表于 6 天前 | 显示全部楼层 |阅读模式
代码如下,SmithJointGGXVisibilityTerm函数的实现
[AppleScript] 纯文本查看 复制代码
// Ref: [url]http://jcgt.org/published/0003/02/03/paper.pdf[/url]
//GGX可见性项V
//G(l,v,h)=G1(l)G1(v)
inline half SmithJointGGXVisibilityTerm (half NdotL, half NdotV, half roughness)
{
//#if 0分支不会被执行,执行下面的简化
#if 0
	//原始公式
	//根据GGX的G(l,v,h)公式,分子分母同时除2*NdotL/2*NdotV,最后的结果分母可以整理成(1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
	//疑问:下方的值计算不一致,以及最后G的值计算是否有问题
    // Original formulation:
    //  lambda_v    = (-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
    //  lambda_l    = (-1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5f;
    //  G           = 1 / (1 + lambda_v + lambda_l);

    // Reorder code to be more optimal
    half a          = roughness; 
    half a2         = a * a;
	//重排代码为何会出现NdotL,NdotV混用?
    half lambdaV    = NdotL * sqrt((-NdotV * a2 + NdotV) * NdotV + a2);
    half lambdaL    = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);
	//简化的可见性项
	//((4.0f * NdotL * NdotV)
    // Simplify visibility term: (2.0f * NdotL * NdotV) /  ((4.0f * NdotL * NdotV) * (lambda_v + lambda_l + 1e-5f));
    return 0.5f / (lambdaV + lambdaL + 1e-5f);  // This function is not intended to be running on Mobile,
                                                // therefore epsilon is smaller than can be represented by half
#else
	//上述公式的近似,简化了sqrt,数学不正确但足够接近
    // Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough)
    half a = roughness;
    half lambdaV = NdotL * (NdotV * (1 - a) + a);
    half lambdaL = NdotV * (NdotL * (1 - a) + a);

    return 0.5f / (lambdaV + lambdaL + 1e-5f);
#endif
}
GGX的G(l,v,h)项计算公式应该搜到的是这个
捕获.PNG

在我的计算中:
原始公式中lambda_l=(-1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
根据G1的公式,分子分母同时除以2NdotL可以的整理得:
(1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f;
首项一个是1一个是-1
再者,G拆分成两个G1子函数,最后G的结果应该是两个子函数的积,即G=G1(l)G1(v),但是代码中似乎是用的加法而不是乘法假设(1 + sqrt(a2 * (1 - NdotL2) / NdotL2 + 1)) * 0.5f拆成 sqrt(a2 * (1 - NdotL2) / NdotL2 + 1) * 0.5f+0.5f;
即a+0.5,同理(1 + sqrt(a2 * (1 - NdotV2) / NdotV2 + 1)) * 0.5f为b+0.5
对应的是代码公式中的a-0.5,b-0.5
根据代码公式计算的结果为1/(a+b)
而根据G=G1(l)G1(v),结果是1/(ab+0.5a+0.5b+0.25)
结果根本不一致
谁清楚unity实现GGX是什么原理啊,还是我哪里想错了??

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表