Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

程序纹理的生成

一、C#代码动态生成程序纹理

1.主要思路

  1. 利用 Unity 中的 Texture2D 类生成纹理对象
  2. 利用 Renderer 类设置材质球纹理
  3. 利用 Unity 编辑器拓展知识自定义 Inspector 窗口
  4. 利用单张纹理的 shader 进行测试

2.生成对应的格式纹理对象

这里以生成国际象棋纹理为例

  1. 设置程序纹理的可编辑参数 纹理宽高、棋盘行列数、棋盘格的颜色
  2. 实现更新纹理的方法
    1. 创建 Texture2D 对象,通过参数设置尺寸
    2. 设置纹理对象的每一个像素点的颜色
    3. 自定义规则:使得(x,y)的像素所在格子和规则一致即可
    4. 应用像素的变化

3.设置材质球的主纹理

  1. 获取对应对象的 Renderer 渲染器脚本
  2. 通过 Renderer 脚本设置材质球主纹理

4.在 Inspector 中窗口中添加更新纹理按钮

  1. 为生成纹理脚本创建自定义的 Inspector 窗口家脚本
  2. 添加自定义编辑器特性
  3. 重写 OnInspectorGUI(),在其中使用 DrawDefaultInspector 显示默认组件
  4. 新建按钮,用于调用材质的方法

5.示例代码

1.)生成纹理代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//这里以生成国际象棋纹理为例

public class ProgramTexture : MonoBehaviour
{
//程序纹理的宽高
public int textureWidth = 256;
public int textureHeight = 256;
//程序纹理的行列数
public int tileCount = 8;
//程序纹理的颜色
public Color color1 = Color.white;
public Color color2 = Color.black;
private void Start()
{
UpdateTexture();
}
/// <summary>
/// 更新纹理
/// </summary>
public void UpdateTexture()
{
//根据对应的纹理宽高 创建2D纹理
Texture2D tex = new Texture2D(textureWidth, textureHeight);
for (int y = 0; y < textureHeight; y++)
{
for (int x = 0; x < textureWidth; x++)
{
//1.首先需要知道 格子的宽高
//格子的宽tileWidth = textureWidth / tileCount;
//格子的高 = textureHeight / tileCount;

//2.计算当前像素在哪个格子中
// x / 格子的宽 = 格子的行数
// y / 格子的高 = 格子的列数

//3.判断一个格子编号 是否同奇同偶


if (x / (textureWidth / tileCount) % 2 == y / (textureHeight / tileCount) % 2)
tex.SetPixel(x, y, color1);
else
tex.SetPixel(x, y, color2);
}
}
tex.Apply();
Renderer renderer = GetComponent<Renderer>();
if (renderer != null)
{
//得到渲染器中的材质球 并修改它的主纹理
renderer.sharedMaterial.mainTexture = tex;
}
}
}

2.)Inspector 中窗口中添加更新纹理按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
[CustomEditor(typeof(ProgramTexture))]
public class ProgramTextureEditor : Editor
{
public override void OnInspectorGUI()
{
//绘制默认参数的相关内容
DrawDefaultInspector();
//获取目标脚本
ProgramTexture scriptObj = (ProgramTexture)target;
if (GUILayout.Button("更新程序纹理"))
scriptObj.UpdateTexture();
}
}

二、Shader 代码的动态生成

1.主要思路

  1. 新建 Shader,删除无用代码
  2. 属性声明
    1. 平铺数量
    2. 格子颜色 1
    3. 格子颜色 2
  3. v2f 结构体
    1. 顶点坐标
    2. uv 坐标
  4. 顶点着色器
    1. 顶点坐标转换
    2. uv 的直接赋值
  5. 片元着色器
    1. uv * 行列式 即::将 uv 坐标从 0~1 的范围,缩放到 0~TileCount 的范围
    2. 利用 floor()函数得到格子编号 floor(x) 去参数 x 的能得到的最大整数
    3. 利用奇偶数相加规则得到 0 或者 1 的值,0 代表同奇同偶,1 代表一奇一偶
    4. 利用上述得到的值获取颜色

2.示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Shader "Unlit/ProgramTexture"
{
Properties
{
//棋盘格行列数
_TileCount("TileCount",Float) = 8
_Color1("Color1",Color) = (1,1,1,1)
_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;
float4 vertex : SV_POSITION;
};


v2f vert (appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
return o;
}

fixed4 frag (v2f i) : SV_Target
{
//把uv坐标从0~1的范围,缩放到0~TileCount的范围
float2 uv = i.uv * _TileCount;
//这一步相当于就是得到 当前uv坐标 所在的格子索引位置
float2 posIndex = floor(uv);
//同奇同偶 加起来就是偶数
//一奇一偶 加起来就是奇数
//这的结果只会是0或者1
float value = (posIndex.x + posIndex.y) % 2;
//因为value 只会是0或者1 所以可以使用lerp进行取值
return lerp(_Color1,_Color2,value);
}
ENDCG
}
}
}

评论