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

1. 渐变纹理

另外一种对于纹理的使用方式是通过渐变纹理为物体提供漫反射光照效果。

在这里插入图片描述
顾名思义,渐变纹理本身就是一张颜色渐变(可以是连续渐变,也可能是突变)的图片,这个渐变的过程模拟的就是光源从不同的角度照射物体的过程,因此对渐变纹理的采样通关不关心目标像素的位置信息,只关心光照角度。

通常来讲,渐变纹理都是左右不可以互相拼接的(像上图这样)。假设我们期望的采样点在纹理的最右侧(白色),但考虑到采样坐标的精度问题,实际的采样坐标可能为1.001,如果渐变纹理的 Wrap Mode 选择的是 Repeat,就会按照 0.001 进行采样,于是就会从渐变纹理的最左边进行采样(深红),从而导致一片白色中突然出现一点深红。因此,为了避免这种问题,渐变纹理的 Wrap Mode 需要选择为 Clamp。

在这里插入图片描述
如上图所示,我们在Shader中为物体设置了一张 MainTex 用于提供物体的基本颜色,然后设置了一张RampTex,用于根据光照角度提供漫反射颜色。

Shader如下:

Shader "MyShader/Chapter_7/Chapter_7_RampTexture"
{
    Properties
    {
        _MainTex("MainTex", 2D) = "white"{}
        _RampTex("RampTex", 2D) = ""{}
        _Specular("Specular", Color) = (1,1,1,1)
        _Gloss("Gloss", Range(1.0, 256.0)) = 16
    }
    
    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 worldNormal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
            };
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _RampTex;
            fixed4 _Specular;
            half _Gloss;
            
            v2f vert(a2v v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.worldNormal = mul(v.normal, unity_WorldToObject);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                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 _albode = tex2D(_MainTex, i.uv);
                float _halfLambert = 0.5 * dot(_worldNormal, _worldLight) + 0.5;
                fixed4 _ramp = tex2D(_RampTex, _halfLambert.rr);
                fixed3 _diffuse = _LightColor0.rgb * _albode.xyz * _ramp.rgb;
                
                float3 _worldView = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);
                float3 _h = normalize(_worldView + _worldLight);
                fixed3 _specular = _LightColor0.rgb * _Specular.xyz * pow(saturate(dot(_worldNormal, _h)) , _Gloss);
                
                return fixed4(_ambient + _diffuse + _specular, 1);
            }
            
            ENDCG
        }
    
    }

}

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

2.遮罩纹理

所谓遮罩纹理,其实就是向Shader提供额外参数控制的一种手段。由于通过纹理采样可以覆盖到物体表面的每一个像素,因此我们可以通过将参数存储到纹理中为物体表面每一个像素提供更精细的控制。

比如在进行高光反射计算时,如果我们希望物体表面某些地方的高光强度更高,某些地方的高光强度更低,就可以将这个调整高光强度的系数存到一张纹理当中,在计算高光反射的最后乘以从纹理中采样得到的控制系数。

再比如我们在Shader 的 Properties 中设置了某些属性可以供使用者调整,但这个属性的值是对整个Shader生效的,或者说是对物体表面每一个像素生效的,就像之前Shader中常用的 _Gloss 属性,用于控制高光亮斑的大小,如果我们希望物体不同部分在计算高光反射时,分别按照不同的 _Gloss 值进行计算,就可以将需要的 _Gloss 值存到纹理中,在着色器中采样获得。

在这里插入图片描述

这个例子中,通过一张遮罩纹理的R通道为漫反射提供了一个额外的强度系数。

Shader如下:

Shader "MyShader/Chapter_7/Chapter_7_MaskTexture"
{
    Properties
    {
        _MainTex("MainTex", 2D) = "white"{}
        _BumpTex("BumpTex", 2D) = "bump"{}
        _MaskTex("MaskTex", 2D) = ""{}
        _MaskScale("MaskScale", float) = 5
        _Specular("Specular", Color) = (1,1,1,1)
        _Gloss("Gloss", Range(1.0, 256.0)) = 16
    }
    
    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;
                float4 tangent : TANGENT;
                float2 uv : TEXCOORD0;
            };
            
            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 tangentView : TEXCOORD1;
                float3 tangentLight : TEXCOORD2;
            };
            
            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _BumpTex;
            sampler2D _MaskTex;
            half _MaskScale;
            fixed4 _Specular;
            half _Gloss;
            
            v2f vert(a2v v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                
                TANGENT_SPACE_ROTATION;
                o.tangentView = mul(rotation, ObjSpaceViewDir(v.vertex));
                o.tangentLight = mul(rotation, ObjSpaceLightDir(v.vertex));
                return o;
            }
            
            fixed4 frag(v2f i) : SV_Target
            {
                
                fixed3 _ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
                
                float3 _tangentLight = normalize(i.tangentLight);
                fixed4 _packedNormal = tex2D(_BumpTex, i.uv);
                float3 _tangentNormal = UnpackNormal(_packedNormal) ;
                _tangentNormal.z = sqrt(1.0 - dot(_tangentNormal.xy, _tangentNormal.xy));
                fixed4 _albode = tex2D(_MainTex, i.uv);
                float _diffuseFix = tex2D(_MaskTex, i.uv).r * _MaskScale;
                fixed3 _diffuse = _LightColor0.rgb * _albode.xyz * saturate(dot(_tangentNormal, _tangentLight)) * _diffuseFix;
                
                float3 _tangentView = normalize(i.tangentView);
                float3 _h = normalize(_tangentView + _tangentLight);
                fixed3 _specular = _LightColor0.rgb * _Specular.xyz * pow(saturate(dot(_tangentNormal, _h)) , _Gloss);
                
                return fixed4(_ambient + _diffuse + _specular, 1);
            }
            
            ENDCG
        }
    
    }

}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python代码:七、小数化整数

