UnityShader学习笔记——基础纹理

embedded/2025/2/8 9:41:42/

——内容源自唐老狮的shader课程


目录

1.概述

2.纹理颜色采样

  3.纹理结合光照

4.凹凸纹理

4.1.概念

4.2.高度纹理贴图

4.3.法线纹理贴图(一般用这个)

4.3.1.概述

4.3.2.读取分量的规则

4.3.3.法线纹理贴图的两种存储方式

1.基于模型空间的法线纹理

2.基于切线空间的法线纹理(这个最常用)

4.4.计算

4.4.1.在切线空间下

4.4.2.在世界空间下

5.渐变纹理

6.遮罩纹理

6.1.计算

6.2.遮罩纹理的RGBA值

7.如有疏漏,还请指出


1.概述

        1.纹理就是图片或者图片集,我们要做的就是从这些纹理中取颜色,即纹理采样

        2.纹理坐标(uv坐标):相当于将模型平铺成一张正方形图片,每一个顶点都有自己的位置,而且uv坐标的的横轴和纵轴是被归一化过的,在0~1的范围内

        3.记录了顶点的uv坐标,并将其传入片元着色器之后,其会被转为片元(像素)的uv坐标(中间的转换靠的是插值计算),这个uv坐标可以在纹理中采集对应位置(像素)的颜色。


2.纹理颜色采样

        首先要知道如何获取uv坐标:将a2v中用TEXCOORD修饰的的变量的xy分量进行变化然后赋给v2f中用TEXCOORD修饰的float2变量即可,这个float2变量就可以在片元着色器中进行纹理采样。

