首页 > 其他分享 >基于物理的渲染(4):Disney 原则

基于物理的渲染(4):Disney 原则

时间:2024-12-03 21:55:55浏览次数:3  
标签:NdotV 1.0 渲染 float uniform vec3 NdotH Disney 物理

1 背景

​​  2010年提出的PBR光照模型存在包含大量复杂而晦涩的物理参数,不利于美术人员理解、使用和快速产出等问题,2012年disney发表《Physically-based shading at Disney》,提出了Disney 原则的BRDF,在行业内制造了一场基于物理的渲染革命。之后主流游戏引擎都开始从传统的渲染工作流转移到基于物理的渲染工作流。

2 基础概念

2.1 控制BRDF的各项参数

参数 解释
baseColor 固有色 表面颜色,通常由纹理贴图提供
subsurface 次表面 使用次表面近似控制漫反射形状
metallic 金属度 金属(0 = 电介质,1 =金属)。这是两种不同模型之间的线性混合。金属模型没有漫反射成分,并且还具有等于基础色的着色入射镜面反射
specular 镜面反射强度 入射镜面反射量。用于取代折射率
specularTint 镜面反射颜色 对美术控制的让步,用于对基础色(baseColor)的入射镜面反射进行颜色控制。掠射镜面反射仍然是非彩色的
roughness 粗糙度 表面粗糙度,控制漫反射和镜面反射
anisotropic 各向异性强度 各向异性程度。用于控制镜面反射高光的纵横比。(0 =各向同性,1 =最大各向异性。)
sheen 光泽度 一种额外的掠射分量(grazing component),主要用于布料
sheenTint 光泽颜色 对sheen(光泽度)的颜色控制
clearcoat 清漆强度 有特殊用途的第二个镜面波瓣(specular lobe)
clearcoatGloss 清漆光泽度 控制透明涂层光泽度,0 = “缎面(satin)”外观,1 = “光泽(gloss)”外观

  其他参数保持为常数,变化其中一种参数显示的效果如下图所示:

2.2 Disney BRDF

  基于微平面模型、能量守恒原则、菲涅尔反射方程的渲染方程如下所示:

\[L_o(p,ω_o)=∫_Ωf_r(p,ω_i,ω_o)L_i(p,ω_i)n⋅ω_idω_i \]

​  其中\(L_o\)为P点的出射辐射率,\(f_r\)是P点入射方向到出射方向光的反射比,也叫双向反射分布函数(BRDF),\(L_i\)是P点入射光辐射率。渲染方程说明了P点的出射辐射率,可以通过半球 \(Ω\)内所有入射方向光线辐射率乘以\(f_r\),和余弦值 \(n⋅ω_i\) 。

  Cook-Torrance BRDF模型既有漫反射项又有高光反射项,在实时渲染中最为常用:

\[f_r=f_d+f_s \]

  c为表面颜色。Cook-Torrance 高光反射模型如下

​   \(f_{cook-torrance}=\frac{DFG}{4(W_o*n)(w_i*n)}\)

  其中包含三个函数,D表示法线分布函数(Normal Distribution Function),F表示菲涅尔方程(Fresnel Equation),和G表示几何函数(Geometry Function)。

a. 漫反射项(Disney Diffuse)

  Disney表示Lambert漫反射在模型边缘通常太暗,开发了新的经验模型,以在光滑表面的漫反射菲涅尔阴影和粗糙表面之间进行平滑过渡。公式为:

\[f_d=\frac{baseColor}{\pi}(1+(F_{D90}-1)(1-cos{\theta_l})^5)(1+(F_{D90}-1)(1-cos{\theta_v})^5) \]

​  其中,

\[F_{D90}=0.5+2.0*roughness*cos^2{\theta_d} \]

​  代码实现如下:

