【Unity Shader入门精要 第7章】基础纹理(一)

news2024/11/19 0:23:37

1. 纹理映射

每一张纹理可以看作拥有一个属于自己的2D坐标空间,其横轴用U表示,纵轴用V表示,因此也称为UV坐标空间。

UV空间的坐标范围为[0,0]到[1,1],在Unity中,UV空间也是从左下到右上,即纹理的左下角对应的UV坐标为[0,0],纹理右上角对应的UV坐标为[1,1]

在美术导出模型资源时,会通过UV展开将模型每个顶点对应的UV坐标存储到顶点信息中。渲染时通过顶点(或片元)的UV坐标映射到纹理上的某一点,这样就可以通过采样每一个顶点(或片元)对应的纹理上的颜色将纹理显示出来。

2. 纹理基础设置

以Unity 2021为例,一张纹理的Inspector面板大致如下
在这里插入图片描述
其中红框部分是本节主要关注的部分

  • Generate Mip Maps

    • 勾选后会提前进行滤波,生成不同采样等级的Mip Map纹理
    • 渲染时根据屏幕像素对应的纹理范围从对应等级的Mip Map纹理中进行采样
    • 由于生成了新的纹理,因此会占用更多的内存空间
  • Wrap Mode
    UV坐标空间自身的范围虽然只有0到1,但实际采样时,顶点映射的UV坐标可能超过这个范围,WrapMode属性决定了采样的UV坐标超过[0, 1]范围时的处理方式

    • Repeat:重复采样,即超过范围时舍弃整数部分只按小数部分采样,比如(1.1, 1.2)实际会按照(0.1, 0.2)采样
    • Clamp:超过[0, 1]的部分延用相应边缘的值(0或者1)
  • Filter Mode
    决定纹理采样的滤波方式

    • Point:就近点采样
    • Bilinear:双线性插值
    • Trilinear:三线性插值

关于MipMap和滤波的原理可以参照【Unity Shader入门精要 第7章】基础纹理补充内容:MipMap原理

3. 在Shader中使用纹理

  • 创建Chapter_7_BaseTexture_Mat 作为测试材质
  • 创建Chapter_7_BaseTexture作为测试shader,并赋给Chapter_7_BaseTexture_Mat 材质
  • 场景中创建胶囊体,将Chapter_7_BaseTexture_Mat 材质赋给胶囊体
  • 场景中添加一盏平行光,并调整平行光角度

在Shader中,我们通过对纹理采样得到的颜色来代替之前固定的漫反射颜色,并在片元着色器中进行逐像素的光照计算,得到最终的效果:

  • 在Properties中添加属性 _MainTex(“MainTex”, 2D) = “white”{} 用于设置纹理,此时选中胶囊体可在Inspector面板中看到如下纹理设置选项
    在这里插入图片描述
    • Tiling:平铺数量,可以理解为反向的缩放度,值越大单位空间平铺数量越多,相当于对纹理缩小,反之相当与放大
    • Offset:偏移
  • 在CG代码段中添加与属性同名的变量 _MainTex来使用面板中设置的纹理,其类型为 sampler2D
  • 顶点着色器中输入的uv坐标是模型导出时顶点对应的uv坐标,为了能够得到正确的纹理采样结果,除了考虑顶点自身的uv坐标外,还需要考虑面板中对要采样的纹理设置的缩放和偏移,这部分信息可通过在Shader中声明 XXX_ST 的变量获得,其中XXX为纹理属性的名字,当前Shader中也就是 _MainTex_ST,该变量类型为float4,其中xy表示缩放,zw表示平移
  • 通过 input.uv.xy * _MainTex_ST.xy + _MainTex_ST.zw 即可得到实际采样使用的uv坐标,也可以通过内置的TRANSFORM_TEX(_MainTex, input.uv)方法获得,此时引擎会自己使用名为 _MainTex_ST 的变量进行上述计算,因此即使使用内置方法计算uv也需要声明_ST变量
  • 最后在着色器中通过 tex2D(_MainTex, i.uv) 方法即可对纹理进行采样获得颜色,我们以该颜色作为物体自身的漫反射颜色系数带入漫反射光照计算

Shader如下:

Shader "MyShader/Chapter_7/Chapter_7_BaseTexture"
{
    Properties
    {
        _MainTex("MainTex", 2D) = "white"{}
        _Specular("Specular", Color) = (1,1,1,1)
        _Gloss("Gloss", Range(1.0, 256.0)) = 10
    }
    
    SubShader
    {
        Pass
        {
            Tags {"LightMode" = "ForwardBase"}
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"
            
            struct a2v
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 uv : TEXCOORD0;
            };
            
            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 worldPos : TEXCOORD1;
                float3 worldNormal : TEXCOORD2;
            };
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 _Specular;
            half _Gloss;
            
            v2f vert(a2v i)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(i.vertex);
                o.worldPos = mul(unity_ObjectToWorld, i.vertex);
                o.worldNormal = mul(i.normal, (float3x3)unity_WorldToObject);
                o.uv = TRANSFORM_TEX(i.uv, _MainTex);
                return o;
            }
            
            fixed4 frag(v2f i) : SV_Target
            {
                fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
                
                float3 _worldNormal = normalize(i.worldNormal);
                float3 _worldLight = normalize(_WorldSpaceLightPos0.xyz);
                fixed4 _albedo = tex2D(_MainTex, i.uv);
                fixed3 _diffuse = _LightColor0.rgb * _albedo.rgb * saturate(dot(_worldNormal, _worldLight));
                
                float3 _worldRefl = normalize(reflect(-_worldLight, _worldNormal));
                float3 _worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);
                fixed3 _specular = _LightColor0.rgb * _Specular.xyz * pow( saturate(dot(_worldRefl, _worldView)),_Gloss);
                
                return fixed4(_ambient + _diffuse + _specular, 1);
            }
            
            ENDCG
        }
    
    }

}

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

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

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

相关文章

OSPF工作过程

1.OSPF的数据包 hello包——周期性的发现,建立以及保活邻居关系 hello时间 --- 10S 死亡时间 --- 4倍的hello时间 --- 40S RID --- 1,全网唯一;2,格式统一---- 格式要求和IP地址一样,由32位二进制构成,使用点分十进制…

【科研】常用的实验结果评价指标(2) —— MAE 是什么? !

了解MAE 提示:先说概念,后续再陆续上代码 文章目录 了解MAE前言一、MAE 基本概念1. MAE 是什么?2. MAE 的起源3. MAE 的计算公式 二、MAE的适用场景是什么?三、MAE 的劣势,或 不适用于那些场景或者数据?四、…

常见磁盘分区问题

给磁盘分区有几个主要的原因: 组织和管理数据:分区可以帮助用户更好地组织和管理数据。例如,你可以在一个分区上安装操作系统,而在另一个分区上存储个人文件。这样,即使操作系统崩溃或需要重新安装,你的个…

十二生肖Midjourney绘画大挑战:释放你的创意火花

随着AI艺术逐渐进入大众视野,使用Midjourney绘制十二生肖不仅能够激发我们的想象力,还能让我们与传统文化进行一场新式的对话。在这里,我们会逐一提供给你创意满满的绘画提示词,让你的作品别具一格。而且,我们还精选了…

机器学习周报第41周

目录 摘要Abstract一、文献阅读1.1 摘要1.2 背景1.3 论文方法1.3.1 局部特征提取1.3.2 局部特征转换器 (LoFTR) 模块1.3.4 建立粗粒度匹配1.3.5 精细匹配 1.4 损失1.5 实现细节1.6 实验1.6.1 单应性估计1.6.2 相对位姿估计 二、论文代码总结 摘要 本周阅读了一篇特征匹配领域的…

【JS面试题】原型原型链

一、面试真题展示: 1. 如何准确判断一个变量是不是数组? ① 使用instanceof进行判断:a instanceof Array ② 使用Array.isArray()进行判断:Array.isArray(a) 2. 手写一个简易的jQuery,考虑插件和扩展性? …

iOS——消息传递和消息转发

