316 lines
12 KiB
C#
316 lines
12 KiB
C#
// Stylized Water 3 by Staggart Creations (http://staggart.xyz)
|
|
// COPYRIGHT PROTECTED UNDER THE UNITY ASSET STORE EULA (https://unity.com/legal/as-terms)
|
|
// • Copying or referencing source code for the production of new asset store, or public, content is strictly prohibited!
|
|
// • Uploading this file to a public repository will subject it to an automated DMCA takedown request.
|
|
|
|
#if SWS_DEV
|
|
#define ENABLE_SHADER_STRIPPING_LOG
|
|
#endif
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using UnityEditor;
|
|
using UnityEditor.Build;
|
|
using UnityEditor.Rendering;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Serialization;
|
|
using Debug = UnityEngine.Debug;
|
|
using Object = UnityEngine.Object;
|
|
using Random = UnityEngine.Random;
|
|
#if URP
|
|
using UnityEngine.Rendering.Universal;
|
|
#endif
|
|
|
|
namespace StylizedWater3
|
|
{
|
|
public static class ShaderConfigurator
|
|
{
|
|
public const string DEFAULT_SHADER_GUID = "823f6b206953b674a9a64f9e3ec57752";
|
|
|
|
public static Shader GetDefaultShader()
|
|
{
|
|
string defaultShaderPath = AssetDatabase.GUIDToAssetPath(DEFAULT_SHADER_GUID);
|
|
Shader defaultShader = AssetDatabase.LoadAssetAtPath<Shader>(defaultShaderPath);
|
|
|
|
return defaultShader;
|
|
}
|
|
|
|
public static ShaderMessage[] GetErrorMessages(Shader shader)
|
|
{
|
|
ShaderMessage[] messages = null;
|
|
|
|
int n = ShaderUtil.GetShaderMessageCount(shader);
|
|
|
|
if (n < 1) return messages;
|
|
|
|
messages = ShaderUtil.GetShaderMessages(shader);
|
|
|
|
//Filter for errors
|
|
messages = messages.Where(x => x.severity == ShaderCompilerMessageSeverity.Error).ToArray();
|
|
|
|
return messages;
|
|
}
|
|
|
|
#if URP
|
|
//Strips keywords from the shader for features belonging to newer URP versions.
|
|
private class KeywordStripper : IPreprocessShaders
|
|
{
|
|
private const string LOG_FILEPATH = "Logs/Stylized Water 3 Compilation.log";
|
|
|
|
#if ENABLE_SHADER_STRIPPING_LOG
|
|
private System.Diagnostics.Stopwatch m_stripTimer = new System.Diagnostics.Stopwatch();
|
|
#endif
|
|
|
|
private List<ShaderKeyword> StrippedKeywords = new List<ShaderKeyword>();
|
|
|
|
//URP 18+
|
|
private readonly ShaderKeyword _TEST = new ShaderKeyword("_TEST");
|
|
|
|
private readonly bool heightPrePassEnabled;
|
|
|
|
#if SWS_DEV
|
|
[MenuItem("SWS/Debug/HeightPrePassEnabled")]
|
|
#endif
|
|
private static bool HeightPrePassEnabled()
|
|
{
|
|
bool state = false;
|
|
|
|
if (StylizedWaterRenderFeature.RequireHeightPrePass) return true;
|
|
|
|
//Check if the displacement pre-pass is enabled anywhere
|
|
for (int i = 0; i < GraphicsSettings.allConfiguredRenderPipelines.Length; i++)
|
|
{
|
|
UniversalRenderPipelineAsset pipeline = (UniversalRenderPipelineAsset)GraphicsSettings.allConfiguredRenderPipelines[i];
|
|
|
|
ScriptableRendererData[] renderers = PipelineUtilities.GetRenderDataList(pipeline);
|
|
|
|
for (int j = 0; j < renderers.Length; j++)
|
|
{
|
|
StylizedWaterRenderFeature renderFeature = (StylizedWaterRenderFeature)PipelineUtilities.GetRenderFeature<StylizedWaterRenderFeature>(renderers[j]);
|
|
|
|
if (renderFeature)
|
|
{
|
|
state |= renderFeature.heightPrePassSettings.enable;
|
|
|
|
#if SWS_DEV
|
|
//Debug.Log($"{renderers[j].name}. Enable?:{renderFeature.heightPrePassSettings.enable}");
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#if SWS_DEV
|
|
//Debug.Log("Height pre-pass enabled somewhere: " + state);
|
|
#endif
|
|
|
|
return state;
|
|
}
|
|
|
|
//Note: Constructor is called once, when building starts
|
|
public KeywordStripper()
|
|
{
|
|
if (PlayerSettings.GetGraphicsAPIs(EditorUserBuildSettings.activeBuildTarget)[0] == GraphicsDeviceType.OpenGLES3)
|
|
{
|
|
if (UniversalRenderPipeline.asset.msaaSampleCount > 1)
|
|
{
|
|
Debug.LogWarning("[Stylized Water 3] You are deploying a build using the OpenGLES 3.0 graphics API with MSAA enabled (in your URP pipeline asset). Due to a bug in some graphics chips, transparent materials (including the water) will not render. " +
|
|
"Disable MSAA, or use the Vulkan graphics API", UniversalRenderPipeline.asset);
|
|
}
|
|
}
|
|
|
|
//Check if the displacement pre-pass is enabled anywhere
|
|
heightPrePassEnabled = HeightPrePassEnabled();
|
|
|
|
StrippedKeywords.Clear();
|
|
|
|
if (!heightPrePassEnabled)
|
|
{
|
|
StrippedKeywords.Add(new ShaderKeyword(ShaderParams.Keywords.WaterHeightPass));
|
|
}
|
|
|
|
//Note: Keywords for extensions are only injected through the shader generator. Hence they don't need to be stripped
|
|
|
|
#if !UNITY_6000_0_OR_NEWER
|
|
StrippedKeywords.Add(_TEST);
|
|
#endif
|
|
|
|
LogInitialization();
|
|
}
|
|
|
|
public int callbackOrder => 0;
|
|
|
|
public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> compilerDataList)
|
|
{
|
|
#if URP
|
|
if (UniversalRenderPipeline.asset == null || compilerDataList == null || compilerDataList.Count == 0) return;
|
|
|
|
//Only run for specific shaders
|
|
if (shader.name.Contains("Stylized Water 3") == false) return;
|
|
|
|
LogStart(shader, snippet, compilerDataList);
|
|
|
|
var inputShaderVariantCount = compilerDataList.Count;
|
|
for (int i = 0; i < inputShaderVariantCount;)
|
|
{
|
|
//If any of the excluded keywords are enabled in this variant, strip it
|
|
bool removeInput = StripUnused(shader, compilerDataList[i], snippet);
|
|
|
|
// Remove at swap back
|
|
if (removeInput)
|
|
compilerDataList[i] = compilerDataList[--inputShaderVariantCount];
|
|
else
|
|
++i;
|
|
}
|
|
|
|
if (compilerDataList is List<ShaderCompilerData> inputDataList)
|
|
{
|
|
inputDataList.RemoveRange(inputShaderVariantCount, inputDataList.Count - inputShaderVariantCount);
|
|
}
|
|
else
|
|
{
|
|
for (int i = compilerDataList.Count - 1; i >= inputShaderVariantCount; --i)
|
|
compilerDataList.RemoveAt(i);
|
|
}
|
|
|
|
LogStrippingEnd(compilerDataList.Count);
|
|
#endif
|
|
}
|
|
|
|
private bool StripUnused(Shader shader, ShaderCompilerData compilerData, ShaderSnippetData snippet)
|
|
{
|
|
if (StripPass(shader, snippet))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
foreach (var keyword in StrippedKeywords)
|
|
{
|
|
if (StripKeyword(shader, keyword, compilerData, snippet))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool StripPass(Shader shader, ShaderSnippetData snippet)
|
|
{
|
|
if (heightPrePassEnabled == false && snippet.passName == ShaderParams.Passes.HeightPrePass)
|
|
{
|
|
Log($"- Stripped Pass {snippet.passName} ({shader.name}) (Stage: {snippet.shaderType})");
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool StripKeyword(Shader shader, ShaderKeyword keyword, ShaderCompilerData compilerData, ShaderSnippetData snippet)
|
|
{
|
|
if (compilerData.shaderKeywordSet.IsEnabled(keyword))
|
|
{
|
|
LogStripping(shader, keyword, snippet);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#region Logging
|
|
struct StrippingLog
|
|
{
|
|
public Shader shader;
|
|
public ShaderKeyword keyword;
|
|
public string passName;
|
|
public ShaderType shaderType;
|
|
}
|
|
|
|
private void LogInitialization()
|
|
{
|
|
#if ENABLE_SHADER_STRIPPING_LOG
|
|
//Clear log file first
|
|
File.WriteAllLines(LOG_FILEPATH, new string[] {});
|
|
|
|
Log("KeywordStripper initialized...", true);
|
|
|
|
Log(string.Empty);
|
|
|
|
Log($"Displacement Pre-pass enabled in build: {heightPrePassEnabled}", true);
|
|
|
|
Log(string.Empty);
|
|
|
|
for (int i = 0; i < StrippedKeywords.Count; i++)
|
|
{
|
|
Log($"• {StrippedKeywords[i].name} keyword to be stripped");
|
|
}
|
|
|
|
Log($"{StrippedKeywords.Count} total keywords to be stripped");
|
|
#endif
|
|
}
|
|
|
|
private void LogStart(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> compilerDataList)
|
|
{
|
|
#if ENABLE_SHADER_STRIPPING_LOG
|
|
m_stripTimer.Start();
|
|
|
|
var text = $"OnProcessShader running for {shader.name}. (Pass: {snippet.passName}) (Stage: {snippet.shaderType}). Num variants: {compilerDataList.Count}";
|
|
|
|
Log(text, true);
|
|
#endif
|
|
}
|
|
|
|
StrippingLog prevLog;
|
|
|
|
private void LogStripping(Shader shader, ShaderKeyword keyword, ShaderSnippetData snippet)
|
|
{
|
|
#if ENABLE_SHADER_STRIPPING_LOG
|
|
|
|
//Try to avoid spamming the log with duplicates, this otherwise slows down compilation to a crawl
|
|
if (prevLog.keyword.index == keyword.index && prevLog.shader == shader && prevLog.passName == snippet.passName && prevLog.shaderType == snippet.shaderType)
|
|
{
|
|
//File.AppendAllText(LOG_FILEPATH, "- Skipping log!\n" );
|
|
return;
|
|
}
|
|
|
|
prevLog.shader = shader;
|
|
prevLog.keyword = keyword;
|
|
prevLog.passName = snippet.passName;
|
|
prevLog.shaderType = snippet.shaderType;
|
|
|
|
var text = $"- Stripped {keyword.name} ({shader.name}) variant. (Pass {snippet.passName}) (Stage: {snippet.shaderType})";
|
|
|
|
Log(text);
|
|
#endif
|
|
}
|
|
|
|
private void LogStrippingEnd(int count)
|
|
{
|
|
#if ENABLE_SHADER_STRIPPING_LOG
|
|
m_stripTimer.Stop();
|
|
System.TimeSpan stripTimespan = m_stripTimer.Elapsed;
|
|
|
|
var text = $"Stripping took {stripTimespan.Minutes}m{stripTimespan.Seconds}s ({stripTimespan.Milliseconds}ms). Remaining variants to compile: {count}";
|
|
|
|
Log(text);
|
|
|
|
m_stripTimer.Reset();
|
|
#endif
|
|
}
|
|
|
|
private void Log(string text, bool newLine = false)
|
|
{
|
|
#if ENABLE_SHADER_STRIPPING_LOG
|
|
File.AppendAllText(LOG_FILEPATH, (newLine ? "\n" : "") + text + "\n");
|
|
#endif
|
|
}
|
|
#endregion
|
|
}
|
|
#endif
|
|
}
|
|
} |