我试图在我们的项目中实现基于物理的渲染(PBR) (我们开始了一个用于学术和学习目的的小游戏引擎),但我不明白根据材质的金属和粗糙度计算镜面反射和漫反射贡献的正确方法是什么。
我们没有使用任何第三方库/引擎来渲染,所有的东西都是用OpenGL 3.3手工编写的。
现在我有了这个(我会把完整的代码放在下面):
// Calculate contribution based on metallicity
vec3 diffuseColor = baseColor - baseColor * metallic;
vec3 specularColor = mix(vec3(0.00), baseColor, metallic);但我的印象是,镜面反射项必须以某种方式依赖于粗糙度。我想把它改成这样:
vec3 specularColor = mix(vec3(0.00), baseColor, roughness);但再说一次,我不确定。什么才是正确的方法呢?有没有一种正确的方法,或者我应该只使用“试错”的方法,直到我得到满意的结果?
下面是完整的GLSL代码:
// Calculates specular intensity according to the Cook - Torrance model
float CalcCookTorSpec(vec3 normal, vec3 lightDir, vec3 viewDir, float roughness, float F0)
{
// Calculate intermediary values
vec3 halfVector = normalize(lightDir + viewDir);
float NdotL = max(dot(normal, lightDir), 0.0);
float NdotH = max(dot(normal, halfVector), 0.0);
float NdotV = max(dot(normal, viewDir), 0.0); // Note: this could also be NdotL, which is the same value
float VdotH = max(dot(viewDir, halfVector), 0.0);
float specular = 0.0;
if(NdotL > 0.0)
{
float G = GeometricalAttenuation(NdotH, NdotV, VdotH, NdotL);
float D = BeckmannDistribution(roughness, NdotH);
float F = Fresnel(F0, VdotH);
specular = (D * F * G) / (NdotV * NdotL * 4);
}
return specular;
}
vec3 CalcLight(vec3 lightColor, vec3 normal, vec3 lightDir, vec3 viewDir, Material material, float shadowFactor)
{
// Helper variables
vec3 baseColor = material.diffuse;
vec3 specColor = material.specular;
vec3 emissive = material.emissive;
float roughness = material.roughness;
float fresnel = material.fresnel;
float metallic = material.metallic;
// Calculate contribution based on metallicity
vec3 diffuseColor = baseColor - baseColor * metallic;
vec3 specularColor = mix(vec3(0.00), baseColor, metallic);
// Lambertian reflectance
float Kd = DiffuseLambert(normal, lightDir);
// Specular shading (Cook-Torrance model)
float Ks = CalcCookTorSpec(normal, lightDir, viewDir, roughness, fresnel);
// Combine results
vec3 diffuse = diffuseColor * Kd;
vec3 specular = specularColor * Ks;
vec3 result = lightColor * (emissive + diffuse + specular);
return result * (1.0 - shadowFactor);
}发布于 2016-04-09 10:44:36
您要查找的是材质的双向反射比分布函数(BRDF)。在您的代码中,您引用了“库克-托伦斯模型”,它是一种常见且有效(但计算成本也很高)的BRDF。看起来你可能从“金属/粗糙度”模型和“镜面反射/光泽度”模型中得到了灵感。这是一个巨大的话题,但理解这两个可能会有所帮助。
无论如何,在基于物理的着色模型中,BRDF必须节省能量。因此,漫反射+镜面反射的贡献不能超过1或:
Kd = 1 - Ks着色器的物理精度取决于对材质特性执行的计算,但在您的情况下,可以将金属项合并到BRDF中,如下所示:
BRDF = (1-m)*diffuse + m*specular从这里你可以处理照明等等。
--金属度/粗糙度着色器原点
迪士尼提出了一种更逼真的着色器方法。UnrealEngine4实现了这个模型,现在有很多关于术语和纹理工作流的混淆。
https://stackoverflow.com/questions/36510170
复制相似问题