Files
CortexCore e2650195a5 1
2024-05-17 16:24:41 +08:00

404 lines
15 KiB
C#

//////////////////////////////////////////////////////
// MicroSplat
// Copyright (c) Jason Booth
//////////////////////////////////////////////////////
using UnityEngine;
using UnityEditor;
using System.Text;
using System.Linq;
namespace JBooth.MicroSplat
{
public class SurfaceShaderRenderLoopAdapter : IRenderLoopAdapter
{
public string GetDisplayName()
{
return "Standard";
}
public string GetShaderExtension()
{
return "shader";
}
public string GetRenderLoopKeyword()
{
return "_MSRENDERLOOP_SURFACESHADER";
}
public string GetVersion()
{
return MicroSplatShaderGUI.MicroSplatVersion;
}
MicroSplatGenerator gen;
TextAsset templateStandard;
TextAsset templatePassForward;
TextAsset templatePassForwardAdd;
TextAsset templatePassGBuffer;
TextAsset templatePassShadow;
TextAsset templatePassMeta;
TextAsset templateShared;
TextAsset templateShaderDesc;
TextAsset templateCommonHLSL;
TextAsset templateChain;
TextAsset templateTess;
public void Init(string[] paths)
{
if (gen == null)
{
gen = new MicroSplatGenerator();
}
gen.Init(paths);
foreach (var p in paths)
{
if (p.EndsWith("microsplat_template_standard.txt"))
{
templateStandard = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_func_tess2.txt"))
{
templateTess = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_chain.txt"))
{
templateChain = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_standard_passforward.txt"))
{
templatePassForward = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_standard_passforwardadd.txt"))
{
templatePassForwardAdd = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_standard_passgbuffer.txt"))
{
templatePassGBuffer = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_standard_passmeta.txt"))
{
templatePassMeta = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_standard_passshadow.txt"))
{
templatePassShadow = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_standard_commonHLSL.txt"))
{
templateCommonHLSL = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_shaderdesc.txt"))
{
templateShaderDesc = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
else if (p.EndsWith("microsplat_template_shared.txt"))
{
templateShared = AssetDatabase.LoadAssetAtPath<TextAsset>(p);
}
}
if (templateStandard == null)
{
Debug.LogError ("Cannot find microsplat_template_standard.txt, will not be able to compile valid shaders");
}
if (templateChain == null)
{
Debug.LogError ("Cannot find microsplat_template_chain.txt, will not be able to compile valid shaders");
}
if (templatePassForward == null)
{
Debug.LogError ("Cannot find template for pass forward, will not be able to compile valid shaders");
}
if (templatePassForwardAdd == null)
{
Debug.LogError ("Cannot find template for pass forward add, will not be able to compile valid shaders");
}
if (templatePassGBuffer == null)
{
Debug.LogError ("Cannot find template for pass gbuffer, will not be able to compile valid shaders");
}
if (templatePassShadow == null)
{
Debug.LogError ("Cannot find template for pass shadow, will not be able to compile valid shaders");
}
if (templatePassMeta == null)
{
Debug.LogError ("Cannot find template for pass meta, will not be able to compile valid shaders");
}
if (templateShaderDesc == null)
{
Debug.LogError ("Cannot find template for shader desc, will not be able to compile valid shaders");
}
if (templateShared == null)
{
Debug.LogError ("Cannot find template for template shared, will not be able to compile valid shaders");
}
if (templateCommonHLSL == null)
{
Debug.LogError ("Cannot find template for template common HLSL, will not be able to compile valid shaders");
}
}
public static StringBuilder Strip(string code, StringBuilder template, string param, string[] keys)
{
bool contains = false;
foreach (var k in keys)
{
if (code.Contains(k))
{
contains = true;
break;
}
}
if (contains)
{
return template.Replace(param, "");
}
else
{
return template.Replace(param, "//");
}
}
public static StringBuilder Strip(string code, StringBuilder template, string param, string key)
{
if (code.Contains(key))
{
return template.Replace(param, "");
}
else
{
return template.Replace(param, "//");
}
}
public static StringBuilder Strip(string code, StringBuilder template)
{
template = Strip(code, template, "%SCREENPOS%", new string[] { ".screenPos", ".screenUV" });
template = Strip(code, template, "%UV0%", ".texcoord0");
template = Strip(code, template, "%UV1%", ".texcoord1");
template = Strip(code, template, "%UV2%", ".texcoord2");
template = Strip(code, template, "%UV3%", ".texcoord3");
template = Strip(code, template, "%V2FUV0%", ".texcoord0");
template = Strip(code, template, "%V2FUV1%", ".texcoord1");
template = Strip(code, template, "%V2FUV2%", ".texcoord2");
template = Strip(code, template, "%V2FUV3%", ".texcoord3");
template = Strip(code, template, "%LOCALSPACEPOSITION%", ".localSpacePosition");
template = Strip(code, template, "%LOCALSPACENORMAL%", ".localSpaceNormal");
template = Strip(code, template, "%LOCALSPACETANGENT%", ".localSpaceTangent");
template = Strip(code, template, "%VERTEXCOLOR%", ".vertexColor");
template = Strip(code, template, "%V2FVERTEXCOLOR%", ".vertexColor");
template = Strip(code, template, "%EXTRAV2F0%", ".extraV2F0");
template = Strip(code, template, "%EXTRAV2F1%", ".extraV2F1");
template = Strip(code, template, "%EXTRAV2F2%", ".extraV2F2");
template = Strip(code, template, "%EXTRAV2F3%", ".extraV2F3");
template = Strip(code, template, "%EXTRAV2F4%", ".extraV2F4");
template = Strip(code, template, "%EXTRAV2F5%", ".extraV2F5");
template = Strip(code, template, "%EXTRAV2F6%", ".extraV2F6");
template = Strip(code, template, "%EXTRAV2F7%", ".extraV2F7");
template = Strip(code, template, "%VERTEXID%", ".vertexID");
template = template.Replace("ChainSurfaceFunction", "SurfaceFunction");
return template;
}
public static StringBuilder ReplaceOrRemove(StringBuilder template, string key, string tag, string option)
{
if (!string.IsNullOrEmpty(option))
{
return template.Replace(key, tag + " \"" + option + "\"");
}
else
{
return template.Replace(key, "");
}
}
public static string GetTags(string options)
{
string[] lines = options.ToLines();
foreach (var l in lines)
{
string s = l.Trim();
if (s.Contains("Tags {"))
{
return l;
}
}
return "";
}
public static string GetOption(string options, string name)
{
string[] lines = options.ToLines();
foreach (var l in lines)
{
string s = l.Trim();
if (s.Contains(name))
{
return s.Replace(name, "").Replace("\"", "").Trim();
}
}
return "";
}
StringBuilder BuildTemplate(Blocks blocks, string fallbackOverride = null)
{
var template = new StringBuilder(100000);
template.Append(templateStandard.text);
var passforward = new StringBuilder(templatePassForward.text);
var passforwardAdd = new StringBuilder(templatePassForwardAdd.text);
var passGBuffer = new StringBuilder(templatePassGBuffer.text);
var passShadow = new StringBuilder(templatePassShadow.text);
var passMeta = new StringBuilder(templatePassMeta.text);
if (blocks.defines.Contains("_BDRF3") || blocks.defines.Contains("_BDRFLAMBERT"))
{
passGBuffer.Length = 0;
}
if (blocks.options.Contains("Unlit"))
{
passGBuffer.Length = 0;
passforwardAdd.Length = 0;
}
if (blocks.options.Contains("Alpha"))
{
passGBuffer.Length = 0;
passShadow.Length = 0;
passforward = passforward.Replace("%FORWARDBASEBLEND%", "Blend SrcAlpha OneMinusSrcAlpha");
passforwardAdd = passforwardAdd.Replace("%FORWARDADDBLEND%", "Blend SrcAlpha One");
blocks.defines += "\n #define _ALPHABLEND_ON 1";
passforward = passforward.Insert(0, "\nZWrite Off ColorMask RGB\n\n");
}
else
{
passforward = passforward.Replace("%FORWARDBASEBLEND%", "");
passforwardAdd = passforwardAdd.Replace("%FORWARDADDBLEND%", "");
}
template = template.Replace("%PASSGBUFFER%", passGBuffer.ToString());
template = template.Replace("%PASSMETA%", passMeta.ToString());
template = template.Replace("%PASSFORWARD%", passforward.ToString());
template = template.Replace("%PASSFORWARDADD%", passforwardAdd.ToString());
template = template.Replace("%PASSSHADOW%", passShadow.ToString());
StringBuilder header = new StringBuilder();
header.AppendLine("////////////////////////////////////////");
header.AppendLine("// MicroSplat");
header.AppendLine("// Copyright (c) Jason Booth");
header.AppendLine("//");
header.AppendLine("// Auto-generated shader code, don't hand edit!");
header.AppendLine("//");
header.AppendLine("// Unity Version: " + Application.unityVersion);
header.AppendLine("// MicroSplat Version: " + MicroSplatShaderGUI.MicroSplatVersion);
header.AppendLine("// Render Pipeline: Standard");
header.AppendLine("// Platform: " + Application.platform);
header.AppendLine("////////////////////////////////////////\n\n");
template = template.Insert(0, header);
template = template.Replace("%TAGS%", GetTags(blocks.options));
template = template.Replace("%TEMPLATE_SHARED%", templateShared.text);
template = ReplaceOrRemove(template, "%CUSTOMEDITOR%", "CustomEditor", GetOption(blocks.options, "CustomEditor"));
if (fallbackOverride != null)
{
template = template.Replace("%FALLBACK%", "Fallback \"" + fallbackOverride + "\"");
template = ReplaceOrRemove(template, "%DEPENDENCY%", "Dependency \"BaseMapShader\" = ", fallbackOverride);
}
else
{
template = ReplaceOrRemove(template, "%FALLBACK%", "Fallback", "");
template = ReplaceOrRemove(template, "%DEPENDENCY%", "Dependency", "");
}
return template;
}
public StringBuilder WriteShader(string[] features,
MicroSplatShaderGUI.MicroSplatCompiler compiler,
MicroSplatShaderGUI.MicroSplatCompiler.AuxShader auxShader,
string name,
string baseName)
{
StringBuilder defines = new StringBuilder();
var blocks = gen.GetShaderBlocks(features, compiler, auxShader);
var shader = BuildTemplate(blocks, baseName);
defines.AppendLine(blocks.defines);
defines.AppendLine("\n #define _STANDARD 1");
string shaderTarget = "3.0";
if (features.Contains("_TESSDISTANCE") || features.Contains("_FORCEMODEL46"))
{
shaderTarget = "4.6";
}
else if (features.Contains("_FORCEMODEL50"))
{
shaderTarget = "5.0";
}
if (features.Contains("_TESSDISTANCE") || features.Contains("_TESSEDGE"))
{
defines.AppendLine("\n #define _TESSELLATION_ON 1");
shader = shader.Replace("%TESSELLATION%", templateTess.text);
shader = shader.Replace("%PRAGMAS%", " #pragma hull Hull\n #pragma domain Domain\n #pragma vertex TessVert\n #pragma fragment Frag\n #pragma require tesshw\n");
}
else
{
shader = shader.Replace("%PRAGMAS%", " #pragma vertex Vert\n #pragma fragment Frag");
shader = shader.Replace("%TESSELLATION%", "");
}
shader = shader.Replace("%SHADERTARGET%", shaderTarget);
if (features.Contains("_USESPECULARWORKFLOW"))
{
defines.AppendLine("\n#define _USESPECULAR 1");
defines.AppendLine("#define _MATERIAL_FEATURE_SPECULAR_COLOR 1");
}
defines.AppendLine();
defines.AppendLine(templateCommonHLSL.text);
string shaderDesk = templateShaderDesc.text;
shaderDesk += templateChain.text;
shader = shader.Replace("%SHADERDESC%", shaderDesk);
shader = shader.Replace("%SHADERNAME%", name);
shader = shader.Replace("%PROPERTIES%", blocks.properties);
shader = shader.Replace("%CODE%", blocks.code);
shader = shader.Replace("%DEFINES%", defines.ToString());
shader = shader.Replace("%CBUFFER%", blocks.cbuffer);
string codeNoComments = blocks.code.StripComments();
shader = Strip(codeNoComments, shader);
return shader;
}
}
}