unity Build-in 光源和光照模型
1、Unity光源模型
1.1 两种渲染方式
前向渲染:每个物体都有可能被重复渲染,即基于物体的光源渲染;超出灯光设置数量被当作顶点光(6*6)
延迟渲染:基于光源的物体渲染;以灯光为单位,先计算灯光所需东西,如RT0为漫反射,RT1为金属度,RT2为法线图;对于多光源友好(6+6);
区别:延迟渲染需要MRT技术(multi render target)和空间容量大
1.2 前向渲染
Unity两种前向渲染管线
bulid in:跟上文提到的概念一样; 个pass;base仅一个方向光。
urp:一个pass,最多八盏灯;
1.3 Phong光源模型
高光反射:pow(RdotV,smoothness)×lightcolor;
漫反射:NdotL×lightcolor
若附加纹理,相乘即可。
1.4 法线贴图
unity中的切线a分量是为了兼容各平台差异
法线贴图需要解码,解码后调整隆起大小再转至TBN空间
反射为什么灯光要负方向?
因为unity内置的计算灯光方向是从模型向光源走
forwardbase的实现:
Shader "Unlit/phong2"
{Properties{_MainTex ("Texture", 2D) = "white" {}_smoothness("Smoothness",Range(0.01,100))=1.0_specuIntensity("SpecuIntensity",Range(0.00,100))=1.0_NormalTex ("NormalTex", 2D) = "white" {}_normalIntensity("NormalIntensity",Range(0.00,5))=1.0}SubShader{LOD 100Pass{Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "AutoLight.cginc"#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 nor:NORMAL;float4 tangent:TANGENT;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float3 posW:TEXCOORD1;float3 norW:TEXCOORD2;float3 tangentW:TEXCOORD3;float3 biNormal:TEXCOORD4;};sampler2D _MainTex;float4 _MainTex_ST;float4 _LightColor0;float _smoothness;float _specuIntensity;float _normalIntensity;sampler2D _NormalTex;float4 _NormalTex_ST;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.posW=mul(unity_ObjectToWorld,v.vertex);o.norW=normalize(mul(float4(v.nor,0.0),unity_ObjectToWorld).xyz);o.uv = TRANSFORM_TEX(v.uv, _MainTex);o.tangentW=normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,0.0)).xyz)*v.tangent.w;o.biNormal=normalize(cross(o.tangentW,o.norW));return o;}half4 frag (v2f i) : SV_Target{half3 final;//normal mapfloat4 normalmMap=tex2D(_NormalTex,i.uv);float3 normal=UnpackNormal(normalmMap).xyz;normal.xy=normal.xy*_normalIntensity;float3 tangentW=normalize(i.tangentW);float3 biNormal=normalize(i.biNormal);float3 norW=normalize(i.norW);float3x3 TBN=float3x3(tangentW,biNormal,norW);normal=normalize(mul(normal,TBN)) ;// ambientfixed4 baseColor = tex2D(_MainTex, i.uv);half3 ambient=baseColor.rgb*UNITY_LIGHTMODEL_AMBIENT.rgb;//DIFFUSE//float3 normalW=normalize(i.norW);float3 L=normalize(UnityWorldSpaceLightDir(i.posW));float NdotL=saturate(dot(L,normal));//half3 diffuse=NdotL*baseColor.rgb*_LightColor0.xyz;//SPECULARfloat3 R=reflect(-L,normal);//float3 viewDirW=normalize(UnityWorldSpaceViewDir(i.posW));float3 specu=pow(saturate(dot(R,viewDirW)),_smoothness)*_LightColor0.xyz*_specuIntensity;final=diffuse.rgb+ambient.rgb+specu.rgb;return half4(final,1.0);}ENDCG}}
}
forwardadd的实现:
Tags { "LightMode"="ForwardAdd" }Blend One OneCGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdadd#include "AutoLight.cginc"#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 nor:NORMAL;float4 tangent:TANGENT;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float3 posW:TEXCOORD1;float3 norW:TEXCOORD2;float3 tangentW:TEXCOORD3;float3 biNormal:TEXCOORD4;};sampler2D _MainTex;float4 _MainTex_ST;float4 _LightColor0;float _smoothness;float _specuIntensity;float _normalIntensity;sampler2D _NormalTex;float4 _NormalTex_ST;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.posW=mul(unity_ObjectToWorld,v.vertex);o.norW=normalize(mul(float4(v.nor,0.0),unity_ObjectToWorld).xyz);o.uv = TRANSFORM_TEX(v.uv, _MainTex);o.tangentW=normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,0.0)).xyz)*v.tangent.w;o.biNormal=normalize(cross(o.tangentW,o.norW));return o;}half4 frag (v2f i) : SV_Target{half3 final;//光源衰减#if defined(DIRECTIONAL)float3 L=normalize(UnityWorldSpaceLightDir(i.posW));float attenuation=1.0;#elif defined(POINT)float3 L=normalize(_WorldSpaceLightPos0.xyz-i.posW);float distance=length(_WorldSpaceLightPos0.xyz-i.posW);float Range=1.0/unity_WorldToLight[0][0];float attenuation=saturate(Range-distance/Range);#endif//光源衰减//normal mapfloat4 normalmMap=tex2D(_NormalTex,i.uv);float3 normal=UnpackNormal(normalmMap).xyz;normal.xy=normal.xy*_normalIntensity;float3 tangentW=normalize(i.tangentW);float3 biNormal=normalize(i.biNormal);float3 norW=normalize(i.norW);float3x3 TBN=float3x3(tangentW,biNormal,norW);normal=normalize(mul(normal,TBN)) ;// ambientfixed4 baseColor = tex2D(_MainTex, i.uv);half3 ambient=baseColor.rgb*UNITY_LIGHTMODEL_AMBIENT.rgb;//DIFFUSE//float3 normalW=normalize(i.norW);float NdotL=saturate(dot(L,normal));//half3 diffuse=NdotL*baseColor.rgb*_LightColor0.xyz;//SPECULARfloat3 R=reflect(-L,normal);//float3 viewDirW=normalize(UnityWorldSpaceViewDir(i.posW));float3 specu=pow(saturate(dot(R,viewDirW)),_smoothness)*_LightColor0.xyz*_specuIntensity;final=(diffuse.rgb+specu.rgb)*attenuation;return half4(final,1.0);}
点光源衰减范围:r-d/r
bliphong,在phong模型基础上优化高光反射,减少消耗,(半角向量)h=l+v,NdotH
// phong// float3 R=reflect(-L,normal);// float RdotN=saturate(dot(R,norW));// float3 specu=pow(RdotN,_smoothness)*_LightColor0.xyz*_specuIntensity;//bliphongfloat3 viewDirW=normalize(UnityWorldSpaceViewDir(i.posW));float3 h=max(0.0,L+viewDirW);float HdotN=saturate(dot(h,norW));float3 specu=pow(HdotN,_smoothness)*_LightColor0.xyz*_specuIntensity;
BliPhong Phong
2、ACESFilm tone-mapping:
显示器显示范围为0-1,为LDR,而计算机渲染可以是任意数值。HDR→LDR过程造成失真,丢失许多细节。(HDR:高动态范围)
解决这个问题:HDR→LDR(tone-mapping)
tone-mapping(个人经验),pow(basecolor(diffuse2d),2.2)转换至线性空间,pow(tonecolor,1.0/2.2)转换至伽马空间。
ACESFilm not
全局环境光开启泛光?解决:globalAmbient×baseColor;
3、视差贴图(原理还是不熟悉):
置换贴图,模型表面曲面细分,高密度顶点,读取高度图,顶点偏移。深度图,其实是高度图的反相,白色代表凹陷
for (int i = 0; i < 10; i++)
{half height = tex2D(_ParallaxMap, uv_parallax);uv_parallax = uv_parallax+ (1.0 - height) * view_tangentspace.xy * _Parallax * 0.01f;
}
开启 未开启
4、shadowmap
- shadowmap
- screen space shadowmap
- 联级阴影(csm) cascaded shadowmapping:shadowmap基础上,视锥体分级
shadowmap就是一张深度图,
shadowmap实现:光源相机渲染深度信息,物体转换至光源相机空间,跟shadowmap里的深度值作比较,若片元深度值>深度值(shadowmap),光面。反之阴影面。
联级阴影以及屏幕空间下的阴影还需深入学习!
注意:光位置的w分量可以判断是否为平行光,0为平行光。1为点光。
5、间接光照
5.1基本概念
环境光≈间接光
三种技术实现:
- LightMap(预先烘焙好)
- 反射探针:捕抓环境信息→环境贴图,模拟漫反射
- 光照探针:预先收集环境和光源的漫反射信息,模拟漫反射;
实现原理:
- 环境贴图
- IBL基于图像的照明
- SH球谐光照
CubeMap采样全景图实现:
反射探针和CubeMap实现:
fixed4 frag (v2f i) : SV_Target
{// sample the texturefloat3 viewDir=UnityWorldSpaceViewDir(i.posW);float3 normalW=normalize(i.normalW);float3 ref=reflect(-viewDir,normalW);//反射探针float4 environColor=UNITY_SAMPLE_TEXCUBE(unity_SpecCube0,ref);//为了移动端也可以获取到HDR的信息float3 hdrColor=DecodeHDR(environColor,unity_SpecCube0_HDR);//fixed4 col = texCUBE(_CubeMap, ref);//CubeMapreturn float4(hdrColor,1.0);
}
6、IBL 基于图像的照明
ibl ,一个设置一行代码。
为什么是mipmap?
pow对比度,直接相乘亮度,lerp整体粗糙度,线性粗糙度
ibl镜面反射和漫反射
使用IBL要三线性过滤
IBL实现一般不需要大尺寸(压缩压缩再压缩,,,,)
IBL间接镜面反射光:
fixed4 frag (v2f i) : SV_Target
{// 取rougness,算出mipmap的levelfloat roughness=tex2D(_RoughtMap,i.uv).r;roughness=pow(roughness,_Contrastion)*_Brighteness;roughness=lerp(_RoughnessMin,_RoughnessMax,roughness);roughness = roughness * (1.7 - 0.7 * roughness);float level=roughness*6.0;//取法线,算反射float3 normaldata= UnpackNormal(tex2D(_NormalMap,i.uv));float3 normalW=normalize(i.normalW);float3 tangent=normalize(i.tangent);float3 binormal=normalize(i.binormal); float3x3 TBN=float3x3(tangent,binormal,normalW);float3 normal=normalize(mul(normaldata,TBN));float3 viewDir=UnityWorldSpaceViewDir(i.posW);float3 reflectDir=reflect(-viewDir,normal);//aofloat aoMap=tex2D(_AOMap,i.uv).r;float ao= lerp(1.0,aoMap,_AOAdjust);//cubemap的ibl实现float4 cubeMap=texCUBElod(_CubeMap,float4(reflectDir,level));float3 envir=DecodeHDR(cubeMap,_CubeMap_HDR).rgb;//cubemap的probe实现//half4 color_cubemap = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectDir, level);//half3 envir = DecodeHDR(color_cubemap, unity_SpecCube0_HDR);//确保在移动端能拿到HDR信息//最终颜色float3 col=envir*_Tint.rgb*_Tint.rgb*ao* _Expose;//tonemappingcol=pow(col,2.2);col=ACES_Tonemapping(col);col=pow(col,1/2.2);return float4(col,1.0);
}
IBL间接漫反射光:
float4 uv_ibl = float4(normal_dir, mip_level);half4 color_cubemap = texCUBElod(_CubeMap, uv_ibl);
half3 env_color = DecodeHDR(color_cubemap, _CubeMap_HDR);//确保在移动端能拿到HDR信息
7、球谐光照(SH)
sh球谐光照内置实现(light probe的probe)
在forwardbase实现;
造轮子实现:
half4 frag (v2f i) : SV_Target
{half3 normal_dir = normalize(i.normal_world);half3 normaldata = UnpackNormal(tex2D(_NormalMap,i.uv));normaldata.xy = normaldata.xy* _NormalIntensity;half3 tangent_dir = normalize(i.tangent_world);half3 binormal_dir = normalize(i.binormal_world);normal_dir = normalize(tangent_dir * normaldata.x+ binormal_dir * normaldata.y + normal_dir * normaldata.z);half ao = tex2D(_AOMap, i.uv).r;ao = lerp(1.0,ao, _AOAdjust);float4 normalForSH = float4(normal_dir, 1.0);//SHEvalLinearL0L1half3 x;x.r = dot(custom_SHAr, normalForSH);x.g = dot(custom_SHAg, normalForSH);x.b = dot(custom_SHAb, normalForSH);//SHEvalLinearL2half3 x1, x2;// 4 of the quadratic (L2) polynomialshalf4 vB = normalForSH.xyzz * normalForSH.yzzx;x1.r = dot(custom_SHBr, vB);x1.g = dot(custom_SHBg, vB);x1.b = dot(custom_SHBb, vB);// Final (5th) quadratic (L2) polynomialhalf vC = normalForSH.x*normalForSH.x - normalForSH.y*normalForSH.y;x2 = custom_SHC.rgb * vC;float3 sh = max(float3(0.0, 0.0, 0.0), (x + x1 + x2));sh = pow(sh, 1.0 / 2.2);half3 env_color = sh;half3 final_color = env_color * ao * _Tint.rgb * _Expose;return float4(final_color,1.0);
}
unity内置实现:
half4 frag (v2f i) : SV_Target
{half3 normal_dir = normalize(i.normal_world);half3 normaldata = UnpackNormal(tex2D(_NormalMap,i.uv));normaldata.xy = normaldata.xy* _NormalIntensity;half3 tangent_dir = normalize(i.tangent_world);half3 binormal_dir = normalize(i.binormal_world);normal_dir = normalize(tangent_dir * normaldata.x+ binormal_dir * normaldata.y + normal_dir * normaldata.z);half ao = tex2D(_AOMap, i.uv).r;ao = lerp(1.0,ao, _AOAdjust);half3 env_color = ShadeSH9(float4(normal_dir,1.0));half3 final_color = env_color * ao * _Tint.rgb * _Expose;return float4(final_color,1.0);
}
unity全局间接光:
- lighting-environment lighting 漫反射
- lighting-environment refection 镜面反射
lighting-mixed lighting-baked global illumination 烘焙多光源
8、玉石模拟
玉石光线(穿透感)+光滑质感(环境反射)
组成:漫反射+透射+环境光;
漫反射=phong漫反射+addcolor+竖直方向AO;
透射计算:VdotB(B为L扭曲而成),结合对比度、亮度,乘以模型厚度、basecolor(光源颜色影响世界,所以独立一个光源颜色)和平行光颜色;
环境光:cubemap结合菲涅尔;
forbase:
float4 frag(v2f i) : COLOR
{//infofloat3 diffuse_color = _DiffuseColor;float3 normalDir = normalize(i.normalDir);float3 viewDir = normalize(_WorldSpaceCameraPos - i.posWorld.xyz);float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);//diffusefloat diff_term = max(0.0, dot(normalDir, lightDir));float3 diffuselight_color = diff_term * diffuse_color * _LightColor0.rgb;//竖直方向的AO,上亮下暗float sky_sphere = (dot(normalDir,float3(0,1,0)) + 1.0) * 0.5;float3 sky_light = sky_sphere * diffuse_color;float3 final_diffuse = diffuselight_color + sky_light * _Opacity + _AddColor.xyz;//trans lightfloat3 back_dir = -normalize(lightDir + normalDir * _BasePassDistortion);float VdotB = max(0.0, dot(viewDir, back_dir));float backlight_term = max(0.0,pow(VdotB, _BasePassPower)) * _BasePassScale;float thickness = 1.0 - tex2D(_ThicknessMap, i.uv).r;float3 backlight = backlight_term * thickness *_LightColor0.xyz * _BasePassColor.xyz;//ENVfloat3 reflectDir = reflect(-viewDir,normalDir);half theta = _EnvRotate * UNITY_PI / 180.0f;float2x2 m_rot = float2x2(cos(theta), -sin(theta), sin(theta),cos(theta));float2 v_rot = mul(m_rot, reflectDir.xz);reflectDir = half3(v_rot.x, reflectDir.y, v_rot.y);float4 cubemap_color = texCUBE(_EnvMap,reflectDir);half3 env_color = DecodeHDR(cubemap_color, _EnvMap_HDR);float fresnel = 1.0 - saturate(dot(normalDir, viewDir));fresnel = smoothstep(_FresnelMin, _FresnelMax, fresnel);float3 final_env = env_color * _EnvIntensity * fresnel;//combinefloat3 combined_color = final_diffuse + final_env + backlight;float3 final_color = combined_color;return float4(final_color,1.0);
}
forwardadd:
float4 frag(v2f i) : COLOR
{float3 diffuse_color = _DiffuseColor * _DiffuseColor;float3 normalDir = normalize(i.normalDir); float3 viewDir = normalize(_WorldSpaceCameraPos - i.posWorld.xyz);float NdotV = saturate(dot(normalDir,viewDir));//light infofloat3 lightDir = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));float attenuation = LIGHT_ATTENUATION(i);//trans lightfloat3 back_dir = -normalize(lightDir + normalDir * _AddPassDistortion);float VdotB = max(0.0,dot(viewDir, back_dir));float backlight_term = max(0.0, pow(VdotB, _AddPassPower)) * _AddPassScale;float thickness = 1.0 - tex2D(_ThicknessMap, i.uv).r;float3 backlight = backlight_term * thickness *_LightColor0.xyz * _AddPassColor.xyz;//combinefloat3 final_color = backlight;final_color = sqrt(final_color);return float4(final_color,1.0);
}
9、移动端角色渲染
分析与问题:
- ue和unity的单位区别(米、厘米);
- x轴向的区别;
- 模型和骨骼动画的大量到处;
- Mc纹理,rg通道粗糙度、金属度;
- 角色脚部抖动,曲线优化和压缩问题;
细节:
- 皮肤区域高光弱,金属区域高光强,albedo贴图的使用原理其一
- 皮肤区域漫反射强,金属区域漫反射弱,albedo贴图的使用原理其二
- 粗糙度做文章,越粗糙,光滑度越低
- 阴影不在间接光中计算,仅在直接光中,因为间接光的作用在于提亮暗部
- 皮肤正常sh,其他乘以0.5sh
疑问:
- 间接光的漫反射为什么要限定为0.5到1的范围内?
解答:使用了半兰伯特模型,提亮暗部
2. 153/154的操作不是很能理解,间接光都要乘以这个?
解答:shininess x smoothness ≈ a(1-a)x+a²,a为smoothness,但是还是线性关系
3. 皮肤柔光的插值操作
公式总结:
- 直接光漫反射:diffterm x basecolor x atten x lightcolor
- 直接光镜面反射:specterm x speccolor x atten x lightcolor
- 间接光漫反射:sh x basecolor x halflambert
- 间接光镜面反射:ibl x expose x speccolor x halflambert
头发渲染:kk的各向异性高光渲染
技术原理:normal实现的高光仅仅是一点,我们需要在头发的横截面都有高光
公式:T、L、V三个成关系,LV成半角关系H,求sin(T,H);
细节:
- T根据normal进行偏移,高光即可实现偏移;
- 噪声图扰动各向异性方向,范围由0到1缩放到-1到1;
- N x noise
- half_lambert/NdotL ,防止背光区域也有高光
疑问:
1. 为什么各向异性高光只亮一处?
因为sin(T,H)的夹角为90°时才为1
2. 为什么成光盘一样的扇形?
因为顺着边缘变化,中间的偏移更大,两边渐变,越远渐变范围越大;而中心范围小是因为没有偏移
细节语法:
1. 宏定义:检查器隐藏
2. 宏开关:多重编译和shader特性,增加一个,代码量两倍
unity Build-in 光源和光照模型相关推荐
- 如何在Unity中自定义光源,包含URP管线和Build in 管线(一)
如何在Unity中自定义光源,包含URP管线和Build in 管线(一) 众所周知,光照在游戏画面效果上占了很大比例,一个游戏画面好不好,用最简单的理解来说,就是看游戏画面亮不亮,当然这个亮不是不是 ...
- [unity] build项目报错:Currently selected scripting backend (.NET)is not installed
[Unity] Currently selected scripting backend .NET is notinstalled Unity build项目报错,没有安装 .NET 问题概况 Uni ...
- unity build设置_Microsoft Build上的Unity:展会上的7个重点
unity build设置 The Microsoft Build 2018 developer conference just wrapped up in Seattle and Unity was ...
- unity球体添加光源_Unity渲染路径——光源种类
在之前的实践场景中,一般只有一个光源且光源类型是平行光.但实际光源类型不止一种,且需要被区别对待. 光源种类 在之前的文章中多多少少地提到了Unity中支持几种不同的光源,其中包括点光源(point ...
- unity build报错Type has an extra field of type in the and thus can‘t be serialized error
一般发生于unity的android打包中,删除Library文件夹下的Bee文件夹和BuildPlayerData文件夹重新build即可,unity版本2021.3.13f1c1
- unity球体添加光源_关于Unity中的光源
一.光源定义 光源,是一个普通节点加一个Light组件,创建的时候可以直接创建光源节点,也可以先创建一个空节点,再添加Light组件实例. 二.颜色形成 看到的物体颜色受两个很重要的因素的影响,一个是 ...
- Unity build setting小技巧
1.如何隐藏分辨率选择窗口(如果需要的话运行程序时按住shift按键可呼出) 2.如果某些特殊设备分辨率怎么都调不对,不妨看看这里勾选了没有 3.在这里可以更改程序运行时的'made with uni ...
- Unity Build IOS包
今天接触了Unity和IOS的交互,最主要是学习了UnitybuildIOS包,实际情况呢可以参考别人的博客 https://blog.csdn.net/jia18337935154/article/ ...
- Unity中的多光源
在Unity中,如果想要使用多光源,比如2个平行光,或者1个平行光+1个点光源,需要在额外的shader pass中进行处理: Pass {Tags {"LightMode" = ...
最新文章
- runaway深度递归函数测试及相关汇编指令
- svg text换行_5分钟看懂SVG反爬虫原理与绕过实战 | 知了干货分享
- 吊打一切现有开源OCR项目:效果再升7%,速度提升220%
- 最快最新最详细的IT电子书
- with 关键字实现递归查询
- Wpf 调用线程无法访问此对象,因为另一个线程拥有该对象,解决方案
- poj 1083 Moving Tables
- python安装mysqldb模块_Python的MySQLdb模块安装
- redis 介绍与安装
- 内联函数与宏定义的区别
- 任正非——《一江春水向东流》
- 幽默 滑稽 及 其他
- Java模拟消息队列
- 大众点评评论抓取-CSS加密破解
- EVE-ng模拟器安装教程和使用教程
- Windows MFC 工程应用开发与框架原理完全剖析教程(下)
- 单片机/树莓派扩展双串口(TTL和RS485)
- OSI七层模型和TCPIP五层模型
- 外部PLC触发VisionMaster多流程运行
- 发现一款好用到爆的数据库工具,被惊艳到了!