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

news2024/11/16 7:43:43

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.coloradmin.cn/o/1700791.html

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

相关文章

GpuMall智算云:meta-llama/llama3/Llama3

Llama 3 的推出标志着 Meta 基于 Llama 2 架构推出了四个新的开放型大语言模型。这些模型分为两种规模&#xff1a;8B 和 70B 参数&#xff0c;每种规模都提供预训练基础版和指令调优版。所有版本均可在各种消费级硬件上运行&#xff0c;并具有 8000 Token 的上下文长度。 Gpu…

【php开发系统性学习】——thinkphp框架的控制器和视图的精简详细的使用

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

3款简洁个人网站引导页(附带源码)

3款个人网站引导页 效果图及部分源码1.个人页2.引导页3.导航页 领取源码下期更新预报 效果图及部分源码 1.个人页 部分源码 * {margin: 0;padding: 0; }body {background-image: linear-gradient(to left, rgba(255, 0, 149, 0.2), rgba(0, 247, 255, 0.2)), url(../img/bg.j…

265 基于matlab的粒子群优化分数阶灰色预测模型

基于matlab的粒子群优化分数阶灰色预测模型&#xff0c;以误差结果为目标进行预测&#xff0c;输出多个预测结果。并输出迭代曲线。程序已调通&#xff0c;可直接运行。 265 分数阶灰色预测 粒子群优化算法 - 小红书 (xiaohongshu.com)

2024年中国电机工程学会杯数学建模思路 - 案例:最短时间生产计划安排

# 前言 2024电工杯(中国电机工程学会杯)数学建模思路解析 最新思路更新(看最新发布的文章即可): https://blog.csdn.net/dc_sinor/article/details/138726153 最短时间生产计划模型 该模型出现在好几个竞赛赛题上&#xff0c;预测2022今年国赛也会与该模型相关。 1 模型描…

类和对象(上)【有关类的全面学习】【this指针的学习】

类和对象&#xff08;上&#xff09; 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C语言注重过程&#xff1a; C是基于面向对象的&#xff0c;关注的是对象&#xff0…

云手机在软件测试中的作用,为软件测试工程师减负

针对每家企业来说&#xff0c;对于即将上线的软件进行测试这一步骤是不可忽视的&#xff0c;这决定产品上线后的质量和口碑&#xff1b; 传统的的真机测试可能面临设备大量的采购&#xff0c;管理和维护的成本提高&#xff0c;现在不少企业都开始用云手机来代替真机&#xff0…

深圳比创达电子EMC|EMC电磁兼容性行业:挑战与机遇并存

随着电子技术的迅猛发展&#xff0c;电磁兼容性&#xff08;EMC&#xff09;已成为各行各业不可忽视的关键问题。EMC是指设备或系统在其电磁环境中能正常工作且不对该环境中任何事物构成不能承受的电磁骚扰的能力。 一、EMC电磁兼容性行业的现状 EMC电磁兼容性行业作为电子技…

基于 Spring Boot 博客系统开发(十一)

基于 Spring Boot 博客系统开发&#xff08;十一&#xff09; 本系统是简易的个人博客系统开发&#xff0c;为了更加熟练地掌握 SprIng Boot 框架及相关技术的使用。&#x1f33f;&#x1f33f;&#x1f33f; 基于 Spring Boot 博客系统开发&#xff08;十&#xff09;&#x…

YoloV8实战:复现基于多任务的YoloV8方案

摘要 自动驾驶中多任务学习,特别是通过设计一种自适应、实时且轻量级的模型来同时处理目标检测、可行驶区域分割和车道线分割,是一种非常有用的研究方法,其中最出名的当属YOLOP模型。然后,YoloP在实时性上并没有得到满足,本文复现基于YoloV8的对任务方案,并在BDD100K数据…

深入解析与实现:变分自编码器(VAE)完整代码详解

VAE理论上一篇已经详细讲完了&#xff0c;虽然VAE已经是过去的东西了&#xff0c;但是它对后面强大的生成模型是很有指导意义的。接下来&#xff0c;我们简单实现一下其代码吧。 1 VAE在minist数据集上的实现 完整的代码如下&#xff0c;没有什么特别好讲的。 import cv2 im…

【计算机毕业设计】安卓054基于Android校园助手

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

渗透测试的测试流程与注意事项

软件测试流程 渗透测试是一种重要的软件测试技术&#xff0c;通过对系统进行模拟攻击和漏洞评估&#xff0c;帮助组织发现和修复潜在的安全风险&#xff0c;提高系统的安全性和稳定性。在进行渗透测试时&#xff0c;需要注意合法授权、技术能力、安全意识和报告质量等方面的问…

基于springboot实现华府便利店信息管理系统项目【项目源码+论文说明】

基于springboot实现华府便利店信息管理系统演示 摘要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本华府便利店信息管理系统就是在这样的大环境下诞生&#xff…

VMware安装保姆教程、Docker安装/依赖安装缓慢等问题

常见问题前置: 1、docker依赖安装缓慢,没有走设置的资源库:解决安装docker-ce过慢 Operation too slow. Less than 1000 bytes/sec transferred the last 30 seconds‘) 在添加阿里云镜像后安装依旧慢: yum-config-manager --add-repo http://mirrors.aliyun.com/docker…

移动云:连接未来的智慧之旅

随着数字化转型的加速&#xff0c;云服务在各行各业中的应用越来越广泛。移动云不仅提供了灵活的计算和存储资源&#xff0c;还通过创新的技术手段&#xff0c;为企业和开发者解决了许多实际问题。在这个变革的大背景下&#xff0c;移动云服务作为中国移动倾力打造的云业务品牌…

计算机网络6——应用层5 DHCP/SNMP

文章目录 一、动态主机配置协议 DHCP二、简单网络管理协议 SNMP1、网络管理的基本概念2、管理信息结构SMI1&#xff09;被管对象的命名2&#xff09;被管对象的数据类型3&#xff09;编码方法 3、管理信息库 MIB4、SNMP的协议数据单元和报文 一、动态主机配置协议 DHCP 为了把…

产品经理-交互说明撰写(八)

1. 交互说明 交互说明可以看做是交互设计师或者产品经理输出的最核心的”产品“交互说明面向的”用户“是下游的同事 ⇒ UI设计师、开发工程师、测试工程师 2. 基本交互形式 2.1 页面交互 2.2 元素控件交互 3. 交互说明主要包括以下3个维度 3.1 页面流程&#xff08;页面之…

unity制作app(10)--统一字体

1.载入字体&#xff0c;微软雅黑&#xff0c;需要3分钟左右 加载进来3个 2.font文件夹下创建一个txt&#xff0c;内部的内容如下&#xff1a; &#xfeff;啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏…

linux系统更改SSH端口号配置

1.编写sshd.config cd /etc/ssh sudo cp sshd_config sshd_config.bak vim sshd_config2.重启服务 systemctl restart sshd 结束&#xff01;&#xff01;