25.纹理-单张纹理-纹理颜色采样
25.1 知识点
知识回顾 - 内置函数:二维纹理采样函数
在纹理采样中,我们使用内置的 tex2D
函数来获取纹理中某一位置的颜色值:
fixed4 tex2D(sampler2D tex, float2 s)
传入纹理图片和uv坐标,返回纹理图片中对应位置的颜色值
编写单张纹理颜色采样Shader
我们将通过以下步骤编写一个可以采样纹理颜色的Shader。
编写Shader文件的基本结构
首先,我们创建一个基础的Shader文件,并确保它不报错。
Shader "Unlit/Lesson25_Single_Texture_Color_Sampler"
{
Properties {}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
v2f_img vert(appdata_base appdata_base)
{
v2f_img v2f_img;
v2f_img.pos = UnityObjectToClipPos(appdata_base.vertex);
v2f_img.uv = appdata_base.texcoord.xy;
return v2f_img;
}
fixed4 frag(v2f_img v2f_img) : SV_Target
{
return fixed4(1, 1, 1, 1); // 默认返回白色
}
ENDCG
}
}
}
其中appdata_base和v2f_img结构如下,他们都在UnityCG.cginc中定义
struct appdata_base {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f_img
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
声明纹理属性和CG中的成员变量
我们需要声明ShaderLab中的属性,并在CG中映射这些属性。
ShaderLab声明一个2D纹理变量。
CG中映射需要有两个成员变量, 一个用于映射纹理颜色数据,一个用于映射纹理缩放平移数据。
ShaderLab属性:
- 2D纹理,用于根据UV坐标从纹理中获取颜色值。
CG中的成员变量:
sampler2D
:映射纹理图片数据。float4
:映射纹理的缩放和平移数据(固定命名为_ST
,代表Scale和Translation)。
Properties
{
//主纹理
_MainTex("MainTex", 2D) = ""{}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//映射对应纹理属性的图片颜色相关数据
sampler2D _MainTex;
//映射对应纹理属性的 缩放 平(偏)移数据
float4 _MainTex_ST; //xy代表缩放 zw代表平移
...
ENDCG
}
}
使用缩放和平移参数参与UV值计算
如何获取模型中携带的uv信息?
- 在顶点着色器中,我们可以利用TEXCOORD语义获取到模型中的纹理坐标信息
appdata_base.texcoord
appdata_base.texcoord
是一个float4类型的appdata_base.texcoord.xy
获取到的是纹理坐标的水平和垂直坐标appdata_base.texcoord.zw
获取到的是纹理携带的一些额外信息,例如深度值等
- 在顶点着色器中,我们可以利用TEXCOORD语义获取到模型中的纹理坐标信息
如何计算
- 固定算法:
- 公式
- 先缩放,后平(偏)移
- 缩放用乘法,平(偏)用加法
- 纹理坐标.xy * 纹理名_ST.xy(缩放)+ 纹理名_ST.zw(平移)
- UV坐标的缩放和平移可以用固定的公式:
uv = appdata_base.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw
- 宏
- 或者直接用内置宏:
TRANSFORM_TEX(纹理坐标变量, 纹理变量)
,该宏在内部会进行相同的计算 uv = TRANSFORM_TEX(appdata_base.texcoord.xy, _MainTex)
- 或者直接用内置宏:
v2f_img vert(appdata_base appdata_base)
{
v2f_img v2f_img; // 定义一个v2f_img类型的变量,用于存储顶点输出数据
// 计算顶点的裁剪空间位置
v2f_img.pos = UnityObjectToClipPos(appdata_base.vertex);
// 计算纹理坐标 (UV)
// appdata_base.texcoord.xy 表示UV坐标
// appdata_base.texcoord.zw 可能代表一些额外的信息,如深度等
v2f_img.uv = appdata_base.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
// 另一种方法:使用宏定义来转换纹理坐标
// 宏定义示例:#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
// v2f_img.uv = TRANSFORM_TEX(appdata_base.texcoord.xy, _MainTex);
// 返回变换后的顶点数据
return v2f_img;
}
在片元着色器中进行纹理颜色采样
在片元着色器中,我们将使用 tex2D
函数根据UV坐标从纹理中获取颜色。
fixed4 frag(v2f_img v2f_img) : SV_Target
{
//这传入的uv 是经过插值运算后的 就是每一个片元都有自己的一个uv坐标
//这样才能精准的在贴图当中取出颜色
fixed4 color = tex2D(_MainTex, v2f_img.uv);
return color;
}
为模型创建材质并绑定Shader
接下来,我们需要创建一个材质,并将Shader应用到材质上,让模型使用这个材质来显示纹理效果。
总结
通过这个过程,我们学习了如何编写一个简单的纹理采样Shader,并从模型的UV坐标中采样纹理颜色。具体步骤如下:
顶点着色器:
- 获取模型中的纹理坐标信息(UV),并进行缩放和平移计算。
片元着色器:
- 接收顶点着色器插值后的UV坐标,并利用
tex2D
函数从纹理中采样对应的颜色值,最后返回该颜色。
- 接收顶点着色器插值后的UV坐标,并利用
25.2 知识点代码
Lesson25_纹理_单张纹理_纹理颜色采样
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson25_纹理_单张纹理_纹理颜色采样 : MonoBehaviour
{
void Start()
{
#region 知识回顾 内置函数——二维纹理采样函数
//fixed4 tex2D(sampler2D tex, float2 s)
//传入纹理图片和uv坐标
//返回纹理图片中对应位置的颜色值
#endregion
#region 知识点 书写单张纹理颜色采样Shader
#region 第一步 完成Shader文件基本结构,让其不报错
#endregion
#region 第二步 纹理属性和CG成员变量声明
// 关键知识点
// CG中映射ShaderLab中的纹理属性,需要有两个成员变量
// 一个用于映射纹理颜色数据,一个用于映射纹理缩放平移数据
//
// ShaderLab中的属性
// 图片属性(2D)
// 用于利用UV坐标提取其中颜色
// CG中用于映射属性的成员变量
// 1.sampler2D 用于映射纹理图片
// 2.float4 用于映射纹理图片的缩放和平移
// 固定命名方式 纹理名_ST (S代表scale缩放 T代表translation平移)
#endregion
#region 第三步 用缩放平移参数参与uv值计算
//1.如何获取模型中携带的uv信息?
// 在顶点着色器中,我们可以利用TEXCOORD语义获取到模型中的纹理坐标信息
// 它是一个float4类型的
// xy获取到的是纹理坐标的水平和垂直坐标
// zw获取到的是纹理携带的一些额外信息,例如深度值等
//2.如何计算
// 固定算法
// 先缩放,后平(偏)移
// 缩放用乘法,平(偏)用加法
// 纹理坐标.xy * 纹理名_ST.xy + 纹理名_ST.wz
// 或者直接用内置宏
// TRANSFORM_TEX(纹理坐标变量, 纹理变量)
// 该宏在内部会进行相同的计算
#endregion
#region 第四步 在片元着色器中进行纹理颜色采样
#endregion
#endregion
#region 总结
//纹理颜色采样非常简单
//1.顶点着色器中获取到模型中的纹理坐标信息
// 进行相关的缩放偏移计算后返回
//2.片元着色器得到插值后的uv坐标进行纹理采样
// 返回对应的颜色
#endregion
}
}
Lesson25_Single_Texture_Color_Sampler.shader
Shader "Unlit/Lesson25_Single_Texture_Color_Sampler"
{
Properties
{
//主纹理
_MainTex("MainTex", 2D) = ""{}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//映射对应纹理属性的图片颜色相关数据
sampler2D _MainTex;
//映射对应纹理属性的 缩放 平(偏)移数据
float4 _MainTex_ST; //xy代表缩放 zw代表平移
v2f_img vert(appdata_base appdata_base)
{
v2f_img v2f_img;
v2f_img.pos = UnityObjectToClipPos(appdata_base.vertex);
//appdata_base.texcoord.xy //代表uv坐标
//appdata_base.texcoord.zw //代表一些额外信息 例如深度值
//先缩放 后平移 这个是一个固定的算法 规则如此
//如果没有进行缩放和平移 那么 这个计算后 值是不会产生变化的
//因为缩放默认值是1和1 ,平移默认值是0和0
v2f_img.uv = appdata_base.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
//另一种写法 使用纹理的宏
// Transforms 2D UV by scale/bias property
//#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
//TRANSFORM_TEX(appdata_base.texcoord.xy, _MainTex);
return v2f_img;
}
fixed4 frag(v2f_img v2f_img) : SV_Target
{
//这传入的uv 是经过插值运算后的 就是每一个片元都有自己的一个uv坐标
//这样才能精准的在贴图当中取出颜色
fixed4 color = tex2D(_MainTex, v2f_img.uv);
return color;
}
ENDCG
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com