Shader "Study/Lesson29"
{Properties{_MainTex("MainTex", 2D) = ""{}}SubShader{Tags {}pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"//映射对应纹理属性的图片颜色相关数据sampler2D _MainTex;//映射对应纹理属性的 缩放平移(偏移)float4 _MainTex_ST;    //x,y代表缩放,zw代表平移v2f_img vert(appdata_base data){v2f_img v2fData;v2fData.pos = UnityObjectToClipPos(data.vertex);v2fData.uv = data.texcoord.xy;//data.texcoord.xy;  //代表uv坐标//data.texcoord.zw;  //代表一些额外信息//如果没有进行缩放和平移,那么计算后的值是不会发生变化的//先缩放,后平移;//缩放用乘法计算,平移用加法计算v2fData.uv = data.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; //固定写法//或者用内置宏//TRANSFORM_TEX(data.texcoord.xy, _MainTex);return v2fData; }fixed4 frag(v2f_img data) : SV_TARGET{//这里传入的uv是经过插值运算后的,每一个片元都有自己的uv坐标//这样能精准的在贴图中取出颜色fixed4 color = tex2D(_MainTex, data.uv);return color;}ENDCG}}}

        _MainTex_ST是_MainTex(2D类型)自带的,但需要将其声明出来才能用,其代表纹理的缩放与偏移,可以在外部改变

将枪的纹理贴图贴到枪的模型上

      


  3.纹理结合光照

        1.将纹理采样后得到的颜色与声明的漫反射颜色相乘得albedo,

        2.然后用albedo作为漫反射计算中的漫反射颜色。

        3.让环境光与albedo相乘得到新的环境光ambient

        4.用新的环境光代替原来的环境光,漫反射颜色使用albedo计算所得的满反射颜色,进行光照模型的计算

        

Shader "Study/Lesson31"
{Properties{//主要是将单张纹理Shader和Blinn-Phong光照模型逐片元Shader结合_GunTexture("GunTexture", 2D) = ""{}_DiffuseColor("DiffuseColor", Color) = (1, 1, 1, 1)_HighlightColor("HighlightColor", Color) = (1, 1, 1, 1)_Gloss("Gloss", Range(0, 20)) = 1}SubShader{Tags{"LightMode" = "ForwardBase"}Pass{CGPROGRAM//1.纹理颜色需要和漫反射颜色 进行乘法叠加,他们俩共同影响最终的颜色//2.兰伯特光照模型计算时,漫反射材质颜色使用 1 中的叠加颜色计算//3.最后使用的环境光叠加时,环境光变量UNITY_LIGHTMODEL_AMBIENT需要和 1 中颜色进行乘法叠加//  为了避免最终的渲染效果偏灰////其他的计算步骤同Blinn_Phong的逐片元光照实现#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"sampler2D _GunTexture;float4 _GunTexture_ST;fixed4 _DiffuseColor;fixed4 _HighlightColor;float _Gloss;struct v2f{float4 cPos : SV_POSITION;float2 uv : TEXCOORD0;float4 wPos : TEXCOORD1;float3 wNormal : NORMAL;};fixed3 GetLambertColor(float4 wPos, float3 wNormal, fixed3 albedo){float3 normalizedLightDir = normalize(_WorldSpaceLightPos0);fixed3 color = _LightColor0.rgb * albedo * max(dot(wNormal, normalizedLightDir), 0);return color;}fixed3 GetBlinn_PhongColor(float4 wPos, float3 wNormal){float3 normalizedLightDir = normalize(_WorldSpaceLightPos0);float3 normalizedViewDir = normalize(_WorldSpaceCameraPos - wPos);float3 normalizedHalfAngleDir = normalize(normalizedLightDir + normalizedViewDir);fixed3 color = _LightColor0.rgb * _HighlightColor.rgb * pow(max(dot(wNormal, normalizedHalfAngleDir), 0), _Gloss);return color;}v2f vert(appdata_base v){v2f v2fData;v2fData.cPos = UnityObjectToClipPos(v.vertex);v2fData.uv = v.texcoord.xy * _GunTexture_ST.xy + _GunTexture_ST.zw;v2fData.wPos = mul(unity_ObjectToWorld, v.vertex);v2fData.wNormal = UnityObjectToWorldNormal(v.normal);return v2fData;}fixed4 frag(v2f i) : SV_TARGET{////漫反射颜色和纹理颜色叠加,共同决定最后的颜色fixed3 albedo = tex2D(_GunTexture, i.uv).rgb * _DiffuseColor.rgb;//fixed3 lambertColor = GetLambertColor(i.wPos, i.wNormal, albedo);fixed3 blinn_PhongColor = GetBlinn_PhongColor(i.wPos, i.wNormal);fixed3 ambientColor = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;fixed3 finalColor = ambientColor + lambertColor + blinn_PhongColor;return fixed4(finalColor, 1);}ENDCG}}
}
纹理结合光照


4.凹凸纹理

4.1.概念

        使用一张法线纹理来代替模型本身的法线来参与计算,让我们无需增加顶点也能让模型看起来有凹凸效果。

4.2.高度纹理贴图

        一般称为亮度图,存储了模型表面上每个点的高度信息,通常使用灰度图像,不同灰度值代表不同高度,较亮的区域使用较高的点。主要用于模拟物体表面的唯一

        存储规则:图片的某一点的rgb值都是相同的,都表示高度值,a一般为1,高度值范围一般为0~1,0为最低,1为最高

        好处是可以明确知道模型表面的凹凸情况;缺点是无法在shader中直接得到模型顶点的法线信息,需要额外计算,所以很少用

4.3.法线纹理贴图(一般用这个)

4.3.1.概述

        存储了模型表面的每个点的法线方向

        存储规则:图片的rgb值分别存储法线的xyz分量,w用于存储其他信息

        优点是可以直接得到法线信息,缺点是不能直观地看到模型表面地凹凸情况

4.3.2.读取分量的规则

        由于法线xyz分量在[-1, 1]之间,而像素rgb分量范围在[0, 1]之间,所以需要进行转换:

        读取数据时:法线分量 = 像素分量 * 2 - 1

        存储图片时进行逆运算

4.3.3.法线纹理贴图的两种存储方式

1.基于模型空间的法线纹理

        模型空间中自带的法线数据,定义在模型空间中,其取出来直接参与shader计算即可

2.基于切线空间的法线纹理(这个最常用)

        每个顶点都有自己切线空间:

        原点为顶点本身,X轴为顶点切线,Y轴为法线方向,Z轴为XY的叉乘结果,也称副切线

        而没有凹凸感的顶点的坐标为(0, 0, 1),映射到像素上就是蓝色,这就是为什么该纹理总是出现大片蓝色

        这种纹理需要进行转换才能参与计算

        优点:可以用于不同模型,方便处理模型变换,可以复用,可以压缩(只存储两个轴的分量),方便制作uv动画

4.4.计算

4.4.1.在切线空间下

        需要把光照方向,视角方向变换到切线空间下参与计算,好处是计算效率高,计算量小,但对于一些全局效果的表现可能不准确

        1.首先需要计算出由模型空间向切线空间转换的变换矩阵(父到子),该矩阵为3x3矩阵,因为进行的是矢量的变换,无需位移(这里的法线和切线用的模型本身的):

— 切线 —

— 副切线 —

— 法线 —

        2.然后将光照方向和视角方向转换到切线空间参与计算

        3.先对法线纹理进行采样,然后使用UnpackNormal对float4变量进行计算,所得即为切线空间下的法线tNormal。

        4.然后将tNormal的xy分量乘以凹凸度(这个是自定义的),然后进行如下计算(也算是单位化)

tNormal.z = sqrt(1- saturate(dot(tNomral.xy, tNormal.xy)))

         5.进行计算

Shader "Study/TangentNormal"
{Properties{_DiffuseColor("DiffuseColor", Color) = (0, 0, 0, 0)_SpecularColor("HighlightColor", Color) = (0, 0, 0, 0)_Gloss("Gloss", Range(0, 20)) = 5_MyTex("MyTex", 2D) = ""{}//法线纹理_BumpMap("BumpMap", 2D) = ""{}_BumpScale("BumpScale", Range(-1, 1)) = 0}SubShader{Tags { "Lighting" = "ForwardBase" }Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"fixed4 _DiffuseColor;fixed4 _SpecularColor;float _Gloss;sampler2D _MyTex;float4 _MyTex_ST;sampler2D _BumpMap;float4 _BumpMap_ST;float _BumpScale;struct v2f{float4 pos : SV_POSITION;//纹理坐标//float2 uvTex : TEXCOORD0;//法线纹理//float2 uvBump : TEXCOORD1;//将上面俩合成一个,xy代表纹理坐标,zw代表法线纹理float4 uv : TEXCOORD0;float3 tangentSpaceViewDir : TEXCOORD2;float3 tangentSpaceLightDir : TEXCOORD1;};v2f vert(appdata_full v){v2f data;data.pos = UnityObjectToClipPos(v.vertex);data.uv.xy = v.texcoord.xy * _MyTex_ST.xy + _MyTex_ST.zw;data.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;float3 biTangent = cross(normalize(v.tangent), normalize(v.normal)) * v.tangent.w;;float3x3 rotation = float3x3(v.tangent.xyz,biTangent,v.normal);float3 viewDir = normalize(ObjSpaceViewDir(v.vertex));float3 lightDir = normalize(ObjSpaceLightDir(v.vertex));float3 tangentSpaceViewDir = mul(rotation, viewDir);float3 tangentSpaceLightDir = mul(rotation, lightDir);data.tangentSpaceViewDir = tangentSpaceViewDir;data.tangentSpaceLightDir = tangentSpaceLightDir;return data;}fixed4 frag(v2f f) : SV_TARGET{fixed3 texColor = tex2D(_MyTex, f.uv.xy);float4 t_tangentNormal = tex2D(_BumpMap, f.uv.zw);float3 tangentNormal = UnpackNormal(t_tangentNormal);tangentNormal.xy *= _BumpScale;tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));  //也算是一种单位化fixed3 albedo = texColor * _DiffuseColor.rgb;fixed3 lambertColor = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, f.tangentSpaceLightDir));float3 halfAngle = normalize(f.tangentSpaceViewDir + f.tangentSpaceLightDir);fixed3 blinn_PhongColor = _LightColor0.rgb * _SpecularColor.rgb * pow(max(0, dot(tangentNormal, halfAngle)), _Gloss);fixed3 ambientColor = UNITY_LIGHTMODEL_AMBIENT.rgb * albedo;fixed3 finalColor = ambientColor + lambertColor + blinn_PhongColor;return fixed4(finalColor, 1.0);}ENDCG}}
}
切线空间下计算

4.4.2.在世界空间下

        类比上面那个,将法线从切线空间变到世界空间,这时的变换矩阵为:

|         |         |

切线 副切线 法线

|         |         |

 

世界空间下计算

5.渐变纹理

        将半兰伯特后半部分所得0~1的数作为 uv坐标,u和v都是该值。目的是让物体具有一定的卡通风格。

渐变纹理

 


6.遮罩纹理

6.1.计算

        作用是控制某些效果的显示范围,或者说,保护某些区域,使他们免于修改

        1.从遮罩纹理中取出对应的遮罩掩码值(取出来的rgb值都可用,因为这仨都一样)

        2.用该掩码值和我们定义的遮罩系数进行相乘得到遮罩值

        3.用该遮罩值和高光反射计算出的颜色相乘,这样呈现出来的高光反射就会受到高光遮罩纹理和遮罩系数的影响

遮罩纹理

        

6.2.遮罩纹理的RGBA值

        虽然有4个值,但我们只用1个,显而易见的浪费,所以我们可以用它们来存一些别的值,如透明遮罩系数(G),特效遮罩系数(B)等


7.如有疏漏,还请指出


http://www.ppmy.cn/embedded/160510.html

相关文章

feign Api接口中注解问题:not annotated with HTTP method type (ex. GET, POST)

Bug Description 在调用Feign api时,出现如下异常: java.lang.IllegalStateException: Method PayFeignSentinelApi#getPayByOrderNo(String) not annotated with HTTPReproduciton Steps 1.启动nacos-pay-provider服务,并启动nacos-pay-c…

带罚函数的Bspline拟合

1、内容简介 略 matlab simulink 115-带罚函数的Bspline拟合可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略Flexible Smoothing with B-splines and Penaltie.pdf

团餐订餐系统源码企业订餐小程序写字楼办公区团餐软件开发

市场前景 近年来,随着社会经济的发展和人们生活节奏的加快,团餐市场规模持续扩大,现已稳稳占据了整个餐饮市场三分之一左右的份额,成为了推动餐饮行业发展的重要力量。截至2023年,中国团餐行业市场规模达22350亿元&am…

【Prometheus】如何通过prometheus监控Tomcat运行状态

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

DeepSeek 的含金量还在上升

大家好啊,我是董董灿。 最近 DeepSeek 越来越火了。 网上有很多针对 DeepSeek 的推理测评,除此之外,也有很多人从技术的角度来探讨 DeepSeek 带给行业的影响。 比如今天就看到了一篇文章,探讨 DeepSeek 在使用 GPU 进行模型训练…

Tableau实用技巧 —— 提取Tableau文件中图片

需求背景 在日常开发过程中,我们时常会遇到两种图片提取需求:一是本地报告中的图片文件丢失需要找回,二是从网络论坛中发现有价值的报告图片希望保存使用。针对这些实际应用场景,以下将详细介绍有效的图片提取方法。 解决思路 …

SSM聚合项目+Vue3+Element-plus项目生产部署(Ubuntu24.04LTS)

非常刺激的一次部署经历,我相信很多第一次独立部署前后端分离项目的人都遇到过 后端部署 jdk环境 安装jdk,解压后配置环境变量即可 tomcat运行war包 需要在tomcat的conf/sever.xml中配置SSM聚合项目的每一个子项目的服务(标签),这样tomc…

C语言的物联网

C语言在物联网中的应用 物联网(Internet of Things,IoT)是一个通过网络将各种物理设备连接起来的系统,使其能够收集和交换数据。随着技术的进步,物联网已经走入了我们的日常生活,并在智能家居、智能城市、…