float SchlickFresnel(float u)
{
    float m = clamp(1-u, 0, 1);
    float m2 = m*m;
    return m2*m2*m; // pow(m,5)
}
// Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
// and mix in diffuse retro-reflection based on roughness
float FL = SchlickFresnel(NdotL), FV = SchlickFresnel(NdotV);
float Fd90 = 0.5 + 2 * LdotH*LdotH * roughness;
float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);

b. 法线分布项(Specular D)

​  Disney将Trowbridge-Reitz进行了N次幂的推广,并将其取名为Generalized-Trowbridge-Reitz,GTR:

\[D_GTR=\frac{c}{({\alpha}^2cos^2{\theta_h}+sin^2{\theta_h})^{\gamma}} \]

  其中,c为缩放系数,a为粗糙度系数取[0,1],当r=1时,GTR为Berry分布,当r=2时,GTR为Trowbridge-Reitz分布。如下图所示:

  实现代码如下:

float GTR1(float NdotH, float a)
{
    if (a >= 1) return 1/PI;
    float a2 = a*a;
    float t = 1 + (a2-1)*NdotH*NdotH;
    return (a2-1) / (PI*log(a2)*t);
}

float GTR2(float NdotH, float a)
{
    float a2 = a*a;
    float t = 1 + (a2-1)*NdotH*NdotH;
    return a2 / (PI * t*t);
}

float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
{
    return 1 / (PI * ax*ay * sqr( sqr(HdotX/ax) + sqr(HdotY/ay) + NdotH*NdotH ));
}

c. 菲涅尔项(Specular F)

  采用Schlick Fresnel近似:

\[F_{schlick}=F_0+(1-F_{0})(1-cos{\theta_d})^5 \]

  其中,常数F0表示垂直入射时的镜面反射率,\(\theta_d\)为半矢量h和视线矢量v之间的夹角。

d. 几何遮蔽项(Specular G)

  Disney参考了 Walter的近似方法,使用Smith GGX导出的G项,并将粗糙度参数进行重映射以减少光泽表面的极端增益,几何项的粗糙度变化更加平滑。

  材料的粗糙度越高,微平面相互遮蔽的概率越高,SmithG-GGX几何函数

​   \(G_{SmithG\_GGX}(n,v,k)=\frac{2n⋅v}{(n⋅v)+\sqrt(\alpha^2+(1-\alpha^2)(n⋅v)^2)}\)

  其中a由粗糙度计算而来:

​   \(\alpha=(0.5+\frac{roughness}{2})^2\)

​  实现的代码如下:

float smithG_GGX(float NdotV, float alphaG)
{
    float a = alphaG*alphaG;
    float b = NdotV*NdotV;
    return 1 / (NdotV + sqrt(a + b - a*b));
}

float smithG_GGX_aniso(float NdotV, float VdotX, float VdotY, float ax, float ay)
{
    return 1 / (NdotV + sqrt( sqr(VdotX*ax) + sqr(VdotY*ay) + sqr(NdotV) ));
}

3 osg中实现

  真实感渲染,顶点着色器:

const char* vertCode=R"(
#version 330
layout(location=0) in vec3 vPosition;
layout(location=1) in vec3 vColor;
layout(location=2) in vec3 vNormal;
layout(location=3) in vec3 vTexCoord;


uniform mat4 osg_ModelViewProjectionMatrix;
uniform mat4 osg_ModelViewMatrix;
uniform mat4 osg_NormalMatrix;

out vec2 texCoord;
out vec3 cPos;
out vec3 cNorm;

void main()
{
	texCoord=vTexCoord;
	cNorm=osg_NormalMatrix*(vNormal);
	gl_position=osg_ModelViewProjectionMatrix*vec4(Position,1.0);	
}
)“;

  片段着色器:

const char* fragCode=R"(
#version 330
const vec3 lightPos=vec3(0.0,0.0,1.0);
const vec3 lightColor=vec3(5.6,5.6,5.6);
const float PI=3.1415926;

uniform sample2D tex;

