1、程序纹理是什么
程序纹理(Procedural Textures)就是通过程序代码生成的纹理
2、程序纹理如何生成
一般生成程序纹理由两种方式:
- 通过C#脚本生成纹理后传递给Shader
- 直接在Shader代码中自定义逻辑生成纹理
3、程序纹理的好处
程序纹理由于是由程序员写代码动态生成的,因此它具备以下优点:
- 由于是动态生成,不需要存储大文件,可以在运行时生成任意分辨率的纹理
- 可以根据需求调整自定义参数,实时的更改纹理外观
- 通过适当的函数设计,可以生成无缝平铺的纹理
总体而言:程序纹理的最明显好处就是自由度高,可控性强
4、C# 程序生成
生成一个国际象棋棋盘网格,规则是:格子的行列编号同奇同偶则为白色,否则为黑色
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 生成一个国际象棋网格
/// </summary>
public class DynamicGenTex : MonoBehaviour
{
public int textureWidth = 256;
public int textureHeight = 256;
public int tileCount = 8;
private int pixelPerUnit;
public Color Color1 = Color.white;
public Color Color2 = Color.black;
void Start()
{
UpdateTexture();
}
/// <summary>
/// 更新纹理
/// </summary>
public void UpdateTexture() {
pixelPerUnit = textureWidth / tileCount;
Texture2D tex = new Texture2D(textureWidth, textureHeight);
for (int y = 0; y < textureHeight; y++) {
for (int x = 0; x < textureWidth; x++) {
int row = x / pixelPerUnit;
int col = y / pixelPerUnit;
if (row % 2 == col % 2)
tex.SetPixel(x, y, Color1);
else
tex.SetPixel(x, y, Color2);
}
}
// 应用像素的变化
tex.Apply();
Renderer renderer = this.GetComponent<Renderer>();
if (renderer != null) {
renderer.sharedMaterial.mainTexture = tex;
}
}
}
但是现在必须在运行时才能看见,所以可以通过自定义Inspector窗口调用函数
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(DynamicGenTex))]
public class DynamicGenTex_Editor : Editor
{
public override void OnInspectorGUI() {
base.OnInspectorGUI();
// 获取目标脚本
DynamicGenTex obj = (DynamicGenTex)target;
if (GUILayout.Button("更新程序纹理")) {
obj.UpdateTexture();
}
}
}
5、Shader 生成纹理
Shader "ShaderProj/7/DynamicGenTex"
{
Properties
{
_TileCount ("TileCount", Float) = 8
_Color1 ("Color1", Color) = (1,1,1,1)
_Color2 ("Color2", Color) = (1,1,1,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
{
float2 uv = i.uv * _TileCount;
float2 posIndex = floor(uv);
float value = (posIndex.x + posIndex.y) % 2;
return lerp(_Color1, _Color2, value);
}
ENDCG
}
}
}