当前位置:网站首页>UnityShader入门精要-立方体纹理、反射、折射、菲涅尔反射
UnityShader入门精要-立方体纹理、反射、折射、菲涅尔反射
2022-08-10 05:37:00 【hippodu】
立方体纹理用于实现环境映射模拟周围环境,共包含了6张图像,对这样的纹理采样我们需要提供三维的纹理坐标,表示一个矢量,与触碰到的六个纹理之一相交后对该点采样。场景中引入了新的物体、光源、物体移动,就需要重新生成立方体纹理,仅可反射环境,不能反射使用了该立方体纹理的物体本身,不能模拟多次反射,尽量对凸面体使用立方体纹理。常用于天空盒子和环境映射。
Skybox
创建一个用于环境映射的立方体纹理方法有:①由特殊布局的纹理创建(类似立方体展开图),只需将该纹理的texture type 设置为cube。(PBR中常用一张HDR生成高质量的cubemap)②创建一个cubemap,把六张纹理拖拽到面板中。③创建立方体纹理使用脚本。
逻辑为:在指定位置动态创建一个摄像机,并调用RenderToCubemap把当前位置观察的图像渲染到指定的立方体纹理中,完成后销毁临时摄像机,需要放入Editor文件夹中。
得到的cubemap设置大小Face size,越大纹理分辨率越大 内存也越大。准备好了立方体纹理后,就可以对物体使用环境映射技术,常见的为反射与折射。
反射
通过入射光线的方向与法线方向计算反射方向,再利用反射方向对立方体纹理采样。reflectcolor控制反射颜色,reflectamount控制反射程度,cubemap为用于反射的环境映射纹理。在顶点着色器中计算顶点处的反射方向,在片元着色器中利用反射方向对立方体纹理采样,使用texCUBE函数。
o.worldRefl=reflect(-o.worldViewDir,o.worldNormal);//在顶点着色器内
fixed3 reflection= texCUBE(_Cubemap,i.worldRefl).rgb*_ReflectColor.rgb;//在片元着色器内
完整:
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "Shaders/AdvTex/Reflection"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_ReflectColor("Reflection Color",Color)=(1,1,1,1)
_ReflectAmount("ReflectAmount",Range(0,1))=1
_Cubemap("Reflection Cubemap", Cube)="_Skybox"{}
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry"}
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
fixed4 _Color;
fixed4 _ReflectColor;
fixed _ReflectAmount;
samplerCUBE _Cubemap;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
float3 worldPos:TEXCOORD0;
fixed3 worldNormal :TEXCOORD1;
fixed3 worldViewDir :TEXCOORD2;
fixed3 worldRefl :TEXCOORD3;
SHADOW_COORDS(4)
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal=UnityObjectToWorldNormal(v.normal);
o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
o.worldViewDir=UnityWorldSpaceViewDir(v.vertex);
o.worldRefl=reflect(-o.worldViewDir,o.worldNormal);
TRANSFER_SHADOW(o);
return o;
}
fixed4 frag(v2f i) : SV_Target {
float3 worldNormal=normalize(i.worldNormal);
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 viewDir = normalize(i.worldViewDir);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz ;
fixed3 diffuse = _LightColor0.rgb * _Color.rgb* max(0, dot(worldNormal, lightDir));
fixed3 reflection= texCUBE(_Cubemap,i.worldRefl).rgb*_ReflectColor.rgb;
UNITY_LIGHT_ATTENUATION(atten, i,i. worldPos);
fixed3 color =ambient + lerp(diffuse,reflection,_ReflectAmount)*atten;
return fixed4(color, 1.0);
}
ENDCG
}
}
FallBack "Reflective/VertexLit"
}
折射
公式:n1sina=n2sinb,n为折射率,ab为入射角与折射角。
除了amount与color以外,需要_RefractRatio表示不同介质的透射比来计算折射方向。
refract函数,第一个参数为入射光线的方向,第二个参数为表面法相,它们都需要进行normalize,第三个参数是折射率之比(入射比折射),使用折射方向对立方体纹理采样。
和上面相比,要更改的只有把反射部分的计算改为折射部分的
// Compute the refract dir in world space in vert
o.worldRefr = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractRatio);
// Use the refract dir in world space to access the cubemap in frag
fixed3 refraction = texCUBE(_Cubemap, i.worldRefr).rgb * _RefractColor.rgb;
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
// Mix the diffuse color with the refract color
fixed3 color = ambient + lerp(diffuse, refraction, _RefractAmount) * atten;
菲涅尔反射
使用菲涅尔反射来根据视角方向控制反射程度,描述一部分光反射一部分光折射或散射的现象,计算其比率。主要使用的近似公式有两种。
Schlick菲涅尔近似式: 其中F0为反射系数控制反射强度,v是视角方向,n是表面法线。
Empricial菲涅尔近似式:
其中bias、scale、power是控制项。
下面只将漫反射项与反射项使用菲涅尔反射值进行插值计算,后面会处理反射与折射,涉及到与上面不同的代码如下:
fixed fresnel =_FresnelScale+(1-_FresnelScale)*pow(1-dot(worldViewDir,worldNormal),5);
fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb;
fixed3 color = ambient + lerp(diffuse, reflection,saturate(fresnel)) * atten;
从左至右 反射 折射 菲涅尔反射 效果展示:
边栏推荐
- 动态规划、背包问题 6/23 101-105
- 碳酸锂、碳酸氢锂溶液除钙镁离子工艺原理
- 浅谈游戏中3种常用阴影渲染技术(3):阴影贴图
- Linux的文件IO与标准IO,以及IO缓存
- 多线程与多进程(概念详细讲解)
- (Flutter报错)Cannot run with sound null safety, because the following dependencies
- markdown使用技巧
- Teach you to change the kernel source code--sysfs virtual file system 1
- 8个问题轻松掌握Unity前向渲染
- 2021-04-15 jacoco代码覆盖率统计和白盒测试
猜你喜欢
LruCache与DiskLruCache结合简单实现ImageLoader
浅谈游戏中3种常用阴影渲染技术(2):阴影锥
ASP.Net利用代码点击相应按钮来关闭当前的页面(亲测有效)
【C语言】结构体变量学习笔记1
开源游戏服务器框架NoahGameFrame(NF)客户端环境搭建(三)
Talking about 3 common shadow rendering techniques in games (2): shadow cone
C#对MySQL数据库进行增删改查操作(该操作还有防止MySQL注入功能)
Unity的GetComponentsInChildren1、2、3
手机端应用类型
Easy to master Unity of eight prior to rendering
随机推荐
Kernel performance analysis summary
钴镍回收树脂的工艺原理
剑指 Offer(第 2 版)7/6 9-13
(Flutter报错)Cannot run with sound null safety, because the following dependencies
The use of pointers from the exchange of two data values (C language implementation)
如何实现网格建造系统
浅谈游戏中3种常用阴影渲染技术(1):平面阴影
超纯水抛光树脂
浅谈游戏中3种常用阴影渲染技术(3):阴影贴图
动态规划、背包问题 6/26 116-120
作为测试,常用的adb命令
计算数字区间中数字出现次数
LruCache与DiskLruCache结合简单实现ImageLoader
Unity血条跟随对象
Multisim软件的基本使用
动态规划、背包问题 6/28 121-124
Unity中暂停、继续播放、杀死、正放、倒放Dotween动画
分享一个专业TA的《Shader参考大全》
享元模式-缓存池
unity在UI界面上展示旋转模型