uniform vec3  uBaseColor=vec3(0.82,0.67,0.16);
uniform float uMetallic=0.0;
uniform float uSubsurface=1.0;
uniform float uSpecular=1.0;
uniform float uSpecularTint=1.0;
uniform float uRoughness=0.11;
uniform float uAnisotropic=1.0;
uniform float uSheen=0.0;
uniform float uSheenTint=0.0;
uniform float uClearcoat=1.0;
uniform float uClearcoatGloss=0.76;

uniform float uHue=0.5;
uniform float uSaturation=0.5;
uniform float uBrightness=0.5;

uniform float alpha=1.0;

in vec2 texCoord;
in vec3 cPos;
in vec3 cNorm;

vec3 rgb2hsv(vec3 c)
{
	vec4 k=vec4(0.0,-1.0/3.0,2.0/3.0,-1.0);
	vec4 p=mix(vec4(c.bg,k.wz),vec4(c.gb,k.xy),step(c.b,c.g));
	vec4 q=mix(vec4(p.xyw,c.r),vec4(c.r,p.yzx),step(p.x,c.r));
	
	float d=q.x-min(q.w,q.y);
	float e=1.e-10;
	return vec3(abs(q.z+(q.w-q.y)/(6.0*d+e)),d/(q.x+e),q.x);
}

vec3 hsv2rgb(vec3 c)
{
	vec4 k=vec4(1.0,2.0/3.0,1.0/3.0,3.0);
	vec3 p=abs(frack(c.xxx+k.xyz)*6.0-k.www);
	return c.z*mix(k.xxx,clamp(p-k.xxx,0.0,1.0),c.y);
}

float calcSaturation(float s1,float s2)
{
	if(s2<0.5)s1=s1*(s2*2.0);
	else if(s2<0.9)s1=s1*((s2-0.5)*4.0+1.0);
	else s1=s1*((s2-0.9)*32.0+2.6);
	s1=min(s1,1.0);
	return s1;
}

vec3 calcHsl(vec3 hsl,vec3 para)
{
	float hue=hsl.x;
	float sat=hsl.y;
	float light=hsl.z;
	
	float hue1=para.x;
	float sat1=para.y;
	float light1=para.z;
	
	hue=mod(hue+(hue1-0.5),1.0);
	sat=calcSaturation(sat,sat1);
	light==light+light1*2.0-1.0;
	light=min(light,1.0);
	light=max(light,0.0);
	return vec3(hue,sat,light);	
}


float sqr(float x) { return x*x; }

float SchlickFresnel(float u)
{
    float m = clamp(1-u, 0, 1);
    float m2 = m*m;
    return m2*m2*m; // pow(m,5)
}

float GTR1(float NdotH, float a)
{
    if (a >= 1) return 1/PI;
    float a2 = a*a;
    float t = 1 + (a2-1)*NdotH*NdotH;
    return (a2-1) / (PI*log(a2)*t);
}

float GTR2(float NdotH, float a)
{
    float a2 = a*a;
    float t = 1 + (a2-1)*NdotH*NdotH;
    return a2 / (PI * t*t);
}

float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay)
{
    return 1 / (PI * ax*ay * sqr( sqr(HdotX/ax) + sqr(HdotY/ay) + NdotH*NdotH ));
}

float smithG_GGX(float NdotV, float alphaG)
{
    float a = alphaG*alphaG;
    float b = NdotV*NdotV;
    return 1 / (NdotV + sqrt(a + b - a*b));
}

float smithG_GGX_aniso(float NdotV, float VdotX, float VdotY, float ax, float ay)
{
    return 1 / (NdotV + sqrt( sqr(VdotX*ax) + sqr(VdotY*ay) + sqr(NdotV) ));
}

vec3 mon2lin(vec3 x)
{
    return vec3(pow(x[0], 2.2), pow(x[1], 2.2), pow(x[2], 2.2));
}

vec3 calculateTangent(vec3 N)
{
    vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
    return normalize(cross(up, N));
}

