原理

根据能量守恒,以及一系列光照原理得出微表面BRDF(Bidirectional Reflectance Distribution Function)公式

//     D(h) F(v,h) G(l,v,h)
//f(l,v) = ---------------------------
//       4(n·l)(n·v)

D;微表面法线分布函数,选取ggx近似

//       alpha^2
//D(h) = -----------------------------------
//      pi*((n·h)^2 *(alpha^2-1)+1)^2
其中 alpha = roughness^2

//G(l,v,h) 微表面遮挡函数,使用smith-Schlick近似
// 1
//G(l,v,h) = --------------------------------------------------
// (nl*(1-k)+k)*(nv*(1-k)+k)
//
// k = (a^2 +1) * (a^2 +1)/8; 抄ue4
// k = roughness^2 //u3d

//F(I,h) schlick菲涅尔近似等式
//F(I,h) = F0+(1-F0)(1-nl)^5
//F0高光反射颜色

对应的shader代码

half3 viewDir  = normalize(i.viewDir);

half3 lightDir = normalize(_WorldSpaceLightPos0.xyz);

fixed3 normalTex = UnpackNormal(tex2D(_BumpTex, i.uv)).rgb;
half3 wn = calculateWorldNormal(i.normal, i.tangent, normalTex, _normalScale);

half nl = saturate(dot(wn, lightDir));
half nh = saturate(dot(wn, halfDir));
half nv = saturate(dot(wn, viewDir));
half lh = saturate(dot(lightDir ,halfDir));

inline half BRDFspec(half roughness, half nl , half nv , half nh, half3 specColor )
{
half a2 = roughness*roughness*roughness*roughness;
half d = nh*nh*(a2-1)+1;
half D = UNITY_INV_PI*a2/(d*d);

half k = (a2+1)*(a2+1)/8;
half G = 1/((nl*(1-k)+k)*(nv*(1-k)+k));

half F = specColor+(1-specColor)*Pow5(1-nl);
return F*max( 0, D*G*nl/(4*nl*nv));
}

fixed spec = BRDFspec(roughness,  nl, nv ,  nh ,  specColor);

漫反射部分使用Disney(从unity里抄的)

