Unity编辑器里动态生成红白圆环贴图,并一键保存PNG的保姆级代码

张开发
2026/4/19 10:35:19 15 分钟阅读

分享文章

Unity编辑器里动态生成红白圆环贴图,并一键保存PNG的保姆级代码
Unity编辑器动态生成红白圆环贴图全流程指南在游戏开发中程序化生成纹理是提升效率的重要技能。想象一下这样的场景你正在设计一个科幻风格的UI界面需要一组红白相间的环形进度条贴图。传统做法是打开Photoshop手动绘制但当你需要调整环的粗细或颜色时又得重新导出。其实用Unity编辑器脚本可以一键生成并保存这些贴图整个过程不到5秒。1. 准备工作与环境搭建在开始编写纹理生成代码前我们需要明确几个关键点。首先这个功能完全运行在Unity编辑器环境下这意味着我们需要使用UnityEditor命名空间下的API。其次生成的纹理需要保存为项目资源因此要熟悉Application.dataPath和AssetDatabase的配合使用。创建一个新的C#脚本命名为TextureGenerator并确保包含以下命名空间using UnityEngine; using UnityEditor; using System.IO;提示编辑器脚本通常放在项目的Editor文件夹中如果没有请先创建这样可以确保脚本只在编辑模式下运行而不会包含在最终构建中。2. 核心纹理生成逻辑红白圆环的生成原理其实很简单我们创建一个正方形的Texture2D然后遍历每个像素计算其到中心点的距离。如果在预设的半径范围内就填充红色否则填充白色。public static Texture2D GenerateRingTexture(int width, int innerRadius, int outerRadius, Color ringColor, Color bgColor) { Texture2D texture new Texture2D(width, width, TextureFormat.ARGB32, false); Vector2 center new Vector2(width * 0.5f, width * 0.5f); for (int y 0; y width; y) { for (int x 0; x width; x) { float distance Vector2.Distance(new Vector2(x, y), center); bool inRing distance innerRadius distance outerRadius; texture.SetPixel(x, y, inRing ? ringColor : bgColor); } } texture.Apply(); return texture; }这段代码的几个关键参数width: 纹理的宽度和高度正方形innerRadius: 圆环的内半径outerRadius: 圆环的外半径ringColor: 圆环颜色bgColor: 背景颜色3. 纹理保存与资源刷新生成纹理后我们需要将其保存为PNG文件并自动导入到Unity项目中。这里有几个容易踩坑的地方public static void SaveTextureToFile(Texture2D texture, string relativePath) { byte[] pngData texture.EncodeToPNG(); string fullPath Path.Combine(Application.dataPath, relativePath); File.WriteAllBytes(fullPath, pngData); AssetDatabase.Refresh(); // 设置纹理导入设置 string assetPath Assets/ relativePath; TextureImporter importer AssetImporter.GetAtPath(assetPath) as TextureImporter; if (importer ! null) { importer.textureType TextureImporterType.Default; importer.isReadable true; importer.SaveAndReimport(); } }常见问题及解决方案图片保存了但在Project窗口不显示确保调用了AssetDatabase.Refresh()生成的图片无法编辑通过TextureImporter设置isReadable为true路径问题使用Application.dataPath获取项目根目录但保存时需要去掉Assets/4. 创建编辑器界面为了方便使用我们可以创建一个自定义编辑器窗口提供可视化参数调整public class TextureGeneratorWindow : EditorWindow { private int textureSize 512; private int innerRadius 100; private int outerRadius 200; private Color ringColor Color.red; private Color bgColor Color.white; private string savePath GeneratedTextures/RingTexture.png; [MenuItem(Tools/Generate Ring Texture)] public static void ShowWindow() { GetWindowTextureGeneratorWindow(Texture Generator); } void OnGUI() { textureSize EditorGUILayout.IntField(Texture Size, textureSize); innerRadius EditorGUILayout.IntField(Inner Radius, innerRadius); outerRadius EditorGUILayout.IntField(Outer Radius, outerRadius); ringColor EditorGUILayout.ColorField(Ring Color, ringColor); bgColor EditorGUILayout.ColorField(Background Color, bgColor); savePath EditorGUILayout.TextField(Save Path, savePath); if (GUILayout.Button(Generate and Save)) { Texture2D texture TextureGenerator.GenerateRingTexture( textureSize, innerRadius, outerRadius, ringColor, bgColor); TextureGenerator.SaveTextureToFile(texture, savePath); } } }这个编辑器窗口提供了以下功能调整纹理大小和圆环尺寸自定义颜色方案指定保存路径一键生成并保存按钮5. 高级技巧与优化建议基础功能实现后我们可以考虑一些增强功能5.1 抗锯齿处理原始代码生成的圆环边缘会有锯齿我们可以通过以下方式改善// 在GenerateRingTexture方法中修改像素判断逻辑 float distance Vector2.Distance(new Vector2(x, y), center); float delta distance - innerRadius; float fadeStart outerRadius - 5; // 开始抗锯齿的半径 if (distance innerRadius distance outerRadius) { if (distance fadeStart) { // 边缘抗锯齿 float fade 1 - (distance - fadeStart) / 5f; texture.SetPixel(x, y, Color.Lerp(bgColor, ringColor, fade)); } else { texture.SetPixel(x, y, ringColor); } }5.2 批量生成多尺寸纹理有时我们需要同一图案的不同尺寸版本可以扩展生成逻辑public static void GenerateMultipleSizes(string basePath, int[] sizes, int innerRadius, int outerRadius) { foreach (int size in sizes) { string path ${basePath}_{size}x{size}.png; Texture2D texture GenerateRingTexture(size, innerRadius, outerRadius, Color.red, Color.white); SaveTextureToFile(texture, path); } }5.3 纹理性能优化生成的纹理在使用时可以考虑以下优化优化项说明实现方式Mipmaps生成纹理金字塔textureImporter.mipmapEnabled true压缩格式减少内存占用textureImporter.textureCompression TextureImporterCompression.Compressed读写控制发布后不需要读写textureImporter.isReadable false6. 实际应用案例这种程序化生成的纹理在游戏开发中有广泛应用场景UI元素进度条、雷达图、技能冷却指示器特效遮罩冲击波、能量护盾的渐变效果材质贴图用于Shader实现环形高光、边缘发光等效果例如创建一个能量护盾效果// 生成带有透明通道的能量环 Texture2D energyRing GenerateRingTexture(512, 200, 250, new Color(0, 0.8f, 1f, 0.7f), Color.clear); SaveTextureToFile(energyRing, Effects/EnergyRing.png); // 在Shader中使用 sampler2D _MainTex (EnergyRing.png); fixed4 c tex2D(_MainTex, IN.uv_MainTex); o.Emission c.rgb * _Intensity;7. 调试与问题排查在开发过程中可能会遇到以下问题纹理显示为粉色通常表示纹理导入失败检查文件路径和导入设置内存泄漏及时销毁临时创建的Texture2D对象性能问题大尺寸纹理生成时考虑分帧处理调试建议使用Debug.Log输出生成进度在循环中添加yield return null实现分帧生成使用Profiler分析内存使用情况// 分帧生成示例 IEnumerator GenerateLargeTextureCoroutine() { Texture2D texture new Texture2D(4096, 4096); for (int y 0; y 4096; y) { for (int x 0; x 4096; x) { // 生成逻辑... } if (y % 64 0) yield return null; // 每64行暂停一帧 } texture.Apply(); }8. 扩展思路掌握了基础纹理生成技术后可以尝试更复杂的效果多色环通过叠加多个圆环实现彩虹效果动态生成根据游戏参数实时调整环的粗细和颜色3D纹理将同样的原理扩展到3D体积纹理例如创建一个动态进度环public Texture2D CreateProgressRing(float progress) { Texture2D texture new Texture2D(512, 512); Vector2 center new Vector2(256, 256); float anglePerPixel 360f / 512; for (int y 0; y 512; y) { for (int x 0; x 512; x) { Vector2 dir new Vector2(x, y) - center; float angle Vector2.SignedAngle(Vector2.up, dir); if (angle 0) angle 360; bool inRing dir.magnitude 200 dir.magnitude 250; bool inProgress angle progress * 360; texture.SetPixel(x, y, inRing inProgress ? Color.green : Color.gray); } } texture.Apply(); return texture; }在实际项目中我发现将这类工具脚本封装成可复用的编辑器工具集能极大提升开发效率。比如可以创建一个纹理生成工具库包含圆形、环形、条形等常见图案的生成方法并支持自定义颜色渐变和混合模式。

更多文章