vec3 BRDF( vec3 L, vec3 V, vec3 N, vec3 X, vec3 Y,vec3 albedo)
{
    float NdotL = dot(N,L);
    float NdotV = dot(N,V);
    if (NdotL < 0 || NdotV < 0) return vec3(0);

    vec3 H = normalize(L+V);
    float NdotH = dot(N,H);
    float LdotH = dot(L,H);

    vec3 Cdlin = mon2lin(albedo);
    float Cdlum = .3*Cdlin[0] + .6*Cdlin[1]  + .1*Cdlin[2]; // luminance approx.

    vec3 Ctint = Cdlum > 0 ? Cdlin/Cdlum : vec3(1); // normalize lum. to isolate hue+sat
    vec3 Cspec0 = mix(specular*.08*mix(vec3(1), Ctint, specularTint), Cdlin, metallic);
    vec3 Csheen = mix(vec3(1), Ctint, sheenTint);

    // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing
    // and mix in diffuse retro-reflection based on roughness
    float FL = SchlickFresnel(NdotL), FV = SchlickFresnel(NdotV);
    float Fd90 = 0.5 + 2 * LdotH*LdotH * roughness;
    float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV);

    // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf
    // 1.25 scale is used to (roughly) preserve albedo
    // Fss90 used to "flatten" retroreflection based on roughness
    float Fss90 = LdotH*LdotH*roughness;
    float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV);
    float ss = 1.25 * (Fss * (1 / (NdotL + NdotV) - .5) + .5);

    // specular
    float aspect = sqrt(1-anisotropic*.9);
    float ax = max(.001, sqr(roughness)/aspect);
    float ay = max(.001, sqr(roughness)*aspect);
    float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay);
    float FH = SchlickFresnel(LdotH);
    vec3 Fs = mix(Cspec0, vec3(1), FH);
    float Gs;
    Gs  = smithG_GGX_aniso(NdotL, dot(L, X), dot(L, Y), ax, ay);
    Gs *= smithG_GGX_aniso(NdotV, dot(V, X), dot(V, Y), ax, ay);

    // sheen
    vec3 Fsheen = FH * sheen * Csheen;

    // clearcoat (ior = 1.5 -> F0 = 0.04)
    float Dr = GTR1(NdotH, mix(.1,.001,clearCoatGloss));
    float Fr = mix(.04, 1.0, FH);
    float Gr = smithG_GGX(NdotL, .25) * smithG_GGX(NdotV, .25);

    return ((1/PI) * mix(Fd, ss, subsurface)*Cdlin + Fsheen)
    * (1-metallic)
    + Gs*Fs*Ds + .25*clearCoat*Gr*Fr*Dr;
}

void main()
{
	vec3 albedo=texture2D(tex,texCoord);
	albedo=rgb2hsv(albedo);
	albedo=calcHsl(albedo);
	albedo=hsv2rgb(albedo);
	albedo=mon2lin(albedo);
	vec3 N=cNorm;
	vec3 V=vec3(0.0,0.0,1.0);
	vec3 X=calculateTangent(N);
	vec3 Y=cross(N,X);
	
	vec3 Lo=BRDF(normalize(LightPos-WorldPos),V,N,X,Y,albedo);
	 // Light intensity calculation (assuming a simple point light model)
    float distance = length(lightPosition - WorldPos);
    float attenuation = 1.0 / (distance * distance);
    vec3 radiance = lightColour * attenuation;

    Lo *= radiance * max(dot(N, normalize(lightPosition - WorldPos)), 0.0);

    // HDR tonemapping and Gamma correction (basic)
    Lo = Lo / (Lo + vec3(1.0));
    Lo = pow(Lo, vec3(1.0/2.2));
    fragColor=vec4(Lo,alpha);
}

)“;

标签:NdotV,1.0,渲染,float,uniform,vec3,NdotH,Disney,物理
From: https://www.cnblogs.com/wangxydela/p/18585127

