PBR探索
原理
根据能量守恒,以及一系列光照原理得出微表面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
以下是完整代码:
- // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
- Shader "Custom/PBR"
- {
- Properties
- {
- _EmissiveColor("自发光颜色",Color) = (,,,)
- _EmissiveIntensity("自发光强度",Float) =
- _LightColor("光照颜色",Color) = (,,,)
- _LightIntensity("光照强度",Range(,)) =
- _normalScale("法线强度",Float) =
- _environment_rotation("环境光贴图旋转",Range(,)) =
- _RotateSpeed("旋转速度", float) =
- _Exposure("环境光曝光值",Float) =
- _Skincolor ("Skin Color Custom", Color) = (,,,)
- _MainTex("颜色贴图", 2D) = "white" {}
- _BumpTex("法线贴图", 2D) = "bump" {}
- _ChannelTex("RGB光滑金属变色", 2D) = "white" {}
- _EmissiveMap("自发光贴图", 2D) = "black" {}
- _Cube ("环境光贴图", Cube) = "" {}
- _Metallic("金属度上限",Range(,))=
- _MetallicMin("金属度下限",Range(,))=
- _Glossiness ("光滑度上限", Range(,)) =
- _GlossinessMin ("光滑度下限", Range(,)) =
- //Rim
- _RimColor("轮廓光颜色", Color) = (, , , )
- _RimArea("轮廓光范围", Range(, )) = 3.6
- _RimPower("轮廓光强度", Range(, )) = 0.0
- }
- SubShader
- {
- LOD
- Lighting Off
- Tags {"RenderType"="Opaque"}
- // Pass to render object as a shadow caster
- Pass
- {
- Name "ShadowCaster"
- Tags { "LightMode" = "ShadowCaster" }
- ZWrite On ZTest LEqual Cull Off
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- #pragma multi_compile_shadowcaster
- #include "UnityCG.cginc"
- struct v2f {
- V2F_SHADOW_CASTER;
- };
- v2f vert( appdata_base v )
- {
- v2f o;
- TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
- return o;
- }
- float4 frag( v2f i ) : SV_Target
- {
- SHADOW_CASTER_FRAGMENT(i)
- }
- ENDCG
- }
- Pass
- {
- CGPROGRAM
- #pragma vertex vert
- #pragma fragment frag
- #pragma fragmentoption ARB_precision_hint_fastest
- #include "UnityCG.cginc"
- #include "AutoLight.cginc"
- #include "UnityStandardConfig.cginc"
- #define INTERNAL_DATA
- #define WorldReflectionVector(data,normal) data.worldRefl
- struct v2f
- {
- half4 pos : SV_POSITION;
- half2 uv : TEXCOORD0;
- float3 viewDir : TEXCOORD1;
- half3 normal : TEXCOORD4;
- half4 tangent : TEXCOORD5;
- };
- sampler2D _MainTex;
- sampler2D _BumpTex;
- sampler2D _ChannelTex;
- sampler2D _EmissiveMap;
- samplerCUBE _Cube;
- half4 _Cube_HDR;
- fixed _Metallic;
- fixed _MetallicMin;
- fixed _Glossiness;
- fixed _GlossinessMin;
- half _environment_rotation;
- half _RotateSpeed;
- half _Exposure;
- half _normalScale;
- fixed4 _LightColor;
- half _LightIntensity;
- fixed4 _DLightColor;
- half3 _DLightDir;
- half _DLightIntensity;
- half _EmissiveIntensity;
- fixed4 _EmissiveColor;
- fixed4 _Skincolor;
- float _RimPower;
- fixed4 _RimColor;
- float _RimArea;
- v2f vert(appdata_full v)
- {
- v2f o;
- o.pos = UnityObjectToClipPos(v.vertex);
- o.uv = v.texcoord;
- o.viewDir = WorldSpaceViewDir(v.vertex);
- o.normal = v.normal;
- o.tangent = v.tangent;
- return o;
- }
- fixed4 frag(v2f i) : SV_Target
- {
- half3 viewDir = normalize(i.viewDir);
- //half3 lightDir = _DLightDir;
- half3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
- //half3 lightDir = viewDir;
- fixed4 channel = tex2D(_ChannelTex, i.uv);
- fixed metallic = _MetallicMin + channel.g * ( _Metallic - _MetallicMin );
- fixed glossness = ( _GlossinessMin + channel.r * (_Glossiness-_GlossinessMin) )* .99h;
- fixed roughness = - glossness;
- fixed colorMask = channel.b;
- fixed4 mainTex = tex2D(_MainTex,i.uv);
- mainTex *= colorMask * _Skincolor + ( - colorMask);
- fixed3 normalTex = UnpackNormal(tex2D(_BumpTex, i.uv)).rgb;
- half3 wn = calculateWorldNormal(i.normal, i.tangent, normalTex, _normalScale);
- half3 halfDir = normalize(lightDir + viewDir);
- half nl = saturate(dot(wn, lightDir));
- half nh = saturate(dot(wn, halfDir));
- half nv = saturate(dot(wn, viewDir));
- half lh = saturate(dot(lightDir ,halfDir));
- half3 refDir = reflect(-viewDir, wn);
- refDir = EnvRotate (_environment_rotation + _Time.y * _RotateSpeed * , refDir);
- float4 c;
- half3 specColor = lerp (half3(0.04, 0.04, 0.04) , mainTex.rgb , metallic);
- //DisneyDiffuse(nv, nl, lh, roughness)
- //c.rgb = DiffuseAndSpecularFromMetallic (mainTex.rgb, metallic, /*out*/ specColor);
- //half lightFalloff = (nl * 0.5 + 0.5);
- //half3 diffColor = c.rgb * lightFalloff;
- half diffColor = DisneyDiffuse(nv, nl, lh, roughness)* nl;
- fixed spec = BRDFspec(roughness, nl, nv , nh , specColor);
- half mip = roughness * ;
- half3 rgbm = DecodeHDR(texCUBElod(_Cube, float4(refDir,mip)), _Cube_HDR);
- fixed3 refColor = EnvBRDFMobile(specColor, roughness, nv) * rgbm;
- refColor = ACESToneMapping(refColor , _Exposure);
- refColor += refColor * metallic;
- fixed emimask = tex2D(_EmissiveMap, i.uv).r;
- fixed3 Emissive = emimask * _EmissiveColor.rgb * _EmissiveIntensity;
- //c.rgb = (refColor + (spec + diffColor) * _DLightColor * _DLightIntensity) + Emissive;
- float3 _Rim = pow(1.0 - max(, dot(wn, viewDir)), _RimArea)*_RimColor.rgb*_RimPower;
- 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;
- c.a=;
- return c;
- }
- ENDCG
- CGINCLUDE
- #include "UnityCG.cginc"
- inline half Pow5 (half x)
- {
- return x*x * x*x * x;
- }
- inline half DisneyDiffuse(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
- {
- half fd90 = 0.5 + * LdotH * LdotH * perceptualRoughness;
- // Two schlick fresnel term
- half lightScatter = ( + (fd90 - ) * Pow5( - NdotL));
- half viewScatter = ( + (fd90 - ) * Pow5( - NdotV));
- return lightScatter * viewScatter;
- }
- inline half3 calculateWorldNormal(half3 normal, half4 tangent, fixed3 texnormal, half normalScale)
- {
- normal = normalize(normal);
- tangent = normalize(tangent);
- half3 binormal = cross(normal,tangent.xyz) * tangent.w;
- half3x3 TBN = half3x3(tangent.xyz, binormal, normal);
- texnormal.xy *= normalScale;
- half3 normalL = texnormal.x * TBN[] +
- texnormal.y * TBN[] +
- texnormal.z * TBN[];
- half3 normalW = UnityObjectToWorldNormal(normalL);
- return normalize(normalW);
- }
- inline half RoughnessToSpecPower (fixed roughness, out fixed realRoughness)
- {
- realRoughness = max(.01h, roughness * roughness); // m is the true academic roughness.
- half n = (2.0 / (realRoughness * realRoughness)) - 2.0; // https://dl.dropboxusercontent.com/u/55891920/papers/mm_brdf.pdf
- // prevent possible cases of pow(0,0), which could happen when roughness is 1.0 and NdotH is zero
- return n;
- }
- inline fixed3 FresnelLerpFast (fixed3 F0, fixed3 F90, half cosA)
- {
- cosA = - cosA;
- half fresnel = cosA * cosA * cosA * cosA;
- return lerp (F0, F90, fresnel);
- }
- inline half3 DiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor)
- {
- specColor = lerp (half3(0.04, 0.04, 0.04) , albedo , metallic);
- half oneMinusDielectricSpec = - 0.04;
- half o = oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
- return albedo * o;
- }
- inline half3 EnvRotate (half Degrees, half3 refDir)
- {
- half rot = Degrees / .296h;
- half sinrot, cosrot;
- sincos(rot, sinrot, cosrot);
- half2x2 m = half2x2(cosrot, -sinrot, sinrot, cosrot);
- refDir.xz = mul(m, refDir.xz);
- refDir = normalize(refDir);
- return refDir;
- }
- //微表面BRDF公式
- // D(h) F(v,h) G(l,v,h)
- //f(l,v) = ---------------------------
- // 4(n·l)(n·v)
- //这个是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(l,v)=F(v,h)G(l,n,v)D(h)/4(nl)(nv)
- //F(I,h) schlick菲涅尔近似等式
- //F(I,h) = F0+(1-F0)(1-nl)^5
- //F0高光反射颜色
- inline half BRDFspec(half roughness, half nl , half nv , half nh, half3 specColor )
- {
- half a2 = roughness*roughness*roughness*roughness;
- half d = nh*nh*(a2-)+;
- half D = UNITY_INV_PI*a2/(d*d);
- half k = (a2+)*(a2+)/;
- half G = /((nl*(-k)+k)*(nv*(-k)+k));
- half F = specColor+(-specColor)*Pow5(-nl);
- return F*max( , D*G*nl/(*nl*nv));
- }
- inline half3 EnvBRDFMobile( half3 SpecularColor, half Roughness, half NoV )
- {
- const half4 c0 = { -, -0.0275, -0.572, 0.022 };
- const half4 c1 = { , 0.0425, 1.04, -0.04 };
- half4 r = Roughness * c0 + c1;
- half a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
- half2 AB = half2( -1.04, 1.04 ) * a004 + r.zw;
- return (SpecularColor * AB.x + AB.y);
- }
- inline half3 ACESToneMapping(float3 color, float adapted_lum)
- {
- const half A = 2.51;
- const half B = 0.03;
- const half C = 2.43;
- const half D = 0.59;
- const half E = 0.14;
- color *= adapted_lum;
- return (color * (A * color + B)) / (color * (C * color + D) + E);
- }
- ENDCG
- }
- }
- }
附上截图
PBR探索的更多相关文章
- CG Kit探索移动端高性能渲染
内容来源:华为开发者大会2021 HMS Core 6 Graphics技术论坛,主题演讲<CG Kit探索移动端高性能渲染> 演讲嘉宾:华为海思麒麟GPU团队工程师 大家好,我来自华为海 ...
- 【探索】机器指令翻译成 JavaScript
前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...
- 【探索】利用 canvas 实现数据压缩
前言 HTTP 支持 GZip 压缩,可节省不少传输资源.但遗憾的是,只有下载才有,上传并不支持.如果上传也能压缩,那就完美了.特别适合大量文本提交的场合,比如博客园,就是很好的例子. 虽然标准不支持 ...
- 探索C#之6.0语法糖剖析
阅读目录: 自动属性默认初始化 自动只读属性默认初始化 表达式为主体的函数 表达式为主体的属性(赋值) 静态类导入 Null条件运算符 字符串格式化 索引初始化 异常过滤器when catch和fin ...
- Mysql事务探索及其在Django中的实践(二)
继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...
- Linux学习之探索文件系统
Linux,一起学习进步- ls With it, we can see directory contents and determine a variety of important file ...
- 马里奥AI实现方式探索 ——神经网络+增强学习
[TOC] 马里奥AI实现方式探索 --神经网络+增强学习 儿时我们都曾有过一个经典游戏的体验,就是马里奥(顶蘑菇^v^),这次里约奥运会闭幕式,日本作为2020年东京奥运会的东道主,安倍最后也已经典 ...
- C++随笔:.NET CoreCLR之GC探索(4)
今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize fre ...
- C++随笔:.NET CoreCLR之GC探索(2)
首先谢谢 @dudu 和 @张善友 这2位大神能订阅我,本来在写这个系列以前,我一直对写一些核心而且底层的知识持怀疑态度,我为什么持怀疑态度呢?因为一般写高层语言的人99%都不会碰底层,其实说句实话, ...
随机推荐
- 20160208.CCPP体系具体解释(0018天)
程序片段(01):main.c 内容概要:PointWithOutInit #include <stdio.h> #include <stdlib.h> //01.野指针具体解 ...
- [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 ...
- 《Qt on Android核心编程》相关资源
有不少朋友反馈在搭建 Qt on Android 开发环境时遇到了问题,诸如 Android SDK 无法下载. jdk 找不到合适的版本号.创建 AVD 出错等等.为此我把与<Qt on An ...
- VENOM cve-2015-3456 Qemu 虚拟机逃逸漏洞POC
#include <sys/io.h> int main() { int i ; iopl(3); outb(0x8e, 0x3f5); outb(0x41, 0x3f5); outb(0 ...
- DNS检测
dig @58.241.41.152 6900255264940.barcode.cniotroot.cn naptr 没有naptr 好像有点异常 select count(*) as total ...
- linux在shell中获取时间 date巧用
获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 date1=$(date --date='1 days ago +%Y%m%d') #前一天的日期 date1=$(d ...
- 转:HTTP协议--- multipart/form-data请求分析
转自:http://blog.csdn.net/five3/article/details/7181521 首先来了解什么是multipart/form-data请求: 根据http/1.1 rfc ...
- 关于javaSocket中 Software caused connection abort: recv failed问题
在学习Socket中今天突然遇到了以下这种问题 原来是网路连接出了问题,由于我測试的是远程连接所以是在学校的局域网下,结果非常不稳定,開始还以为怎么了一会连上了一会又出现故障然后把IP地址改为本机的1 ...
- python测试网页是否能正常登陆
#!/usr/bin/python #encoding:utf-8 ##实现网页的登陆检查 import HTMLParser import urlparse import cookielib imp ...
- lua学习笔记(十三)
math库 定义在math中 所有三角函数都使用弧度 指数和对数函数 取整函数 伪随机数math.random 调用时没有参数返回0~1之间的随 ...