Files
stas-barecky/Library/PackageCache/com.unity.render-pipelines.universal@66e99ffa09c7/Editor/Tools/Converters/RenderSettingsConverter.cs
2026-01-08 20:43:08 +05:00

260 lines
10 KiB
C#

using System;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using ShadowQuality = UnityEngine.ShadowQuality;
namespace UnityEditor.Rendering.Universal
{
internal class RenderSettingsConverter : RenderPipelineConverter
{
public override int priority => -9000;
public override string name => "Renderer and Settings Assets Setup";
public override string info =>
"This converter creates Universal Render Pipeline (URP) assets and corresponding Renderer assets, configuring their settings " +
"to match the equivalent settings from the Built-in Render Pipeline.";
public override Type container => typeof(BuiltInToURPConverterContainer);
public override void OnInitialize(InitializeConverterContext context, Action callback)
{
QualitySettings.ForEach((index, name) =>
{
if (QualitySettings.renderPipeline is not UniversalRenderPipelineAsset)
{
context.AddAssetToConvert(new ConverterItemDescriptor
{ name = $"[{index}] {name}", info = "Quality Level must reference a Universal Render Pipeline Asset" });
}
});
callback?.Invoke();
}
Regex s_Regex = new Regex(@"^\[(\d+)\]", RegexOptions.Compiled);
public override void OnRun(ref RunItemContext context)
{
var item = context.item;
Match match = s_Regex.Match(item.descriptor.name);
if (match.Success)
{
int index = int.Parse(match.Groups[1].Value);
if (!CreateURPAssetForQualityLevel(index, out var message))
{
context.didFail = true;
context.info = L10n.Tr(message);
}
}
else
{
context.didFail = true;
context.info = L10n.Tr($"Unable to retrieve index from {item.descriptor.name}. Expected : [index] name format.");
}
}
private bool CreateURPAssetForQualityLevel(int qualityIndex, out string message)
{
bool ok = false;
message = string.Empty;
var currentQualityLevel = QualitySettings.GetQualityLevel();
QualitySettings.SetQualityLevel(qualityIndex);
if (QualitySettings.renderPipeline is UniversalRenderPipelineAsset urpAsset)
{
message = $"Quality Level {qualityIndex} already references a Universal Render Pipeline Asset: {urpAsset.name}.";
}
else
{
var asset = CreateAsset($"{QualitySettings.names[qualityIndex]}");
if (asset != null)
{
// Map built-in data to the URP asset data
SetPipelineSettings(asset);
GetRenderers(out var renderers, out var defaultIndex);
asset.m_RendererDataList = renderers;
asset.m_DefaultRendererIndex = defaultIndex;
// Set the asset dirty to make sure that the renderer data is saved
EditorUtility.SetDirty(asset);
QualitySettings.renderPipeline = asset;
ok = true;
}
else
{
message = "Failed to create Universal Render Pipeline Asset.";
}
}
// Restore back the quality level
QualitySettings.SetQualityLevel(currentQualityLevel);
return ok;
}
UniversalRenderPipelineAsset CreateAsset(string name)
{
string path = $"Assets/{UniversalProjectSettings.projectSettingsFolderPath}/{name}.asset";
if (AssetDatabase.AssetPathExists(path))
return AssetDatabase.LoadAssetAtPath<UniversalRenderPipelineAsset>(path);
try
{
CoreUtils.EnsureFolderTreeInAssetFilePath(path);
var asset = ScriptableObject.CreateInstance(typeof(UniversalRenderPipelineAsset)) as UniversalRenderPipelineAsset;
AssetDatabase.CreateAsset(asset, path);
AssetDatabase.SaveAssetIfDirty(asset);
return asset;
}
catch (Exception ex)
{
Debug.LogError($"Unable to create asset at path {path} with exception {ex.Message}");
return null;
}
}
UniversalRendererData CreateUniversalRendererDataAsset(RenderingPath renderingPath, RenderingMode renderingMode)
{
string path = $"Assets/{UniversalProjectSettings.projectSettingsFolderPath}/Default_{renderingMode}_Renderer.asset";
if (AssetDatabase.AssetPathExists(path))
return AssetDatabase.LoadAssetAtPath<UniversalRendererData>(path);
CoreUtils.EnsureFolderTreeInAssetFilePath(path);
var asset = UniversalRenderPipelineAsset.CreateRendererAsset(path, RendererType.UniversalRenderer, relativePath: false) as UniversalRendererData;
asset.renderingMode = renderingPath == RenderingPath.Forward ? RenderingMode.Forward : RenderingMode.Deferred;
return asset;
}
void GetRenderers(out ScriptableRendererData[] renderers, out int defaultIndex)
{
defaultIndex = 0;
var targetGrp = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
var tier = EditorGraphicsSettings.GetTierSettings(targetGrp, GraphicsTier.Tier3);
using (ListPool<ScriptableRendererData>.Get(out var tmp))
{
var renderingPath = tier.renderingPath;
var renderingMode = GetEquivalentRenderMode(renderingPath);
tmp.Add(CreateUniversalRendererDataAsset(renderingPath, renderingMode));
// In case we need multiple renderers modify the defaultIndex and add more renderers here
// ...
renderers = tmp.ToArray();
}
}
private void SetPipelineSettings(UniversalRenderPipelineAsset asset)
{
var targetGrp = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
var tier = EditorGraphicsSettings.GetTierSettings(targetGrp, GraphicsTier.Tier3);
var pixelLightCount = QualitySettings.pixelLightCount;
var shadows = QualitySettings.shadows;
var shadowResolution = QualitySettings.shadowResolution;
var shadowDistance = QualitySettings.shadowDistance;
var reflectionProbeBlending = tier.reflectionProbeBlending;
var reflectionProbeBoxProjection = tier.reflectionProbeBoxProjection;
bool cascadeShadows = tier.cascadedShadowMaps;
var shadowCascadeCount = QualitySettings.shadowCascades;
var cascadeSplit2 = QualitySettings.shadowCascade2Split;
var cascadeSplit4 = QualitySettings.shadowCascade4Split;
bool hdr = tier.hdr;
var msaa = QualitySettings.antiAliasing;
var softParticles = QualitySettings.softParticles;
// General
asset.supportsCameraDepthTexture = softParticles;
// Quality
asset.supportsHDR = hdr;
asset.msaaSampleCount = msaa == 0 ? 1 : msaa;
// Main Light
asset.mainLightRenderingMode = pixelLightCount == 0
? LightRenderingMode.Disabled
: LightRenderingMode.PerPixel;
asset.supportsMainLightShadows = shadows != ShadowQuality.Disable;
asset.mainLightShadowmapResolution =
GetEquivalentMainlightShadowResolution((int)shadowResolution);
// Additional Lights
asset.additionalLightsRenderingMode = pixelLightCount == 0
? LightRenderingMode.PerVertex
: LightRenderingMode.PerPixel;
asset.maxAdditionalLightsCount = pixelLightCount != 0 ? Mathf.Max(0, pixelLightCount) : 4;
asset.supportsAdditionalLightShadows = shadows != ShadowQuality.Disable;
asset.additionalLightsShadowmapResolution =
GetEquivalentAdditionalLightAtlasShadowResolution((int)shadowResolution);
// Reflection Probes
asset.reflectionProbeBlending = reflectionProbeBlending;
asset.reflectionProbeBoxProjection = reflectionProbeBoxProjection;
// Shadows
asset.shadowDistance = shadowDistance;
asset.shadowCascadeCount = cascadeShadows ? shadowCascadeCount : 1;
asset.cascade2Split = cascadeSplit2;
asset.cascade4Split = cascadeSplit4;
asset.supportsSoftShadows = shadows == ShadowQuality.All;
}
#region HelperFunctions
internal static int GetEquivalentMainlightShadowResolution(int value)
{
return GetEquivalentShadowResolution(value);
}
internal static int GetEquivalentAdditionalLightAtlasShadowResolution(int value)
{
return GetEquivalentShadowResolution(value);
}
private static int GetEquivalentShadowResolution(int value)
{
switch (value)
{
case 0: // low
return 1024;
case 1: // med
return 2048;
case 2: // high
return 4096;
case 3: // very high
return 4096;
default: // backup
return 1024;
}
}
private RenderingMode GetEquivalentRenderMode(RenderingPath path)
{
switch (path)
{
case RenderingPath.VertexLit:
case RenderingPath.Forward:
return RenderingMode.Forward;
case RenderingPath.DeferredShading:
return RenderingMode.Deferred;
default:
return RenderingMode.Forward;
}
}
#endregion
}
}