Integrate Aetheria reactive state worktree
This commit is contained in:
parent
426cd8f656
commit
65133ac8a0
61 changed files with 3427 additions and 402 deletions
241
Assets/Scripts/Gameplay/AetheriaRenderSplatLayerRenderer.cs
Normal file
241
Assets/Scripts/Gameplay/AetheriaRenderSplatLayerRenderer.cs
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GameCult.Aetheria.State.Verse;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public sealed class AetheriaRenderSplatLayerRenderer : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private AetheriaRenderSplatRasterizer rasterizer;
|
||||
|
||||
[SerializeField]
|
||||
private AetheriaRenderSplatLayerBinding[] bindings =
|
||||
{
|
||||
new AetheriaRenderSplatLayerBinding
|
||||
{
|
||||
LayerKey = AetheriaRuntimeRenderSplatLayerKeys.GravityHeight,
|
||||
MaterialTextureProperty = "_DetailTex",
|
||||
GlobalTextureName = "_AetheriaGravityHeight"
|
||||
},
|
||||
new AetheriaRenderSplatLayerBinding
|
||||
{
|
||||
LayerKey = AetheriaRuntimeRenderSplatLayerKeys.FogTint,
|
||||
MaterialTextureProperty = "_DetailTex",
|
||||
GlobalTextureName = "_NebulaTint"
|
||||
},
|
||||
new AetheriaRenderSplatLayerBinding
|
||||
{
|
||||
LayerKey = AetheriaRuntimeRenderSplatLayerKeys.FogSurfaceHeight,
|
||||
GlobalTextureName = "_NebulaSurfaceHeight",
|
||||
WidthScale = 0.5f,
|
||||
HeightScale = 0.5f
|
||||
},
|
||||
new AetheriaRenderSplatLayerBinding
|
||||
{
|
||||
LayerKey = AetheriaRuntimeRenderSplatLayerKeys.FogPatchHeight,
|
||||
GlobalTextureName = "_NebulaPatchHeight",
|
||||
WidthScale = 0.5f,
|
||||
HeightScale = 0.5f
|
||||
},
|
||||
new AetheriaRenderSplatLayerBinding
|
||||
{
|
||||
LayerKey = AetheriaRuntimeRenderSplatLayerKeys.FogPatch,
|
||||
GlobalTextureName = "_NebulaPatch",
|
||||
WidthScale = 0.5f,
|
||||
HeightScale = 0.5f
|
||||
},
|
||||
new AetheriaRenderSplatLayerBinding
|
||||
{
|
||||
LayerKey = AetheriaRuntimeRenderSplatLayerKeys.Influence,
|
||||
MaterialTextureProperty = "_DetailTex",
|
||||
GlobalTextureName = "_AetheriaInfluence"
|
||||
}
|
||||
};
|
||||
|
||||
private readonly Dictionary<string, RenderTexture> _texturesByLayerKey =
|
||||
new Dictionary<string, RenderTexture>(StringComparer.Ordinal);
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
rasterizer = GetComponent<AetheriaRenderSplatRasterizer>();
|
||||
}
|
||||
|
||||
public bool TryGetTexture(string layerKey, out RenderTexture texture)
|
||||
{
|
||||
return _texturesByLayerKey.TryGetValue(layerKey ?? "", out texture);
|
||||
}
|
||||
|
||||
public void Render(
|
||||
AetheriaRuntimeRenderSplatsViewportDocument document,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
if (document == null)
|
||||
return;
|
||||
|
||||
ResolveRasterizer();
|
||||
if (rasterizer == null)
|
||||
return;
|
||||
|
||||
var layers = document.Layers ?? Array.Empty<AetheriaRuntimeRenderSplatLayerDefinition>();
|
||||
for (var layerIndex = 0; layerIndex < layers.Count; layerIndex++)
|
||||
{
|
||||
var layer = layers[layerIndex];
|
||||
if (layer == null || string.IsNullOrWhiteSpace(layer.LayerKey))
|
||||
continue;
|
||||
|
||||
foreach (var binding in bindings ?? Array.Empty<AetheriaRenderSplatLayerBinding>())
|
||||
{
|
||||
if (binding == null ||
|
||||
!binding.Enabled ||
|
||||
!string.Equals(binding.LayerKey, layer.LayerKey, StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var texture = EnsureTexture(binding, layer, width, height);
|
||||
rasterizer.RenderLayerToTarget(
|
||||
document,
|
||||
texture,
|
||||
layerIndex,
|
||||
ResolveMaterialPass(layer.BlendMode),
|
||||
ResolveClearColor(layer));
|
||||
ApplyBinding(binding, texture);
|
||||
_texturesByLayerKey[layer.LayerKey] = texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveRasterizer()
|
||||
{
|
||||
if (rasterizer != null)
|
||||
return;
|
||||
|
||||
rasterizer = GetComponent<AetheriaRenderSplatRasterizer>();
|
||||
if (rasterizer == null)
|
||||
rasterizer = gameObject.AddComponent<AetheriaRenderSplatRasterizer>();
|
||||
}
|
||||
|
||||
private RenderTexture EnsureTexture(
|
||||
AetheriaRenderSplatLayerBinding binding,
|
||||
AetheriaRuntimeRenderSplatLayerDefinition layer,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
var targetWidth = math.max(1, Mathf.RoundToInt(width * Mathf.Max(0.01f, binding.WidthScale)));
|
||||
var targetHeight = math.max(1, Mathf.RoundToInt(height * Mathf.Max(0.01f, binding.HeightScale)));
|
||||
var format = ResolveGraphicsFormat(binding.GraphicsFormatOverride, layer.GraphicsFormat);
|
||||
var existing = binding.TargetTexture;
|
||||
if (existing != null &&
|
||||
existing.width == targetWidth &&
|
||||
existing.height == targetHeight &&
|
||||
existing.graphicsFormat == format)
|
||||
{
|
||||
return existing;
|
||||
}
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
existing.Release();
|
||||
Destroy(existing);
|
||||
}
|
||||
|
||||
var descriptor = new RenderTextureDescriptor(targetWidth, targetHeight)
|
||||
{
|
||||
depthBufferBits = 0,
|
||||
graphicsFormat = format,
|
||||
msaaSamples = 1,
|
||||
sRGB = false,
|
||||
useMipMap = binding.UseMipMaps,
|
||||
autoGenerateMips = binding.UseMipMaps
|
||||
};
|
||||
binding.TargetTexture = new RenderTexture(descriptor)
|
||||
{
|
||||
name = $"Aetheria {layer.LayerKey}",
|
||||
filterMode = binding.FilterMode,
|
||||
wrapMode = TextureWrapMode.Clamp
|
||||
};
|
||||
binding.TargetTexture.Create();
|
||||
return binding.TargetTexture;
|
||||
}
|
||||
|
||||
private static GraphicsFormat ResolveGraphicsFormat(string bindingOverride, string layerFormat)
|
||||
{
|
||||
var value = string.IsNullOrWhiteSpace(bindingOverride) ? layerFormat : bindingOverride;
|
||||
return Enum.TryParse(value, out GraphicsFormat format)
|
||||
? format
|
||||
: GraphicsFormat.R16_SFloat;
|
||||
}
|
||||
|
||||
private static int ResolveMaterialPass(string blendMode)
|
||||
{
|
||||
switch (blendMode)
|
||||
{
|
||||
case AetheriaRuntimeRenderSplatBlendModes.Max:
|
||||
return 1;
|
||||
case AetheriaRuntimeRenderSplatBlendModes.Alpha:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static Color ResolveClearColor(AetheriaRuntimeRenderSplatLayerDefinition layer)
|
||||
{
|
||||
return new Color(
|
||||
(float)layer.ClearR,
|
||||
(float)layer.ClearG,
|
||||
(float)layer.ClearB,
|
||||
(float)layer.ClearA);
|
||||
}
|
||||
|
||||
private static void ApplyBinding(AetheriaRenderSplatLayerBinding binding, RenderTexture texture)
|
||||
{
|
||||
if (binding.Display != null)
|
||||
{
|
||||
var material = binding.Display.material;
|
||||
if (material != null && !string.IsNullOrWhiteSpace(binding.MaterialTextureProperty))
|
||||
material.SetTexture(binding.MaterialTextureProperty, texture);
|
||||
else
|
||||
binding.Display.material.mainTexture = texture;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(binding.GlobalTextureName))
|
||||
Shader.SetGlobalTexture(binding.GlobalTextureName, texture);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
foreach (var binding in bindings ?? Array.Empty<AetheriaRenderSplatLayerBinding>())
|
||||
{
|
||||
if (binding?.TargetTexture == null)
|
||||
continue;
|
||||
|
||||
binding.TargetTexture.Release();
|
||||
Destroy(binding.TargetTexture);
|
||||
binding.TargetTexture = null;
|
||||
}
|
||||
|
||||
_texturesByLayerKey.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class AetheriaRenderSplatLayerBinding
|
||||
{
|
||||
public bool Enabled = true;
|
||||
public string LayerKey = "";
|
||||
public Image Display;
|
||||
public string MaterialTextureProperty = "_DetailTex";
|
||||
public string GlobalTextureName = "";
|
||||
public string GraphicsFormatOverride = "";
|
||||
public float WidthScale = 1.0f;
|
||||
public float HeightScale = 1.0f;
|
||||
public bool UseMipMaps;
|
||||
public FilterMode FilterMode = FilterMode.Bilinear;
|
||||
[NonSerialized]
|
||||
public RenderTexture TargetTexture;
|
||||
}
|
||||
Loading…
Reference in a new issue