当前位置: 首页 > news >正文

【Unity Shader入门精要 第10章】高级纹理(一)

1. 立方体纹理原理

立方体纹理由6张图片组成,每张图片分别对应立方体的一个面。这6张图片代表沿世界空间下的轴线(上下左右前后)观察所得的图像

立方体的应用主要分为两类:

  • 单纯利用6张图片的展示功能,为我们提供一个环境背景,比如天空盒
  • 对立方体纹理进行采样,显示在物体表面,反映物体对周围环境的反射、折射等效果,也就是用于环境映射

与2D纹理采样不同,立方体纹理采样时,需要提供一个3维的uv坐标,该坐标提供的是一个世界空间的方向,从立方体的中心出发,沿这个方向前进,会与6张图片中某一张相交在一点,这一点的颜色值即为采样结果。

在这里插入图片描述

2. 用于天空盒

创建天空盒

  • 先创建一个材质,本次使用的材质命名为Chapter_10_SkyBox_Mat
  • 为材质选择天空盒Shader,如下图有四种类型的天空盒Shader
    在这里插入图片描述
  • 6-Sided
    • 使用6张纹理作为天空盒的6个面
    • TintColor——调整整体颜色
    • Exposure——调整亮度
    • Rotation——调整Y轴旋转

(没有找到合适的资源,不试了)
在这里插入图片描述

  • Cubemap

    • 通过一张Cube纹理生成天空盒
      在这里插入图片描述
    • Cube纹理如下
      在这里插入图片描述
  • Panoramic

    • 由美术提供的一张特殊制作的高清纹理生成天空盒
      在这里插入图片描述

设置天空盒

  • 通过Window → Rendering → Lighting 打开光照设置面板
  • 在Environment标签页下设置当前场景天空盒
    在这里插入图片描述
  • 摄像机的Clear Flags 选项选择为 Skybox
  • 也可以为摄像机添加skybox组件,为组件选择其他的天空盒,此时当前摄像机在渲染时就会使用组件指定的天空盒替换掉光照面板中设置的场景天空盒
    在这里插入图片描述
    在这里插入图片描述

渲染顺序

在这里插入图片描述
从上面的截图中可以看到,天空盒的渲染序列为1000(Background)

在【Unity Shader入门精要 第8章】透明效果(一)中曾经说过,渲染队列为Background的物体用于远处的背景,但实际天空盒这些背景并不会真的最先渲染,而是在所有不透明的物体之后再进行渲染

这样在经过不透明物体的深度写入后,天空盒中的大量片元都不会通过深度测试,也就不需要进入片元着色器,可以有效降低 Over Draw

3. 用于环境映射

3.1 创建

除了用于天空盒,立方体纹理的另一个主要作用是用于环境映射。换句话说就是,以场景中的某一点为中心,通过立方体纹理反映从这一点看到的上下前后左右的环境,并可以通过对立方体纹理采样表现这一点的反射折射等现象。

可见,与天空盒不同,用于环境映射的立方体纹理的中心点通常是不确定的,其位置由使用立方体纹理的物体决定,需要表现哪个物体的反射等现象,就需要以该物体的位置为中心创建立方体纹理,这样才能正确表现该物体的周边环境信息。

在创建时,既可以提前准备好用于表示环境的纹理资源,也可以通过摄像机实时创建,常见有以下三种做法:

  • 先有图片,后生成资源——将美术提供提前绘制好的图片导入工程,将类型设置为Cube
    在这里插入图片描述
  • 先有资源,后提供图片——直接在资源面板里右键创建一个Cubemap资源,然后为该资源提供所需的6张图片
    在这里插入图片描述
    在这里插入图片描述
  • 脚本调用Camera的RenderToCubemap接口动态创建
GameObject _go = new GameObject();
_go.transform.position = TargetTransform.position;
Camera _tmpCam = _go.AddComponent<Camera>();
_tmpCam.RenderToCubemap(TargetCubemap);
DestroyImmediate(_tmpCam);

3.2 反射和折射

反射原理

在这里插入图片描述
光线与物体表面交互后改变传播方向进入我们的眼睛(摄像机),这个过程只改变光线的传播路径,不改变光线的颜色,因此我们就看到在物体表面倒映出周边环境的样子。

要模拟反射现象,只需要在渲染Pass中,计算出环境中的哪一点的光线在与当前片元交互后会传入摄像机,并根据反射的强度将这一点的颜色与物体本身颜色做融合即可。

