riversong code showcase
This commit is contained in:
75
Source/Riversong/Game/Rendering/AoERenderingSystem.cs
Normal file
75
Source/Riversong/Game/Rendering/AoERenderingSystem.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[Service(typeof(IAoERenderingService))]
|
||||
[GameSystemGroup(typeof(LateGameSystemGroup))]
|
||||
public class AoERenderingSystem : GameSystem, IInitializable, IDisposable, IUpdatable, IAoERenderingService
|
||||
{
|
||||
private const int MaxAoECount = 16;
|
||||
|
||||
private static readonly int AoESourcesPropertyID = Shader.PropertyToID("_AoE_Sources");
|
||||
|
||||
private static readonly int AoECountPropertyID = Shader.PropertyToID("_AoE_Count");
|
||||
|
||||
[InjectService]
|
||||
private GameConfig _config;
|
||||
|
||||
[InjectService]
|
||||
private IBuildingVisualizationCollection _buildingVisualizationCollection;
|
||||
|
||||
private ComputeBuffer _aoeBuffer;
|
||||
|
||||
private List<AoE> _data = new(MaxAoECount);
|
||||
|
||||
public AoERenderingSystem(IServiceLocator serviceLocator) : base(serviceLocator)
|
||||
{
|
||||
}
|
||||
|
||||
public UniTask InitializeAsync()
|
||||
{
|
||||
_aoeBuffer = new ComputeBuffer(MaxAoECount, sizeof(int) + sizeof(float) * 4, ComputeBufferType.Structured, ComputeBufferMode.Dynamic);
|
||||
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_aoeBuffer.Dispose();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
_aoeBuffer.SetData(_data);
|
||||
|
||||
var material = _config.Vfx.AoEMaterial;
|
||||
material.SetBuffer(AoESourcesPropertyID, _aoeBuffer);
|
||||
material.SetInt(AoECountPropertyID, _data.Count);
|
||||
|
||||
_data.Clear();
|
||||
}
|
||||
|
||||
public void Add(int layer, TileRect rect)
|
||||
{
|
||||
_data.Add(
|
||||
new AoE
|
||||
{
|
||||
Layer = layer,
|
||||
Rect = new float4(rect.Min, rect.Max)
|
||||
});
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct AoE
|
||||
{
|
||||
public int Layer;
|
||||
|
||||
public float4 Rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[GameSystemGroup(typeof(LateGameSystemGroup))]
|
||||
public class GlobalShaderParametersSystem : GameSystem, IInitializable, IDisposable, IUpdatable
|
||||
{
|
||||
[InjectService]
|
||||
private World _world;
|
||||
|
||||
[InjectService]
|
||||
private ISignalBus _signalBus;
|
||||
|
||||
public GlobalShaderParametersSystem(IServiceLocator serviceLocator) : base(serviceLocator)
|
||||
{
|
||||
}
|
||||
|
||||
public UniTask InitializeAsync()
|
||||
{
|
||||
_signalBus.Subscribe<WorldReadySignal>(OnWorldReady);
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_signalBus.Unsubscribe<WorldReadySignal>(OnWorldReady);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var t = Time.unscaledTime;
|
||||
Shader.SetGlobalVector(ShaderProperties.UnscaledTime, new Vector4(t / 20, t, t * 2, t * 3));
|
||||
}
|
||||
|
||||
private void OnWorldReady(WorldReadySignal signal)
|
||||
{
|
||||
Shader.SetGlobalVector(ShaderProperties.WorldSize, new Vector4(_world.Size.x, _world.Size.y, 0, 0));
|
||||
Shader.SetGlobalVector(ShaderProperties.InverseWorldSize, new Vector2(1 / (float)_world.Size.x, 1 / (float)_world.Size.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
7
Source/Riversong/Game/Rendering/IAoERenderingService.cs
Normal file
7
Source/Riversong/Game/Rendering/IAoERenderingService.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public interface IAoERenderingService
|
||||
{
|
||||
void Add(int layer, TileRect rect);
|
||||
}
|
||||
}
|
||||
132
Source/Riversong/Game/Rendering/MaterialReplacementCache.cs
Normal file
132
Source/Riversong/Game/Rendering/MaterialReplacementCache.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Pool;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class MaterialReplacementCache
|
||||
{
|
||||
private static readonly int BaseMapPropertyId = Shader.PropertyToID("_BaseMap");
|
||||
|
||||
private static readonly int MainTexPropertyId = Shader.PropertyToID("_MainTex");
|
||||
|
||||
private static readonly int MainTexturePropertyId = Shader.PropertyToID("_Main_Texture");
|
||||
|
||||
private HashSet<int> _gameObjects = new();
|
||||
|
||||
private List<(Renderer, Material, int, MaterialPropertyBlock)> _cache = new();
|
||||
|
||||
private List<MaterialPropertyBlock> _propertyBlockPool = new();
|
||||
|
||||
private int _propertyBlockPoolIndex;
|
||||
|
||||
private MaterialPropertyBlock _propertyBlock;
|
||||
|
||||
public static void ReplaceRendererMaterials(Renderer renderer, Material material, MaterialPropertyBlock propertyBlock)
|
||||
{
|
||||
var materials = renderer.sharedMaterials;
|
||||
|
||||
for (var i = 0; i < materials.Length; i++)
|
||||
{
|
||||
var originalMaterial = materials[i];
|
||||
materials[i] = material;
|
||||
ReplaceTexture(renderer, originalMaterial, i, propertyBlock, null);
|
||||
}
|
||||
|
||||
renderer.sharedMaterials = materials;
|
||||
}
|
||||
|
||||
public void ReplaceMaterials(GameObject gameObject, Material material)
|
||||
{
|
||||
if (!_gameObjects.Add(gameObject.GetInstanceID())) return;
|
||||
|
||||
using var renderersScope = ListPool<Renderer>.Get(out var renderers);
|
||||
gameObject.GetComponentsInChildren(renderers);
|
||||
|
||||
foreach (var renderer in renderers) ReplaceMaterials(renderer, material);
|
||||
}
|
||||
|
||||
public void ReplaceMaterials(List<GameObject> gameObjects, Material material)
|
||||
{
|
||||
if (gameObjects.Count == 0) return;
|
||||
|
||||
using var renderersScope = ListPool<Renderer>.Get(out var renderers);
|
||||
|
||||
foreach (var gameObject in gameObjects)
|
||||
{
|
||||
if (!_gameObjects.Add(gameObject.GetInstanceID())) continue;
|
||||
|
||||
renderers.Clear();
|
||||
gameObject.GetComponentsInChildren(renderers);
|
||||
|
||||
foreach (var renderer in renderers) ReplaceMaterials(renderer, material);
|
||||
}
|
||||
}
|
||||
|
||||
public void RestoreMaterials()
|
||||
{
|
||||
foreach (var (renderer, material, i, propertyBlock) in _cache)
|
||||
{
|
||||
if (!renderer) continue;
|
||||
|
||||
var materials = renderer.sharedMaterials;
|
||||
materials[i] = material;
|
||||
renderer.sharedMaterials = materials;
|
||||
renderer.SetPropertyBlock(propertyBlock, i);
|
||||
}
|
||||
|
||||
_gameObjects.Clear();
|
||||
_cache.Clear();
|
||||
_propertyBlockPoolIndex = 0;
|
||||
}
|
||||
|
||||
private void ReplaceMaterials(Renderer renderer, Material material)
|
||||
{
|
||||
var materials = renderer.sharedMaterials;
|
||||
|
||||
_propertyBlock ??= new MaterialPropertyBlock();
|
||||
for (var i = 0; i < materials.Length; i++)
|
||||
{
|
||||
var currentPropertyBlock = GetPooledPropertyBlock();
|
||||
renderer.GetPropertyBlock(currentPropertyBlock, i);
|
||||
|
||||
_cache.Add((renderer, materials[i], i, currentPropertyBlock));
|
||||
|
||||
var originalMaterial = materials[i];
|
||||
materials[i] = material;
|
||||
ReplaceTexture(renderer, originalMaterial, i, _propertyBlock, currentPropertyBlock);
|
||||
}
|
||||
|
||||
renderer.sharedMaterials = materials;
|
||||
}
|
||||
|
||||
private MaterialPropertyBlock GetPooledPropertyBlock()
|
||||
{
|
||||
if (_propertyBlockPoolIndex >= _propertyBlockPool.Count) _propertyBlockPool.Add(new MaterialPropertyBlock());
|
||||
|
||||
var propertyBlock = _propertyBlockPool[_propertyBlockPoolIndex++];
|
||||
propertyBlock.Clear();
|
||||
|
||||
return propertyBlock;
|
||||
}
|
||||
|
||||
private static void ReplaceTexture(Renderer renderer, Material material, int materialIndex, MaterialPropertyBlock propertyBlock, MaterialPropertyBlock sourcePropertyBlock)
|
||||
{
|
||||
var texture = GetMainTexture(material);
|
||||
if (!texture) texture = sourcePropertyBlock?.GetTexture(MainTexturePropertyId);
|
||||
if (!texture) return;
|
||||
|
||||
propertyBlock.Clear();
|
||||
propertyBlock.SetTexture(MainTexturePropertyId, texture);
|
||||
|
||||
renderer.SetPropertyBlock(propertyBlock, materialIndex);
|
||||
}
|
||||
|
||||
private static Texture GetMainTexture(Material material)
|
||||
{
|
||||
if (material.HasProperty(BaseMapPropertyId)) return material.GetTexture(BaseMapPropertyId);
|
||||
if (material.HasProperty(MainTexPropertyId)) return material.GetTexture(MainTexPropertyId);
|
||||
return material.HasProperty(MainTexturePropertyId) ? material.GetTexture(MainTexturePropertyId) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[GameSystemGroup(typeof(EarlyGameSystemGroup))]
|
||||
public class RenderingInitializationGameSystem : GameSystem, IServiceProvider
|
||||
{
|
||||
public RenderingInitializationGameSystem(IServiceLocator serviceLocator) : base(serviceLocator)
|
||||
{
|
||||
}
|
||||
|
||||
public void RegisterServices(IServiceLocator serviceLocator)
|
||||
{
|
||||
serviceLocator.RegisterService(new WorldRenderingState());
|
||||
}
|
||||
}
|
||||
}
|
||||
19
Source/Riversong/Game/Rendering/ShaderProperties.cs
Normal file
19
Source/Riversong/Game/Rendering/ShaderProperties.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public static class ShaderProperties
|
||||
{
|
||||
public static readonly int Color = Shader.PropertyToID("_Color");
|
||||
|
||||
public static readonly int Amount = Shader.PropertyToID("_Amount");
|
||||
|
||||
public static readonly int UnscaledTime = Shader.PropertyToID("_Unscaled_Time");
|
||||
|
||||
public static readonly int WorldSize = Shader.PropertyToID("_World_Size");
|
||||
|
||||
public static readonly int InverseWorldSize = Shader.PropertyToID("_Inverse_World_Size");
|
||||
|
||||
public static readonly int NightBlend = Shader.PropertyToID("_Night_Blend");
|
||||
}
|
||||
}
|
||||
19
Source/Riversong/Game/Rendering/WorldRenderingState.cs
Normal file
19
Source/Riversong/Game/Rendering/WorldRenderingState.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
public class WorldRenderingState
|
||||
{
|
||||
/// <summary>
|
||||
/// All terrain chunks. Use <see cref="AddTerrainChunk" /> to register new chunks with the rendering state.
|
||||
/// </summary>
|
||||
public List<TerrainChunk> TerrainChunks { get; } = new();
|
||||
|
||||
public TileHighlight TileHighlight { get; } = new();
|
||||
|
||||
public void AddTerrainChunk(TerrainChunk chunk)
|
||||
{
|
||||
TerrainChunks.Add(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user