消息传递(Message Passing): 在 iOS 中,消息传递机制是基于 Objective-C 语言的动态性质的一种编程方式。这种机制主要涉及到两个概念:发送者(即消息的发送对象)和接收者(即消息的接…

定时器的理论和使用

文章目录 一、定时器理论1.1定时器创建和使用 二、定时器实践2.1周期触发定时器2.2按键消抖 一、定时器理论 定时器是一种允许在特定时间间隔后或在将来的某个时间点调用回调函数的机制。对于需要周期性任务或延迟执行任务的嵌入式应用程序特别有用。 软件定时器: …

Linux修炼之路之yum和vim编辑器

目录 一:Linux软件包管理器yum 二:vim编辑器 vim的三种模式及互相转换 命令模式 底行模式 三:普通用户的sudo指令(修改信任名单) 接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧 一&#xff1a…

(三)Spring教程——依赖注入与控制反转

Spring框架是为了简化企业级应用开发而创建的,其强大之处在于对Java SE和Java EE开发进行全方位的简化,Spring还对常用的功能进行封装,可以极大地提高Java EE的开发效率。 依赖注入是Spring的核心技术之一,也被称为“控制反转”&a…

听说SOLIDWORKS科研版可以节约研发成本?

近几年来,政府越来越重视科研带动产业,绩效优良的产业技术研究院对于国家和地区的学术成果转化、技术创新、产业发展等具有不可忽视的促进和带动作用。研究院会承担众多新产业的基础研究工作,而常规的基础研究需要长期的积累,每个…

【C++】string|迭代器iterator|getline|find

目录 ​编辑 string 1.string与char* 的区别 2.string的使用 字符串遍历 利用迭代器遍历 范围for遍历 反向迭代器 字符串capacity 字符串插入操作 push_back函数 append函数 运算符 ​编辑 insert函数 substr函数 字符串查找函数 find函数 rfind函数 …

果蔬经营平台|基于SSM+vue的果蔬经营平台系统的设计与实现(源码+数据库+文档)

果蔬经营平台系统 目录 基于SSM+vue的果蔬经营平台系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2管理员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介…

过滤器Filter和拦截器Interceptor实现登录校验

一.过滤器 Filter过滤器可以把对资源的请求拦截下来,从而实现一些登录验证的功能 1.Filter的快速入门 1.定义Filter:定义一个类,实现Filter接口,并重写其所有方法。2.配置 public class dofilter implements Filter {Override //初始化只…

IT技术产品:开发者极为重要的思维习惯

1、特色内容预告 1、我用敏捷开发思维,提高工作效率。 2、我用代码批判思维,逐渐让自己的作品变得无可挑剔。 3、我是一个顶级程序员,是哪些重要的专业习惯,让我如此优秀? 2、可以免费获取到的IT资源 1、《软件工程&a…

深度学习入门到放弃系列 - 阿里云人工智能平台PAI部署开源大模型chatglm3

通过深度学习入门到放弃系列 - 魔搭社区完成开源大模型部署调用 ,大概掌握了开源模型的部署调用,但是魔搭社区有一个弊端,关闭实例后数据基本上就丢了,本地的电脑无法满足大模型的配置,就需要去租用一些高性价比的GPU机…

地平线X3开发板Intel Realsense深度相机调试记录

1. 预编译包 编译这个SDK花费了5.6个小时,为了方便各位后续使用, 各位可以直接下载编译好的文件,包含C和Python的库,相关文件已经上传至百度云(提取码:awe4 )。 在提供的这些文件中&#xf…

【教程】Linux/Jetson 安装X11VNC同步屏幕内容

转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,请不吝给个[点赞、收藏、关注]哦~ 目录 背景说明 实际效果 安装步骤 安装 x11vnc 配置 x11vnc 配置 x11vnc 作为系统服务 使用 VNC 客户端连接 背景说明 通常vnc-server是单…

基于Java的俄罗斯方块游戏的设计与实现

关于俄罗斯方块项目源码.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89300281 基于Java的俄罗斯方块游戏的设计与实现 摘 要 俄罗斯方块是一款风靡全球,从一开始到现在都一直经久不衰的电脑、手机、掌上游戏机产品,是一款游戏规则简单…

[MRCTF2020]PixelShooter

是个安卓游戏题 re手肯定不会去玩游戏,先jadx分析一波 没有什么关键信息,但找到了一个unity类,想到apk也可以解压缩得到 .so 或者 Assembly-CSharp.dll 故又在dnspy分析一下 看了半天没有和flag有关信息,看wp: Asse…