因此,模拟反射的重点即是找到光线的来源。基于光路可逆的原理,我们可以从视线方向出发,经过与片元交互反向求出光线方向,然后用该方向对表示环境信息的立方体纹理进行采样。Unity中内置了 reflect 方法来快速计算模拟反射的光线来源方向。

o.worldRefl = reflect(-_worldView, o.worldNormal);

其中:

  • 第一个参数为视线方向,并且是由摄像机指向物体的方向,而Unity中内置变量或内置方法返回的观察方向都是从物体指向摄像机的,因此在使用时需要先取反
  • 第二个参数为当前处理的点的法线
  • 该方法中的参数都不需要归一化

折射原理

在这里插入图片描述
折射现象的原理为光线与物体交互后进入物体内部并发生方向改变,最终进入摄像机,光线改变的角度与光线前后所处介质的折射率有关:
在这里插入图片描述
可见折射的角度与入射光线的角度成一定比例,我们可以用一个折射率系数 RefractRatio 来概括表示这个比例关系。跟反射一样,在模拟折射现象的时候,也可以从视线方向出发,根据折射率系数逆向求出入射光线方向,然后对表示环境信息的立方体纹理采样。

Unity同样提供了用于计算折射的方法

o.worldRefr = refract(-normalize(_worldView), normalize(o.worldNormal), _RefrcatRatio);

其中:

  • 第一个参数为视线方向,同样需要从摄像机指向交互点
  • 第二个参数为交互点的法线方向
  • 第三个参数为折射率系数
  • 与折射不同,在该方法中,传入的视线方向和法线方向都需要经过归一化处理

一个综合了反射和折射的测试Shader:

Shader "MyShader/Chapter_10/Chapter_10_ReflectAndRefract_Shader"
{Properties{_CubeMap ("Cubemap", Cube) = "_Skybox" {}_Color("Color", Color) = (1, 1, 1, 1)_RefrcatRatio("RefractRatio", Range(0.1, 1)) = 0.5_ReflToRefr("ReflToRefr", Range(0, 1)) = 0_Amount("Amount", Range(0, 1)) = 0}SubShader{Pass{Tags { "LightMode" = "ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float3 worldRefl : TEXCOORD2;float3 worldRefr : TEXCOORD3;SHADOW_COORDS(4)};samplerCUBE _CubeMap;fixed4 _Color;fixed _RefrcatRatio;fixed _ReflToRefr;fixed _Amount;v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);float3 _worldView = WorldSpaceViewDir(v.vertex);o.worldRefl = reflect(-_worldView, o.worldNormal);o.worldRefr = refract(-normalize(_worldView), normalize(o.worldNormal), _RefrcatRatio);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;TRANSFER_SHADOW(o);return o;}fixed4 frag(v2f i) : SV_Target{fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;float3 _worldNomal = normalize(i.worldNormal);float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);fixed3 _diffuse = _LightColor0.rgb * _Color.xyz * saturate(dot(_worldNomal, _worldLight));fixed3 _reflColor = texCUBE(_CubeMap, i.worldRefl).rgb;fixed3 _refrColor = texCUBE(_CubeMap, i.worldRefr).rgb;fixed3 _sampler = lerp(_reflColor, _refrColor, _ReflToRefr);UNITY_LIGHT_ATTENUATION(_atten, i, i.worldPos);fixed3 _finalColor = _ambient + lerp(_diffuse, _sampler, _Amount) * _atten;return fixed4(_finalColor, 1);}ENDCG}}
}

效果如下:
在这里插入图片描述

在这里插入图片描述

3.3 菲涅尔反射

菲涅尔反射描述了一种光学现象——当光线照射到物体上时,一部分被反射,一部分进入物体内部,而被反射的光线与入射光存在一定的比率关系。

一个现实中的例子就是当我们看水面时会发现,近处的部分可以透过水面看到水底,而远处的部分就只能看到反射。

在菲涅尔反射现象中,反射光线与入射光线的比率可以通过菲涅尔等式获得。一个描述真实世界菲涅尔反射的等式是非常复杂的,在渲染中往往通过一些公式进行近似模拟,Schlick菲涅尔近似等式就是其中常用的一个等式:
FSchlick(v, n) = F0 + (1 + F0)(1 - v · n)5
其中 v为视线方向,n为法线方向,F0为反射系数,用于控制菲涅尔反射的强度。

一个加入了菲涅尔反射的测试Shader:

Shader "MyShader/Chapter_10/Chapter_10_Fresnel_Shader"
{Properties{_CubeMap ("Cubemap", Cube) = "_Skybox" {}_Color("Color", Color) = (1, 1, 1, 1)_FresnelScale("FresnelToRefl", Range(0, 1)) = 0_Pow("Pow", Range(1, 50)) = 5}SubShader{Pass{Tags { "LightMode" = "ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"struct a2v{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 pos : SV_POSITION;float3 worldNormal : TEXCOORD0;float3 worldPos : TEXCOORD1;float3 worldRefl : TEXCOORD2;float3 worldView : TEXCOORD3;SHADOW_COORDS(4)};samplerCUBE _CubeMap;fixed4 _Color;fixed _FresnelScale;half _Pow;v2f vert(a2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldView = WorldSpaceViewDir(v.vertex);o.worldRefl = reflect(-o.worldView, o.worldNormal);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;TRANSFER_SHADOW(o);return o;}fixed4 frag(v2f i) : SV_Target{fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;float3 _worldNomal = normalize(i.worldNormal);float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);fixed3 _diffuse = _LightColor0.rgb * _Color.xyz * saturate(dot(_worldNomal, _worldLight));fixed3 _reflColor = texCUBE(_CubeMap, i.worldRefl).rgb;float3 _worldView = normalize(i.worldView);fixed _fresnel = _FresnelScale + (1 - _FresnelScale) * pow(1 - dot(_worldView, _worldNomal), _Pow);UNITY_LIGHT_ATTENUATION(_atten, i, i.worldPos);fixed3 _finalColor = _ambient + lerp(_diffuse, _reflColor, saturate(_fresnel)) * _atten;return fixed4(_finalColor, 1);}ENDCG}}
}

效果如下:
在这里插入图片描述

另外,也可以利用这个现象做简单的外轮廓显示:
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 音视频开发—音频相关概念:数模转换、PCM数据与WAV文件详解
  • 一、Nginx详解和安装
  • 翻译《The Old New Thing》- How do I mark a shortcut file as requiring elevation?
  • 微信小程序毕业设计-跑腿系统项目开发实战(附源码+演示视频+LW)
  • 青蛙跳台阶问题
  • [备忘.经验总结]特例问题通用问题,分而治之
  • 手机App收集个人信息,用户是否有权拒绝?
  • 所有平台均可发布,矩阵操作+工具+素材,自动混剪8090后怀旧视频
  • 牛客循环5.27
  • EPBU/MOBI转PDF
  • fastadmin二次开发 修改默认的前端弹出样式
  • JVM 常见配置参数
  • 汇聚荣科技有限公司怎么样?
  • 人工智能应用层岗位—AI项目经理/AI产品经理
  • 【MySQL】MySQL的安装和基本概念
  • 77. Combinations
  • css属性的继承、初识值、计算值、当前值、应用值
  • IndexedDB
  • java2019面试题北京
  • Java面向对象及其三大特征
  • MQ框架的比较
  • Node + FFmpeg 实现Canvas动画导出视频
  • PAT A1092
  • Sequelize 中文文档 v4 - Getting started - 入门
  • SQLServer插入数据
  • Vue ES6 Jade Scss Webpack Gulp
  • Windows Containers 大冒险: 容器网络
  • 关于 Cirru Editor 存储格式
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 前端攻城师
  • 提醒我喝水chrome插件开发指南
  • 因为阿里,他们成了“杭漂”
  • 用Visual Studio开发以太坊智能合约
  • 优化 Vue 项目编译文件大小
  • - 转 Ext2.0 form使用实例
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​2020 年大前端技术趋势解读
  • # windows 安装 mysql 显示 no packages found 解决方法
  • #android不同版本废弃api,新api。
  • #QT(智能家居界面-界面切换)
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (20050108)又读《平凡的世界》
  • (2024,RWKV-5/6,RNN,矩阵值注意力状态,数据依赖线性插值,LoRA,多语言分词器)Eagle 和 Finch
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (C++17) std算法之执行策略 execution
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (生成器)yield与(迭代器)generator
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net 调用php,php 调用.net com组件 --
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .sh 的运行
  • .vimrc php,修改home目录下的.vimrc文件,vim配置php高亮显示
  • @EventListener注解使用说明