Created
March 27, 2023 16:27
-
-
Save isuzu-shiranui/5b8d2a5505eed80d954b95d1cd5da285 to your computer and use it in GitHub Desktop.
シェーダーのPropertiesから定義部分を生成させるやつ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using UnityEditor; | |
using UnityEngine; | |
public class ShaderPropertiesGenerator : EditorWindow | |
{ | |
private Shader targetShader; | |
private void OnGUI() | |
{ | |
EditorGUILayout.BeginVertical(); | |
this.targetShader = (Shader)EditorGUILayout.ObjectField("Target Shader", this.targetShader, typeof(Shader), false); | |
if (GUILayout.Button("Generate HLSL")) this.ExtractShaderProperties(); | |
EditorGUILayout.EndVertical(); | |
} | |
[MenuItem("Window/Shader Properties Generator")] | |
public static void ShowWindow() | |
{ | |
GetWindow<ShaderPropertiesGenerator>("Shader Properties Generator"); | |
} | |
private void ExtractShaderProperties() | |
{ | |
if (this.targetShader == null) | |
{ | |
Debug.LogError("Please select a shader."); | |
return; | |
} | |
var shaderProperties = new List<ShaderProperty>(); | |
var propertyCount = ShaderUtil.GetPropertyCount(this.targetShader); | |
for (var i = 0; i < propertyCount; i++) | |
{ | |
var propertyName = ShaderUtil.GetPropertyName(this.targetShader, i); | |
if (!propertyName.StartsWith("_")) continue; | |
var propertyType = ShaderUtil.GetPropertyType(this.targetShader, i); | |
var propertyDimension = GetPropertyDimension(propertyType); | |
var propertyAttributes = this.targetShader.GetPropertyAttributes(i); | |
if (ShaderUtil.IsShaderPropertyHidden(this.targetShader, i)) continue; | |
var texturePropertyName = GetTexturePropertyName(propertyAttributes); | |
shaderProperties.Add(new ShaderProperty(propertyType, propertyName, propertyDimension, texturePropertyName)); | |
} | |
this.GenerateHLSLFile(shaderProperties); | |
} | |
private void GenerateHLSLFile(List<ShaderProperty> shaderProperties) | |
{ | |
var shaderPath = AssetDatabase.GetAssetPath(this.targetShader); | |
var directoryPath = Path.GetDirectoryName(shaderPath); | |
var fileName = $"{Path.GetFileNameWithoutExtension(shaderPath)}Properties.hlsl"; | |
var filePath = Path.Combine(directoryPath, fileName); | |
var maxPropertyNameLength = shaderProperties.Max(x => x.Name.Length); | |
var sb = new StringBuilder(); | |
sb.AppendLine("//"); | |
sb.AppendLine("// This file is generated by ShaderPropertiesGenerator. Do not edit manually."); | |
sb.AppendLine("//"); | |
sb.AppendLine(); | |
sb.AppendLine("#include \"Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl\""); | |
sb.AppendLine("#include \"Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl\""); | |
sb.AppendLine(); | |
// CBUFFER_START and CBUFFER_END | |
sb.AppendLine("CBUFFER_START(UnityPerMaterial)"); | |
foreach (var property in shaderProperties) | |
{ | |
if (property.Type is not (ShaderUtil.ShaderPropertyType.Color or ShaderUtil.ShaderPropertyType.Range or ShaderUtil.ShaderPropertyType.Float or ShaderUtil.ShaderPropertyType.Vector)) continue; | |
sb.AppendLine($"float{(property.Dimension == 1 ? " " : property.Dimension.ToString())} {property.Name};"); | |
} | |
sb.AppendLine(); | |
foreach (var property in shaderProperties) | |
{ | |
if (property.Type != ShaderUtil.ShaderPropertyType.TexEnv) continue; | |
if (!string.IsNullOrEmpty(property.TexturePropertyName)) continue; | |
sb.AppendLine($"float4 {property.Name}_ST;"); | |
sb.AppendLine($"float4 {property.Name}_TexelSize;"); | |
sb.AppendLine($"float4 {property.Name}_MipInfo;"); | |
sb.AppendLine(); | |
} | |
sb.AppendLine(); | |
sb.AppendLine("CBUFFER_END"); | |
sb.AppendLine(); | |
sb.AppendLine(); | |
// UNITY_DOTS_INSTANCING_START and UNITY_DOTS_INSTANCING_END | |
sb.AppendLine("#ifdef UNITY_DOTS_INSTANCING_ENABLED"); | |
sb.AppendLine("UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)"); | |
foreach (var property in shaderProperties) | |
{ | |
if (property.Type is ShaderUtil.ShaderPropertyType.Color or ShaderUtil.ShaderPropertyType.Range or ShaderUtil.ShaderPropertyType.Float or ShaderUtil.ShaderPropertyType.Vector) | |
sb.AppendLine($" UNITY_DOTS_INSTANCED_PROP(float{(property.Dimension == 1 ? " " : property.Dimension.ToString())}, {property.Name})"); | |
} | |
sb.AppendLine("UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)"); | |
sb.AppendLine(); | |
foreach (var property in shaderProperties) | |
{ | |
if (property.Type is not (ShaderUtil.ShaderPropertyType.Color or ShaderUtil.ShaderPropertyType.Range or ShaderUtil.ShaderPropertyType.Float)) continue; | |
var padding = new string(' ', maxPropertyNameLength - property.Name.Length); | |
sb.AppendLine($"#define {property.Name} {padding}UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(float{(property.Dimension == 1 ? " " : property.Dimension.ToString())}, {property.Name})"); | |
} | |
sb.AppendLine("#endif"); | |
sb.AppendLine(); | |
// TEXTURE2D and SAMPLER | |
foreach (var property in shaderProperties) | |
{ | |
if (property.Type != ShaderUtil.ShaderPropertyType.TexEnv) continue; | |
if (property.TexturePropertyName == null) | |
{ | |
var padding = new string(' ', maxPropertyNameLength - property.Name.Length); | |
sb.AppendLine($"TEXTURE2D({property.Name}); {padding}SAMPLER(sampler{property.Name});"); | |
} | |
else | |
{ | |
sb.AppendLine($"TEXTURE2D({property.Name});"); | |
} | |
} | |
sb.AppendLine("SAMPLER(sampler_linear_clamp);"); | |
File.WriteAllText(filePath, sb.ToString()); | |
AssetDatabase.Refresh(); | |
Debug.Log($"Generated HLSL file: {filePath}"); | |
} | |
private static int GetPropertyDimension(ShaderUtil.ShaderPropertyType type) | |
{ | |
return type switch | |
{ | |
ShaderUtil.ShaderPropertyType.Color => 4, | |
ShaderUtil.ShaderPropertyType.Vector => 4, | |
ShaderUtil.ShaderPropertyType.TexEnv => 2, | |
_ => 1 | |
}; | |
} | |
private static string GetTexturePropertyName(string[] attributes) | |
{ | |
foreach (var attribute in attributes) | |
{ | |
if (!attribute.StartsWith("TextureSampler(")) continue; | |
var startIndex = "TextureSampler(".Length; | |
var endIndex = attribute.LastIndexOf(")"); | |
if (endIndex <= startIndex) break; | |
return attribute.Substring(startIndex, endIndex - startIndex); | |
} | |
return null; | |
} | |
private record ShaderProperty(ShaderUtil.ShaderPropertyType Type, string Name, int Dimension, string TexturePropertyName = null) | |
{ | |
public ShaderUtil.ShaderPropertyType Type { get; } = Type; | |
public string Name { get; } = Name; | |
public int Dimension { get; } = Dimension; | |
public string TexturePropertyName { get; } = TexturePropertyName; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
プロパティのアトリビュートに[TextureSampler(_MainTex)]とかって書くと、Samplerは生成しなくなる。