【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}}
}

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/18387.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【NumPy】深入理解NumPy的dot函数:矩阵乘法与点积运算详解

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

教育小程序的性能优化:从前端到后端的综合提升策略

随着教育小程序的普及&#xff0c;其性能直接影响用户体验和教学效果。本文将从前端到后端&#xff0c;详细探讨教育小程序的性能优化策略&#xff0c;帮助开发者打造高效、流畅的教育应用。 一、前端性能优化策略 代码优化 减少HTTP请求&#xff1a;合并CSS、JavaScript文件…

MagicPose4D:解锁AI驱动的3D模型动作新纪元

在当今快速发展的数字内容创作领域,MagicPose4D正以其革命性的技术颠覆传统动画制作流程,成为创作者手中的魔法棒。这款先进的框架不仅仅是一款工具,更是通往无限创意的一扇门,它使得为3D模型赋予生动、自然的动作变得前所未有的简单和高效。下面,让我们深入探索MagicPose…

@EnableConfigurationProperties源码解析

前言 EnableConfigurationProperties注解的使用&#xff0c;请移步相关博文&#xff1a;EnableConfigurationProperties注解使用 前置知识 Import注解作用简述 注入的类一般继承 ImportSelector 或者 ImportBeanDefinitionRegistrar 接口 继承ImportSelector接口&#xff…

领域驱动设计(DDD)学习笔记之:战术设计

聚合&#xff08;Aggregates&#xff09; 聚合根的定义和职责 在领域驱动设计&#xff08;DDD&#xff09;中&#xff0c;聚合&#xff08;Aggregate&#xff09;是由一个或多个实体和值对象组合而成的业务模型。聚合根&#xff08;Aggregate Root&#xff09;是聚合的入口点…

Day06-Mybatis

1. Mybatis介绍 2. Mybatis连接数据库并返回数据事例 连接oracle数据的设置方式 spring.application.namespringboot-mybatis spring.datasource.driver-class-nameoracle.jdbc.OracleDriver spring.datasource.urljdbc:oracle:thin:192.168.100.66:1521:orcl spring.datasour…

adb的常见操作和命令

最近学习adb的时候&#xff0c;整理了一些adb的使用场景&#xff0c;如&#xff1a;adb与设备交互&#xff0c;adb的安装、卸载&#xff0c;adb命令启动&#xff0c;通过命令清除缓存&#xff0c;文件传输和日志操作。 adb的两大作用&#xff1a;在app测试的时候可以提供监控日…

GB-T 43698-2024 网络安全技术 软件供应链安全要求

编写背景 随着信息技术的快速发展&#xff0c;软件供应链安全问题日益凸显。软件供应链是指软件从开发、分发到最终用户使用过程中涉及的所有环节。在这个过程中&#xff0c;任何一个环节的安全问题都可能影响到整个供应链的安全。GB-T 43698-2024《网络安全技术 软件供应链安…

【头歌】计算机网络DHCP服务器配置第二关access口配置答案

头歌计算机网络DHCP服务器配置第二关access口配置操作步骤 任务描述 本关任务&#xff1a;创建 vlan &#xff0c;并且将与 pc 机相连接口划分 vlan 。 操作要求 在第一关的拓扑图的基础上&#xff0c;配置交换机&#xff0c;具体要求如下&#xff1a; 1、在特权模式下进入 vla…

Python学习备份

2023年1月19日15:25:16 1. vsIDE编程python python路径&#xff1a;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python37_86 python_pip路径(可添加到环境变量)&#xff1a;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python37_86\Scripts 第三方库路…

Flutter 中的 CupertinoTextSelectionToolbar 小部件:全面指南

Flutter 中的 CupertinoTextSelectionToolbar 小部件&#xff1a;全面指南 在 Flutter 中&#xff0c;CupertinoTextSelectionToolbar 是一个专门用于 iOS 风格的文本选择工具栏的小部件。它提供了一组与 iOS 系统相一致的文本操作控件&#xff0c;如复制、粘贴等。这个工具栏…

Docker 快速更改容器的重启策略(Restart Policies)以及重启策略详解

目录 1. 使用 docker update 命令2. 在启动容器时指定重启策略3. 在 Docker Compose 文件中指定重启策略4. 总结 官方文档&#xff1a;Start containers automatically 1. 使用 docker update 命令 Docker 提供了 docker update 命令&#xff0c;可以在容器运行时更改其重启策…

python 队列生产者消费者爬虫

当使用Python编写一个基于队列的生产者消费者爬虫时&#xff0c;我们通常会使用threading或multiprocessing模块来处理并发&#xff0c;并使用queue模块来管理数据队列。下面是一个详细的示例&#xff0c;该示例展示了如何使用生产者线程生成URL&#xff0c;消费者线程爬取这些…

循序渐进Docker Compose

文章目录 1.概述1.1 Docker Compose 定义1.2 Docker Compose背景1.3 Docker Compose核心概念 2.安装2.1 Official Repos2.2 Manual Installation2.3 v1.x 兼容性 3. YAML 配置说明3.1 Services3.2 Volumes & Networks 4. 解析 Service4.1 Pulling一个Image4.2 Building一个…

Unknown module(s) in QT: texttospeech

目录 Qt TextToSpeech Engines tts测试代码&#xff1a; pro配置&#xff1a; 报错&#xff1a;connection to speech-dispatcher failed 不支持中文播报 1. 安装 espeak-ng 和中文语音库 2. 配置 Speech Dispatcher 使用 espeak-ng 3. 配置 espeak-ng 支持中文 4. 重…

Java基础:面向对象(二)

Java基础&#xff1a;面向对象&#xff08;二&#xff09; 文章目录 Java基础&#xff1a;面向对象&#xff08;二&#xff09;1. 面向对象编程思想2. 类与对象2.1 类2.1.1 类的定义2.1.2 成员变量2.1.3 局部变量 2.2 对象2.2.1 对象的定义2.2.2 对象的使用2.2.3 对象创建的原理…

DataGrip使用ssh连接数据库的操作流程

1 选择数据源种类 2 配置ssh 3 填写host、port和认证方式 我选择的密码方式&#xff0c;也可选择其他方式连接&#xff1a; 本文由博客一文多发平台 OpenWrite 发布&#xff01;

【放球问题】920. 播放列表的数量

本文涉及知识点 【组合数学 隔板法 容斥原理】放球问题 本题同解 【动态规划】【组合数学】【C算法】920播放列表的数量 LeetCode 920. 播放列表的数量 你的音乐播放器里有 n 首不同的歌&#xff0c;在旅途中&#xff0c;你计划听 goal 首歌&#xff08;不一定不同&#x…

Selenium 模拟操作与 pytest 断言的结合使用

Selenium 模拟操作与 pytest 断言的结合使用 在使用 Selenium 进行 UI 自动化测试时&#xff0c;通常会结合 pytest 作为测试框架来编写和执行测试用例。pytest 提供了丰富的断言功能&#xff0c;可以用来验证 Selenium 模拟操作的结果是否符合预期。 断言的基本用法 在 pyt…

释放 OSINT 的力量:在线调查综合指南

开源情报 (OSINT) 是从公开信息中提取有价值见解的艺术。无论您是网络安全专业人士、道德黑客还是情报分析师&#xff0c;OSINT 都能为您提供先进的技术&#xff0c;帮助您筛选海量的数字数据&#xff0c;发现隐藏的真相。 在本文中&#xff0c;我们将深入研究大量的OSINT 资源…