相关文章

  • 高中物理必修一 第一章
    概念性质点定义:用来代替物体有质量的点叫做质点。物体可以被看作质点的条件:物体的大小,形状等对于需要研究的问题没有影响或者影响可以忽略。物体上各点的运动状态需要是相同的。参考系定义:要描述一个物体的运动,首先需要确定某个其他物体作为参考,观察物体的位置相对于......
  • 我谈冈萨雷斯对理想滤波器的误解——能用卷积实现的滤波器都是FIR滤波器,都物理可实现
    能用卷积实现的滤波器都是FIR滤波器,都是物理可实现的。Gonzalez可笑的理想滤波器,还反复强调物理不可实现。都采样了,咋就不可物理实现呢?不丝滑归不丝滑。FIR和IIR滤波器的常系数差分方程FIR(FiniteImpulseResponse,有限脉冲响应)和IIR(InfiniteImpulseResponse,......
  • 低配电脑也能轻松渲染珠宝动画:云渲染技术的应用
    珠宝设计中,动画渲染至关重要,但高配置需求常成障碍。云渲染技术解决了这一问题,让低配电脑也能轻松完成高质量渲染,释放设计师的创意潜力。本文将探讨云渲染如何革新珠宝设计行业。一、渲染配置要求在珠宝设计渲染的过程中,硬件配置对于实现高效和高质量的渲染至关重要。其中,CPU(中......
  • 物理套卷练习记录
    20242024Nov12024.11.262024南通如皋高三上学期第一次教学质量检测——【练习】81【总结】基本上是统一进度的试卷,但错了很多简单题。电容的定义式为\(C=\frac{Q}{U}\),其中,\(Q\)指平行电容器一个极板所带电荷量的绝对值。【传送门】https://www.doc88.com/p-9572988......
  • 物理机安装centos7和简单设置
    前期准备下载并写入u盘选择一个喜欢的Linux版本并下载下来,一般在官网下载比较慢,建议在一些国内的镜像网站下载。aliyun镜像此外我们还需要一个将下载好的ISO文件写入U盘的工具,这里使用的是软碟通。下载后安装使用试用版本。软碟通下载在文件-打开找到下载好的iso文件。然后......
  • 【娱乐项目】基于批处理脚本与JavaScript渲染视频列表的Web页面
    Demo介绍一个简单的视频播放器应用,其中包含了视频列表和一个视频播放区域。用户可以通过点击视频列表中的项来选择并播放相应的视频,播放器会自动播放每个视频并在播放完毕后切换到下一个视频。本项目旨在通过自动化脚本和动态网页渲染,帮助用户快速生成并展示本地视频资源(......
  • matlab描述一个涉及多种粒子状态及其相互作用的物理系统,可能用于求解该系统在给定条件
    %定义粒子状态,能级对应的未知数n_states={'n1','1s5';'n2','1s4';'n3','1s3';'n4','1s2';'n5','2p10';'n6','2p9'......
  • 【PostgreSQL备份恢复一】物理备份与恢复
    【PostgreSQL备份恢复】物理备份与恢复文章目录【PostgreSQL备份恢复】物理备份与恢复前言一、PostgreSQL的物理备份什么?二、冷备份1、准备阶段2、关闭数据库3、备份数据目录4、严重数据5、重启数据库服务总结前言前文介绍了PostgreSQL的逻辑备份与恢复,文本......
  • UE4云渲染多机输出,效率惊人!
    在当今的游戏开发和实时3D可视化领域,虚幻引擎(UnrealEngine,简称UE)以其强大的功能和灵活性而广受欢迎。随着云计算技术的飞速发展,云渲染作为一种新兴的服务模式,为UE开发者提供了更多的可能性。核心优势:高性能与低延迟UE4云渲染技术的核心优势在于其能够提供高性能的渲染......
  • 说说React服务端渲染怎么做?原理是什么?
    一、是什么在SSR中 (opensnewwindow),我们了解到Server-SideRendering ,简称SSR,意为服务端渲染指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程其解决的问题主要有两个:SEO,由于搜索引擎爬虫抓取工具......