inline half DisneyDiffuse(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
{
half fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
// Two schlick fresnel term
half lightScatter = (1 + (fd90 - 1) * Pow5(1 - NdotL));
half viewScatter = (1 + (fd90 - 1) * Pow5(1 - NdotV));

return lightScatter * viewScatter;
}

half diffColor = DisneyDiffuse(nv, nl, lh, roughness)* nl;

half3 brdf= (spec+ diffColor*mainTex.rgb) * metallic*_LightColor * _LightIntensity

仅仅brdf会出现死黑,所以要加上基本色

half3 diffuse = (UNITY_LIGHTMODEL_AMBIENT.xyz+(0.3+0.7*nl)*LIGHT_ATTENUATION(i) * _LightColor.xyz)*mainTex.rgb*(1-metallic)

应美术要求把半兰伯特模型的0.5改成了0.3

最终color = diffuse + brdf

以下是完整代码:

  1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
  2.  
  3. Shader "Custom/PBR"
  4. {
  5. Properties
  6. {
  7. _EmissiveColor("自发光颜色",Color) = (,,,)
  8. _EmissiveIntensity("自发光强度",Float) =
  9.  
  10. _LightColor("光照颜色",Color) = (,,,)
  11. _LightIntensity("光照强度",Range(,)) =
  12.  
  13. _normalScale("法线强度",Float) =
  14. _environment_rotation("环境光贴图旋转",Range(,)) =
  15. _RotateSpeed("旋转速度", float) =
  16. _Exposure("环境光曝光值",Float) =
  17. _Skincolor ("Skin Color Custom", Color) = (,,,)
  18.  
  19. _MainTex("颜色贴图", 2D) = "white" {}
  20. _BumpTex("法线贴图", 2D) = "bump" {}
  21.  
  22. _ChannelTex("RGB光滑金属变色", 2D) = "white" {}
  23.  
  24. _EmissiveMap("自发光贴图", 2D) = "black" {}
  25.  
  26. _Cube ("环境光贴图", Cube) = "" {}
  27.  
  28. _Metallic("金属度上限",Range(,))=
  29. _MetallicMin("金属度下限",Range(,))=
  30. _Glossiness ("光滑度上限", Range(,)) =
  31. _GlossinessMin ("光滑度下限", Range(,)) =
  32. //Rim
  33. _RimColor("轮廓光颜色", Color) = (, , , )
  34. _RimArea("轮廓光范围", Range(, )) = 3.6
  35. _RimPower("轮廓光强度", Range(, )) = 0.0
  36. }
  37.  
  38. SubShader
  39. {
  40. LOD
  41. Lighting Off
  42. Tags {"RenderType"="Opaque"}
  43.  
  44. // Pass to render object as a shadow caster
  45. Pass
  46. {
  47. Name "ShadowCaster"
  48. Tags { "LightMode" = "ShadowCaster" }
  49.  
  50. ZWrite On ZTest LEqual Cull Off
  51.  
  52. CGPROGRAM
  53. #pragma vertex vert
  54. #pragma fragment frag
  55. #pragma multi_compile_shadowcaster
  56. #include "UnityCG.cginc"
  57.  
  58. struct v2f {
  59. V2F_SHADOW_CASTER;
  60. };
  61.  
  62. v2f vert( appdata_base v )
  63. {
  64. v2f o;
  65. TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
  66. return o;
  67. }
  68.  
  69. float4 frag( v2f i ) : SV_Target
  70. {
  71. SHADOW_CASTER_FRAGMENT(i)
  72. }
  73. ENDCG
  74. }
  75.  
  76. Pass
  77. {
  78. CGPROGRAM
  79. #pragma vertex vert
  80. #pragma fragment frag
  81. #pragma fragmentoption ARB_precision_hint_fastest
  82. #include "UnityCG.cginc"
  83. #include "AutoLight.cginc"
  84. #include "UnityStandardConfig.cginc"
  85. #define INTERNAL_DATA
  86. #define WorldReflectionVector(data,normal) data.worldRefl
  87.  
  88. struct v2f
  89. {
  90. half4 pos : SV_POSITION;
  91. half2 uv : TEXCOORD0;
  92. float3 viewDir : TEXCOORD1;
  93. half3 normal : TEXCOORD4;
  94. half4 tangent : TEXCOORD5;
  95. };
  96.  
  97. sampler2D _MainTex;
  98. sampler2D _BumpTex;
  99. sampler2D _ChannelTex;
  100. sampler2D _EmissiveMap;
  101. samplerCUBE _Cube;
  102. half4 _Cube_HDR;
  103.  
  104. fixed _Metallic;
  105. fixed _MetallicMin;
  106. fixed _Glossiness;
  107. fixed _GlossinessMin;
  108. half _environment_rotation;
  109. half _RotateSpeed;
  110. half _Exposure;
  111.  
  112. half _normalScale;
  113. fixed4 _LightColor;
  114. half _LightIntensity;
  115.  
  116. fixed4 _DLightColor;
  117. half3 _DLightDir;
  118. half _DLightIntensity;
  119.  
  120. half _EmissiveIntensity;
  121. fixed4 _EmissiveColor;
  122.  
  123. fixed4 _Skincolor;
  124. float _RimPower;
  125. fixed4 _RimColor;
  126. float _RimArea;
  127. v2f vert(appdata_full v)
  128. {
  129. v2f o;
  130. o.pos = UnityObjectToClipPos(v.vertex);
  131. o.uv = v.texcoord;
  132.  
  133. o.viewDir = WorldSpaceViewDir(v.vertex);
  134. o.normal = v.normal;
  135. o.tangent = v.tangent;
  136. return o;
  137. }
  138.  
  139. fixed4 frag(v2f i) : SV_Target
  140. {
  141. half3 viewDir = normalize(i.viewDir);
  142. //half3 lightDir = _DLightDir;
  143. half3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
  144. //half3 lightDir = viewDir;
  145. fixed4 channel = tex2D(_ChannelTex, i.uv);
  146.  
  147. fixed metallic = _MetallicMin + channel.g * ( _Metallic - _MetallicMin );
  148. fixed glossness = ( _GlossinessMin + channel.r * (_Glossiness-_GlossinessMin) )* .99h;
  149. fixed roughness = - glossness;
  150. fixed colorMask = channel.b;
  151.  
  152. fixed4 mainTex = tex2D(_MainTex,i.uv);
  153. mainTex *= colorMask * _Skincolor + ( - colorMask);
  154.  
  155. fixed3 normalTex = UnpackNormal(tex2D(_BumpTex, i.uv)).rgb;
  156. half3 wn = calculateWorldNormal(i.normal, i.tangent, normalTex, _normalScale);
  157.  
  158. half3 halfDir = normalize(lightDir + viewDir);
  159.  
  160. half nl = saturate(dot(wn, lightDir));
  161. half nh = saturate(dot(wn, halfDir));
  162. half nv = saturate(dot(wn, viewDir));
  163. half lh = saturate(dot(lightDir ,halfDir));
  164.  
  165. half3 refDir = reflect(-viewDir, wn);
  166. refDir = EnvRotate (_environment_rotation + _Time.y * _RotateSpeed * , refDir);
  167.  
  168. float4 c;
  169.  
  170. half3 specColor = lerp (half3(0.04, 0.04, 0.04) , mainTex.rgb , metallic);
  171. //DisneyDiffuse(nv, nl, lh, roughness)
  172. //c.rgb = DiffuseAndSpecularFromMetallic (mainTex.rgb, metallic, /*out*/ specColor);
  173. //half lightFalloff = (nl * 0.5 + 0.5);
  174. //half3 diffColor = c.rgb * lightFalloff;
  175.  
  176. half diffColor = DisneyDiffuse(nv, nl, lh, roughness)* nl;
  177. fixed spec = BRDFspec(roughness, nl, nv , nh , specColor);
  178.  
  179. half mip = roughness * ;
  180. half3 rgbm = DecodeHDR(texCUBElod(_Cube, float4(refDir,mip)), _Cube_HDR);
  181.  
  182. fixed3 refColor = EnvBRDFMobile(specColor, roughness, nv) * rgbm;
  183. refColor = ACESToneMapping(refColor , _Exposure);
  184. refColor += refColor * metallic;
  185.  
  186. fixed emimask = tex2D(_EmissiveMap, i.uv).r;
  187. fixed3 Emissive = emimask * _EmissiveColor.rgb * _EmissiveIntensity;
  188.  
  189. //c.rgb = (refColor + (spec + diffColor) * _DLightColor * _DLightIntensity) + Emissive;
  190. float3 _Rim = pow(1.0 - max(, dot(wn, viewDir)), _RimArea)*_RimColor.rgb*_RimPower;
  191. c.rgb = (UNITY_LIGHTMODEL_AMBIENT.xyz+(0.3+0.7*nl)*LIGHT_ATTENUATION(i) * _LightColor.xyz)*mainTex.rgb*(-metallic)+ (refColor + (spec+ diffColor*mainTex.rgb) * metallic*_LightColor * _LightIntensity) + Emissive + _Rim;
  192. c.a=;
  193.  
  194. return c;
  195. }
  196. ENDCG
  197.  
  198. CGINCLUDE
  199. #include "UnityCG.cginc"
  200.  
  201. inline half Pow5 (half x)
  202. {
  203. return x*x * x*x * x;
  204. }
  205.  
  206. inline half DisneyDiffuse(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
  207. {
  208. half fd90 = 0.5 + * LdotH * LdotH * perceptualRoughness;
  209. // Two schlick fresnel term
  210. half lightScatter = ( + (fd90 - ) * Pow5( - NdotL));
  211. half viewScatter = ( + (fd90 - ) * Pow5( - NdotV));
  212.  
  213. return lightScatter * viewScatter;
  214. }
  215. inline half3 calculateWorldNormal(half3 normal, half4 tangent, fixed3 texnormal, half normalScale)
  216. {
  217. normal = normalize(normal);
  218. tangent = normalize(tangent);
  219. half3 binormal = cross(normal,tangent.xyz) * tangent.w;
  220. half3x3 TBN = half3x3(tangent.xyz, binormal, normal);
  221.  
  222. texnormal.xy *= normalScale;
  223. half3 normalL = texnormal.x * TBN[] +
  224. texnormal.y * TBN[] +
  225. texnormal.z * TBN[];
  226. half3 normalW = UnityObjectToWorldNormal(normalL);
  227. return normalize(normalW);
  228. }
  229. inline half RoughnessToSpecPower (fixed roughness, out fixed realRoughness)
  230. {
  231. realRoughness = max(.01h, roughness * roughness); // m is the true academic roughness.
  232.  
  233. half n = (2.0 / (realRoughness * realRoughness)) - 2.0; // https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf
  234. // prevent possible cases of pow(0,0), which could happen when roughness is 1.0 and NdotH is zero
  235. return n;
  236. }
  237. inline fixed3 FresnelLerpFast (fixed3 F0, fixed3 F90, half cosA)
  238. {
  239. cosA = - cosA;
  240. half fresnel = cosA * cosA * cosA * cosA;
  241. return lerp (F0, F90, fresnel);
  242. }
  243. inline half3 DiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor)
  244. {
  245. specColor = lerp (half3(0.04, 0.04, 0.04) , albedo , metallic);
  246.  
  247. half oneMinusDielectricSpec = - 0.04;
  248. half o = oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
  249. return albedo * o;
  250. }
  251. inline half3 EnvRotate (half Degrees, half3 refDir)
  252. {
  253. half rot = Degrees / .296h;
  254. half sinrot, cosrot;
  255. sincos(rot, sinrot, cosrot);
  256. half2x2 m = half2x2(cosrot, -sinrot, sinrot, cosrot);
  257. refDir.xz = mul(m, refDir.xz);
  258. refDir = normalize(refDir);
  259. return refDir;
  260. }
  261.  
  262. //微表面BRDF公式
  263. // D(h) F(v,h) G(l,v,h)
  264. //f(l,v) = ---------------------------
  265. // 4(n·l)(n·v)
  266.  
  267. //这个是GGX
  268. // alpha^2
  269. //D(h) = -----------------------------------
  270. // pi*((n·h)^2 *(alpha^2-1)+1)^2
  271. //alpha = roughness^2
  272. //G(l,v,h) smith-Schlick
  273. // 1
  274. //G(l,v,h) = --------------------------------------------------
  275. // (nl*(1-k)+k)*(nv*(1-k)+k)
  276. //
  277. // k = (a^2 +1) * (a^2 +1)/8; 抄ue4
  278. // k = roughness^2 //u3d
  279. //f(l,v)=F(v,h)G(l,n,v)D(h)/4(nl)(nv)
  280. //F(I,h) schlick菲涅尔近似等式
  281. //F(I,h) = F0+(1-F0)(1-nl)^5
  282. //F0高光反射颜色
  283.  
  284. inline half BRDFspec(half roughness, half nl , half nv , half nh, half3 specColor )
  285. {
  286. half a2 = roughness*roughness*roughness*roughness;
  287. half d = nh*nh*(a2-)+;
  288. half D = UNITY_INV_PI*a2/(d*d);
  289.  
  290. half k = (a2+)*(a2+)/;
  291. half G = /((nl*(-k)+k)*(nv*(-k)+k));
  292.  
  293. half F = specColor+(-specColor)*Pow5(-nl);
  294. return F*max( , D*G*nl/(*nl*nv));
  295. }
  296. inline half3 EnvBRDFMobile( half3 SpecularColor, half Roughness, half NoV )
  297. {
  298. const half4 c0 = { -, -0.0275, -0.572, 0.022 };
  299. const half4 c1 = { , 0.0425, 1.04, -0.04 };
  300. half4 r = Roughness * c0 + c1;
  301. half a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
  302. half2 AB = half2( -1.04, 1.04 ) * a004 + r.zw;
  303. return (SpecularColor * AB.x + AB.y);
  304. }
  305. inline half3 ACESToneMapping(float3 color, float adapted_lum)
  306. {
  307. const half A = 2.51;
  308. const half B = 0.03;
  309. const half C = 2.43;
  310. const half D = 0.59;
  311. const half E = 0.14;
  312.  
  313. color *= adapted_lum;
  314. return (color * (A * color + B)) / (color * (C * color + D) + E);
  315. }
  316. ENDCG
  317. }
  318. }
  319. }

附上截图

PBR探索的更多相关文章

  1. CG Kit探索移动端高性能渲染

    内容来源:华为开发者大会2021 HMS Core 6 Graphics技术论坛,主题演讲<CG Kit探索移动端高性能渲染> 演讲嘉宾:华为海思麒麟GPU团队工程师 大家好,我来自华为海 ...

  2. 【探索】机器指令翻译成 JavaScript

    前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...

  3. 【探索】利用 canvas 实现数据压缩

    前言 HTTP 支持 GZip 压缩,可节省不少传输资源.但遗憾的是,只有下载才有,上传并不支持.如果上传也能压缩,那就完美了.特别适合大量文本提交的场合,比如博客园,就是很好的例子. 虽然标准不支持 ...

  4. 探索C#之6.0语法糖剖析

    阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...

  5. Mysql事务探索及其在Django中的实践(二)

    继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...

  6. Linux学习之探索文件系统

    Linux,一起学习进步-    ls With it, we can see directory contents and determine a variety of important file ...

  7. 马里奥AI实现方式探索 ——神经网络+增强学习

    [TOC] 马里奥AI实现方式探索 --神经网络+增强学习 儿时我们都曾有过一个经典游戏的体验,就是马里奥(顶蘑菇^v^),这次里约奥运会闭幕式,日本作为2020年东京奥运会的东道主,安倍最后也已经典 ...

  8. C++随笔:.NET CoreCLR之GC探索(4)

    今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize fre ...

  9. C++随笔:.NET CoreCLR之GC探索(2)

    首先谢谢 @dudu 和 @张善友 这2位大神能订阅我,本来在写这个系列以前,我一直对写一些核心而且底层的知识持怀疑态度,我为什么持怀疑态度呢?因为一般写高层语言的人99%都不会碰底层,其实说句实话, ...

随机推荐

  1. 20160208.CCPP体系具体解释(0018天)

    程序片段(01):main.c 内容概要:PointWithOutInit #include <stdio.h> #include <stdlib.h> //01.野指针具体解 ...

  2. [Angular] Dynamic component rendering by using *ngComponentOutlet

    Let's say you want to rending some component based on condition, for example a Tabs component. Insid ...

  3. 《Qt on Android核心编程》相关资源

    有不少朋友反馈在搭建 Qt on Android 开发环境时遇到了问题,诸如 Android SDK 无法下载. jdk 找不到合适的版本号.创建 AVD 出错等等.为此我把与<Qt on An ...

  4. VENOM cve-2015-3456 Qemu 虚拟机逃逸漏洞POC

    #include <sys/io.h> int main() { int i ; iopl(3); outb(0x8e, 0x3f5); outb(0x41, 0x3f5); outb(0 ...

  5. DNS检测

    dig @58.241.41.152 6900255264940.barcode.cniotroot.cn naptr 没有naptr 好像有点异常 select count(*) as total ...

  6. linux在shell中获取时间 date巧用

    获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 date1=$(date --date='1 days ago +%Y%m%d')    #前一天的日期 date1=$(d ...

  7. 转:HTTP协议--- multipart/form-data请求分析

    转自:http://blog.csdn.net/five3/article/details/7181521 首先来了解什么是multipart/form-data请求: 根据http/1.1 rfc ...

  8. 关于javaSocket中 Software caused connection abort: recv failed问题

    在学习Socket中今天突然遇到了以下这种问题 原来是网路连接出了问题,由于我測试的是远程连接所以是在学校的局域网下,结果非常不稳定,開始还以为怎么了一会连上了一会又出现故障然后把IP地址改为本机的1 ...

  9. python测试网页是否能正常登陆

    #!/usr/bin/python #encoding:utf-8 ##实现网页的登陆检查 import HTMLParser import urlparse import cookielib imp ...

  10. lua学习笔记(十三)

    math库     定义在math中     所有三角函数都使用弧度     指数和对数函数     取整函数     伪随机数math.random         调用时没有参数返回0~1之间的随 ...