43.高级纹理-程序纹理-基础实现-Shader代码动态生成程序纹理
43.1 知识点
知识点回顾
国际象棋棋盘格规则
- 格子的行列编号同奇同偶则为白色,不同则为黑色。
数学知识回顾
- 两个奇数相加结果为偶数。
- 两个偶数相加结果为偶数。
- 一个奇数和一个偶数相加的结果是奇数。
Shader中的内置函数 floor
floor
是 Unity 的UnityCG.cginc
文件中的内置函数。- 功能:对传入数值向下取整。
floor(2.6) // 返回 2
floor(0.4) // 返回 0
floor(-2.3) // 返回 -3
Shader代码动态计算国际象棋棋盘格纹理
新建shader,命名为可编程纹理,保留骨架
Shader "Unlit/Lesson43_ShaderProgrammableTexture"
{
Properties
{
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
ENDCG
}
}
}
声明属性,包括平铺数量(行列数)以及黑白两个颜色
Properties
{
// 棋盘格行列数
_TileCount("TileCount", Float) = 8
// 格子颜色1
_Color1("Color1", Color) = (1,1,1,1)
// 格子颜色2
_Color2("Color2", Color) = (0,0,0,1)
}
// 定义棋盘格着色器所需的属性变量
float _TileCount; // 棋盘格的行列数,控制棋盘格的密度
float4 _Color1; // 格子的第一种颜色
float4 _Color2; // 格子的第二种颜色
定义结构v2f,包括用于纹理采样的uv坐标以及裁剪空间位置
struct v2f
{
float2 uv : TEXCOORD0; // 传递 UV 坐标,用于纹理采样
float4 vertex : SV_POSITION; // 传递顶点的裁剪空间位置,用于渲染
};
顶点函数转换裁剪坐标,并传递输入的uv到片元
v2f vert(appdata_base appdata_base)
{
v2f v2f; // 初始化输出结构体 v2f
// 将模型空间下的顶点位置转换为裁剪空间坐标
// UnityObjectToClipPos 函数将物体的顶点坐标转换为屏幕坐标系中进行渲染的裁剪坐标
v2f.vertex = UnityObjectToClipPos(appdata_base.vertex);
// 将输入的 UV 坐标传递到片元着色器
// 这里直接使用了模型的 UV 坐标来表示纹理的映射位置
v2f.uv = appdata_base.texcoord;
// 返回结构体 v2f,包含了裁剪空间的顶点位置和纹理 UV 坐标
return v2f;
}
片元函数映射uv到格子索引,通过xy格子索引相加的后的奇偶判断哪个颜色显示
fixed4 frag(v2f v2f) : SV_Target
{
//把uv坐标从0~1范围 缩放到 0~_TileCount 比如0-8
float2 uv = v2f.uv * _TileCount;
//进行向下取整 相当于就是得到当前uv坐标所在的格子索引位置
float2 posIndex = floor(uv);
// posIndex.x + posIndex.y
// 情况1:如果它们同奇或者同偶 加起来就是偶数
// 情况2:如果不同一个奇数,一个偶数,加起来就是奇数
// 这的结果只会是 0或者1 如果是0 代表满足情况1;如果是1 代表满足情况2
float value = (posIndex.x + posIndex.y) % 2;
//因为value只会是0或1 ,那么我们完全可以利用lerp进行取值
//取的就是两端的极限值 只有两种情况
return lerp(_Color1, _Color2, value);
}
赋值Shader并查看效果
43.2 知识点代码
Lesson43_高级纹理_程序纹理_基础实现_Shader代码动态生成程序纹理.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson43_高级纹理_程序纹理_基础实现_Shader代码动态生成程序纹理 : MonoBehaviour
{
void Start()
{
#region 知识点回顾
//1.国际象棋棋盘格规则
// 格子的行列编号同奇同偶则为白色,不同则为黑色
//2.数学知识回顾
// 2-1:两个奇数相加结果为偶数
// 2-2:两个偶数相加结果为偶数
// 2-2:一个奇数和一个偶数相加的结果是奇数
#endregion
#region Shader中的内置函数floor
// Shader中的内置函数floor(属于UnityCG.cginc)
// 该函数 传入一个数值 floor(数值)
// 会对传入数值向下取整
// 比如:
// floor(2.6) 返回 2
// floor(0.4) 返回 0
// floor(-2.3) 返回 -3
#endregion
#region 知识点 Shader代码动态计算国际象棋棋盘格纹理
//1.新建Shader,删除无用代码
//2.声明属性
// 平铺数量(行列数) _TileCount
// 格子颜色1 _Color1
// 格子颜色2 _Color2
//3.v2f结构体
// 顶点和uv
//4.顶点着色器
// 顶点坐标转换
// uv直接赋值
//5.片元着色器
// uv * 行列数 将0~1范围 变为 0~_TileCount范围
// 利用floor得到行列格子编号
// 利用奇偶相加规律得到 0、1 值,0代表同奇或同偶,1代表不同
// 利用该值决定该像素使用哪种颜色
#endregion
}
}
Lesson43_ShaderProgrammableTexture.shader
Shader "Unlit/Lesson43_ShaderProgrammableTexture"
{
Properties
{
//棋盘格行列数
_TileCount("TileCount", Float) = 8
//格子颜色1
_Color1("Color1", Color) = (1,1,1,1)
//格子颜色2
_Color2("Color2", Color) = (0,0,0,1)
}
SubShader
{
Tags
{
"RenderType"="Opaque"
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 定义棋盘格着色器所需的属性变量
float _TileCount; // 棋盘格的行列数,控制棋盘格的密度
float4 _Color1; // 格子的第一种颜色
float4 _Color2; // 格子的第二种颜色
struct v2f
{
float2 uv : TEXCOORD0; // 传递 UV 坐标,用于纹理采样
float4 vertex : SV_POSITION; // 传递顶点的裁剪空间位置,用于渲染
};
v2f vert(appdata_base appdata_base)
{
v2f v2f; // 初始化输出结构体 v2f
// 将模型空间下的顶点位置转换为裁剪空间坐标
// UnityObjectToClipPos 函数将物体的顶点坐标转换为屏幕坐标系中进行渲染的裁剪坐标
v2f.vertex = UnityObjectToClipPos(appdata_base.vertex);
// 将输入的 UV 坐标传递到片元着色器
// 这里直接使用了模型的 UV 坐标来表示纹理的映射位置
v2f.uv = appdata_base.texcoord;
// 返回结构体 v2f,包含了裁剪空间的顶点位置和纹理 UV 坐标
return v2f;
}
fixed4 frag(v2f v2f) : SV_Target
{
//把uv坐标从0~1范围 缩放到 0~_TileCount 比如0-8
float2 uv = v2f.uv * _TileCount;
//进行向下取整 相当于就是得到当前uv坐标所在的格子索引位置
float2 posIndex = floor(uv);
// posIndex.x + posIndex.y
// 情况1:如果它们同奇或者同偶 加起来就是偶数
// 情况2:如果不同一个奇数,一个偶数,加起来就是奇数
// 这的结果只会是 0或者1 如果是0 代表满足情况1;如果是1 代表满足情况2
float value = (posIndex.x + posIndex.y) % 2;
//因为value只会是0或1 ,那么我们完全可以利用lerp进行取值
//取的就是两端的极限值 只有两种情况
return lerp(_Color1, _Color2, value);
}
ENDCG
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com