1、题目 日常生活中我们会遇到很多小数,但是有的人不喜欢小数,因此会用四舍五入的方式将其去掉。在Python中我们更加简单,可以利用强制类型转换将小数转变成整数,请你试一试。 2、代码 import sysn float(input()) print(int(…

JUnit5超时处理

测试过程中如果某条测试用例执行过程中阻塞,就会发生超时问题: 阻塞其他用例的执行对于某些用例,如果用例执行时间过长,那么本身就是bug 使用场景: 使用JUnit5自带的超时处理,当测试用例执行时间超过执行…

mybatis-plus-ui代码生成器

mybatis-plus-generator-ui 提供交互式的Web UI用于生成兼容mybatis-plus框架的相关功能代码,包括Entity,Mapper,Mapper.xml,Service,Controller等 ,可以自定义模板以及各类输出参数,也可通过SQL查询语句直接生成代码。 使用方法 引入mave…

邮箱API发信有哪些限制?如何设置API接口?

腾讯云邮箱API与AokSend相比,有哪些优势和特性差异? 使用邮箱API发信并非毫无限制,如何正确设置API接口并选择合适的服务商,成为企业关注的焦点。接下来,Aok将探讨邮箱API发信的限制、API接口的设置方法,以…

图文并茂:解析Spring Boot Controller返回图片的三种方式

欢迎来到我的博客,代码的世界里,每一行都是一个故事 图文并茂:解析Spring Boot Controller返回图片的三种方式 前言使用Base64编码返回图片使用byte数组返回图片使用Resource对象返回图片图片格式转换与性能对比 前言 在互联网的世界里&…

LiveGBS流媒体平台GB/T28181用户手册-国标设备:设备列表、通道列表、流传输模式修改、查看通道播放、设备录像、在线状态、流量统计

LiveGBS流媒体平台GB/T28181用户手册-国标设备:设备列表、通道列表、流传输模式修改、查看通道播放、设备录像、在线状态、流量统计 1、国标设备1.1、设备列表1.1.1、查看通道1.1.2、更新通道1.1.3、编辑1.1.3、导入导出1.1.4、条件检索1.1.5、设备状态记录1.1.6、设备流量统计…

太平洋产险海南分公司提醒您:高温来袭!新能源车该如何正确充电?

据不完全统计 近三年来 7-8月一直是电动汽车烧车事故的高发期 毕竟夏季的高温影响着动力电池的状态新能源汽车为什么会自燃? 小保替你们找到了央视的官方回答! 原来 新能源汽车比传统燃油车多了一套电池系统 电解液为可燃物 当热量聚集达到燃点却没…

【错题集-编程题】主持人调度(二)(贪心 + 优先级队列)

牛客对应题目链接:主持人调度(二)_牛客题霸_牛客网 (nowcoder.com) 一、分析题目 把区间按照左端点排序,然后搞个堆: 先把第⼀个区间的右端点加⼊到堆中。遍历后⾯的区间,分情况讨论:&#xff…

双向链表结构

1.双向链表定义 双向链表也叫双链表&#xff0c;是链表的一种&#xff0c;它的每个数据节点中都有两个指针&#xff0c;分别指向直接前驱和直接后继。 2.实现双向链表 2.1创建双向链表类 /*** 基于双向链表实现元素存取的容器* param <E>*/ public class MyDoubleLinked…

设计模式六大原则之依赖倒置原则

文章目录 概念逻辑关系 小结 概念 依赖倒置原则指在设计代码架构时&#xff0c;高层模块不应该依赖底层模块&#xff0c;二者都应该依赖抽象。抽象不应该依赖于细节&#xff0c;细节应该依赖于抽象。 逻辑关系 如上图所示&#xff0c;逻辑应该就是这样&#xff0c;高层依赖于…

企业微信网页应用开发(java版)

1、成为开发者 企业微信先认证企业,成为开发者,到开发者中心创建web应用 开发者中心 选择工具 2、创建一个web应用 填写web应用信息 填写配置开发信息 域名地址先填一样的,填好后创建应用 3、配置可信域名 点击检查可信域名归属 下载可信域名验证文件 将下好的文件放到…

[案例分享] 产品需求跨职能团队协作

跨职能团队协作不仅可以激发创新、提升生产力&#xff0c;还能促进业务目标的达成。

最新版★重大升级★神点云连锁餐饮V2独立版点餐系统★公众号/h5/小程序前后端全套源码

提醒&#xff1a; 市场上流通很多老版本代码&#xff0c;一大堆问题且无法保证售后的源码&#xff0c;请各位买家一定要睁大眼睛&#xff0c;以防上当受骗&#xff01;&#xff01;&#xff01;本系统源码全是经本人亲自测试与修复的完好版本&#xff0c;且本人用此版本源码已…

Milvus 快速入门

引言 在本篇文章中&#xff0c;我们将介绍 Milvus 的基本概念&#xff0c;并通过一个简单的示例展示如何在 Milvus 中创建集合、插入向量和执行搜索。最后&#xff0c;我们将概览 Milvus 提供的 API。 一、基本概念 1.1 集合 (Collection) 在 Milvus 中&#xff0c;集合类似…

Ubuntu 24 换国内源及原理 (阿里源)

备份原文件 sudo cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak 编辑源文件 sudo gedit /etc/apt/sources.list.d/ubuntu.sources &#xff08;阿里源&#xff09; Types: deb deb-src URIs: https://mirrors.aliyun.com/ubunt…

学习笔记:使用Ollama项目快速本地化部署Qwen 1.5模型

Ollama简介 Ollama是一个开源框架&#xff0c;专门设计用于在本地运行大型语言模型。它的主要特点是将模型权重、配置和数据捆绑到一个包中&#xff0c;从而优化了设置和配置细节&#xff0c;包括GPU使用情况&#xff0c;简化了在本地运行大型模型的过程。Ollama支持macOS和Li…

【Javaer学习Python】2、Django的MVT设计模式,完成CRUD小应用

系列文章&#xff1a;学习Python Django的MVT设计模式由Model(模型), View(视图) 和Template(模板)三部分组成&#xff0c;分别对应单个app目录下的models.py, views.py和templates文件夹。它们看似与MVC设计模式不太一致&#xff0c;其实本质是相同的&#xff1b; 实践是检验学…

LabVIEW静止无功补偿监控系统

LabVIEW静止无功补偿监控系统 随着电力系统和电力电子技术的快速发展&#xff0c;静止无功补偿器作为提高电网质量和稳定性的关键设备&#xff0c;其监控系统的研发显得非常重要。详细介绍基于LabVIEW的SVC监控系统的设计与实现过程&#xff0c;可为电力系统的优化和电力电子技…

基于Java+SpringBoot+Mybaties-plus+Vue+elememt 驾校管理系统 设计与实现

一.项目介绍 系统角色&#xff1a;管理员、驾校教练、学员 管理员&#xff1a; 个人中心&#xff1a;修改密码以及个人信息修改 学员管理&#xff1a;维护学员信息&#xff0c;维护学员成绩信息 驾校教练管理&#xff1a;驾校教练信息的维护 驾校车辆管理&…

Android 触摸事件分离原理

什么是触摸事件分离&#xff1f; 屏幕上存在多个窗口时&#xff0c;多指触摸的情况下&#xff0c;多个手指的触摸事件可以分给不同的窗口&#xff0c;以下面的图为例&#xff0c;第一个手指按下&#xff0c;window1可以响应这个事件&#xff0c;第二个手指按下&#xff08;第一…