25.单张纹理颜色采样

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值计算

  1. 如何获取模型中携带的uv信息?

    • 在顶点着色器中,我们可以利用TEXCOORD语义获取到模型中的纹理坐标信息appdata_base.texcoord
    • appdata_base.texcoord是一个float4类型的
    • appdata_base.texcoord.xy 获取到的是纹理坐标的水平和垂直坐标
    • appdata_base.texcoord.zw 获取到的是纹理携带的一些额外信息,例如深度值等
  2. 如何计算

    • 固定算法:
    • 公式
      • 先缩放,后平(偏)移
      • 缩放用乘法,平(偏)用加法
      • 纹理坐标.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坐标中采样纹理颜色。具体步骤如下:

  1. 顶点着色器

    • 获取模型中的纹理坐标信息(UV),并进行缩放和平移计算。
  2. 片元着色器

    • 接收顶点着色器插值后的UV坐标,并利用 tex2D 函数从纹理中采样对应的颜色值,最后返回该颜色。

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

×

喜欢就点赞,疼爱就打赏