Consume EveUnity fields projection
This commit is contained in:
parent
b23588f396
commit
002e709e98
13 changed files with 27 additions and 655 deletions
|
|
@ -15,5 +15,6 @@
|
|||
<ProjectReference Include="..\..\CultLib\src\GameCult.Networking\GameCult.Networking.csproj" />
|
||||
<ProjectReference Include="..\..\CultMath\src\CultMath\CultMath.csproj" />
|
||||
<ProjectReference Include="..\GameCult.Eve.Surface.csproj" />
|
||||
<ProjectReference Include="..\..\EvePlugins\plugins\eve-plugin-fields\GameCult.Eve.PluginFields.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,137 +0,0 @@
|
|||
using GameCult.Aetheria.State.Verse;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
public sealed class AetheriaRenderSplatBuffer : System.IDisposable
|
||||
{
|
||||
public const string SplatBufferPropertyName = "_AetheriaSplats";
|
||||
public const string SplatCountPropertyName = "_AetheriaSplatCount";
|
||||
public const string ViewportToClipPropertyName = "_AetheriaViewportToClip";
|
||||
public const string ChannelFilterPropertyName = "_AetheriaChannelFilter";
|
||||
|
||||
private const int SplatStrideBytes = 80;
|
||||
|
||||
private AetheriaRenderSplat[] _splats = System.Array.Empty<AetheriaRenderSplat>();
|
||||
private GraphicsBuffer _buffer;
|
||||
private int _capacity;
|
||||
|
||||
public int Count { get; private set; }
|
||||
public GraphicsBuffer Buffer => _buffer;
|
||||
public bool HasGpuBuffer => _buffer != null && _buffer.IsValid() && Count > 0;
|
||||
|
||||
public bool Upload(AetheriaRuntimeRenderSplatSoa splats, int channelFilter = -1, int layerFilter = -1)
|
||||
{
|
||||
Count = Pack(splats, channelFilter, layerFilter);
|
||||
EnsureCapacity(Count);
|
||||
if (Count <= 0)
|
||||
return false;
|
||||
|
||||
_buffer.SetData(_splats, 0, 0, Count);
|
||||
return true;
|
||||
}
|
||||
|
||||
private int Pack(AetheriaRuntimeRenderSplatSoa splats, int channelFilter, int layerFilter)
|
||||
{
|
||||
if (splats == null || splats.Count <= 0)
|
||||
return 0;
|
||||
|
||||
EnsureCpuCapacity(splats.Count);
|
||||
var count = 0;
|
||||
for (var i = 0; i < splats.Count; i++)
|
||||
{
|
||||
var channel = Read(splats.Channel, i, 0);
|
||||
if (channelFilter >= 0 && channel != channelFilter)
|
||||
continue;
|
||||
|
||||
var layerIndex = Read(splats.LayerIndex, i, -1);
|
||||
if (layerFilter >= 0 && layerIndex != layerFilter)
|
||||
continue;
|
||||
|
||||
var halfExtentX = (float)Read(splats.HalfExtentX, i, 0);
|
||||
var halfExtentY = (float)Read(splats.HalfExtentY, i, 0);
|
||||
if (halfExtentX <= 0 || halfExtentY <= 0)
|
||||
continue;
|
||||
|
||||
_splats[count++] = new AetheriaRenderSplat
|
||||
{
|
||||
CenterHalfExtent = new float4(
|
||||
(float)Read(splats.CenterX, i, 0),
|
||||
(float)Read(splats.CenterY, i, 0),
|
||||
halfExtentX,
|
||||
halfExtentY),
|
||||
RotationChannelFalloff = new float4(
|
||||
(float)Read(splats.RotationCos, i, 1),
|
||||
(float)Read(splats.RotationSin, i, 0),
|
||||
channel,
|
||||
Read(splats.Falloff, i, AetheriaRuntimeRenderSplatFalloffs.Smooth)),
|
||||
LayerSource = new float4(
|
||||
layerIndex,
|
||||
Read(splats.SourceKind, i, AetheriaRuntimeRenderSplatSourceKinds.Constant),
|
||||
(float)Read(splats.AnimationSpeed, i, 0),
|
||||
(float)Read(splats.SourceFlags, i, 0)),
|
||||
SourceFrequencyPhase = new float4(
|
||||
(float)Read(splats.FrequencyX, i, 1),
|
||||
(float)Read(splats.FrequencyY, i, 1),
|
||||
(float)Read(splats.PhaseX, i, 0),
|
||||
(float)Read(splats.PhaseY, i, 0)),
|
||||
Value = new float4(
|
||||
(float)Read(splats.ValueR, i, 0),
|
||||
(float)Read(splats.ValueG, i, 0),
|
||||
(float)Read(splats.ValueB, i, 0),
|
||||
(float)Read(splats.ValueA, i, 1))
|
||||
};
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private void EnsureCpuCapacity(int count)
|
||||
{
|
||||
if (_splats.Length >= count)
|
||||
return;
|
||||
|
||||
_splats = new AetheriaRenderSplat[math.ceilpow2(math.max(1, count))];
|
||||
}
|
||||
|
||||
private void EnsureCapacity(int count)
|
||||
{
|
||||
if (_buffer != null && _buffer.IsValid() && _capacity >= count)
|
||||
return;
|
||||
|
||||
_buffer?.Release();
|
||||
_buffer = null;
|
||||
_capacity = 0;
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
_capacity = math.ceilpow2(math.max(1, count));
|
||||
_buffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, _capacity, SplatStrideBytes);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_buffer?.Release();
|
||||
_buffer = null;
|
||||
_capacity = 0;
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
private static double Read(System.Collections.Generic.IReadOnlyList<double> values, int index, double fallback)
|
||||
{
|
||||
return values != null && index >= 0 && index < values.Count ? values[index] : fallback;
|
||||
}
|
||||
|
||||
private static int Read(System.Collections.Generic.IReadOnlyList<int> values, int index, int fallback)
|
||||
{
|
||||
return values != null && index >= 0 && index < values.Count ? values[index] : fallback;
|
||||
}
|
||||
|
||||
private struct AetheriaRenderSplat
|
||||
{
|
||||
public float4 CenterHalfExtent;
|
||||
public float4 RotationChannelFalloff;
|
||||
public float4 LayerSource;
|
||||
public float4 SourceFrequencyPhase;
|
||||
public float4 Value;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32e6f17486f34e8c8c5f7640bff319af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,300 +1,6 @@
|
|||
using GameCult.Aetheria.State.Verse;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
using GameCult.Eve.UnityScene.Fields;
|
||||
|
||||
public sealed class AetheriaRenderSplatRasterizer : MonoBehaviour
|
||||
// Existing scenes retain this MonoScript GUID while EveUnity owns projection.
|
||||
public sealed class AetheriaRenderSplatRasterizer : EveFieldsSplatRasterizer
|
||||
{
|
||||
[SerializeField]
|
||||
private Material splatMaterial;
|
||||
|
||||
[SerializeField]
|
||||
private RenderTexture targetTexture;
|
||||
|
||||
[SerializeField]
|
||||
private GraphicsFormat targetFormat = GraphicsFormat.R16_SFloat;
|
||||
|
||||
[SerializeField]
|
||||
private int width = 512;
|
||||
|
||||
[SerializeField]
|
||||
private int height = 512;
|
||||
|
||||
[SerializeField]
|
||||
private int channelFilter = -1;
|
||||
|
||||
[SerializeField]
|
||||
private int layerFilter = -1;
|
||||
|
||||
[SerializeField]
|
||||
private int materialPass;
|
||||
|
||||
[SerializeField]
|
||||
private Color clearColor = Color.clear;
|
||||
|
||||
[SerializeField]
|
||||
private bool clearBeforeDraw = true;
|
||||
|
||||
private readonly AetheriaRenderSplatBuffer _buffer = new AetheriaRenderSplatBuffer();
|
||||
private CommandBuffer _commandBuffer;
|
||||
private RenderTexture _ownedTargetTexture;
|
||||
private Material _ownedSplatMaterial;
|
||||
private static readonly int SplatBufferPropertyId =
|
||||
Shader.PropertyToID(AetheriaRenderSplatBuffer.SplatBufferPropertyName);
|
||||
private static readonly int SplatCountPropertyId =
|
||||
Shader.PropertyToID(AetheriaRenderSplatBuffer.SplatCountPropertyName);
|
||||
private static readonly int ViewportToClipPropertyId =
|
||||
Shader.PropertyToID(AetheriaRenderSplatBuffer.ViewportToClipPropertyName);
|
||||
private static readonly int ChannelFilterPropertyId =
|
||||
Shader.PropertyToID(AetheriaRenderSplatBuffer.ChannelFilterPropertyName);
|
||||
|
||||
public RenderTexture TargetTexture => targetTexture != null ? targetTexture : _ownedTargetTexture;
|
||||
public int ChannelFilter
|
||||
{
|
||||
get => channelFilter;
|
||||
set => channelFilter = value;
|
||||
}
|
||||
|
||||
public int LayerFilter
|
||||
{
|
||||
get => layerFilter;
|
||||
set => layerFilter = value;
|
||||
}
|
||||
|
||||
public int LastDrawnCount { get; private set; }
|
||||
|
||||
public RenderTexture Render(
|
||||
AetheriaRuntimeRenderSplatsViewportDocument document,
|
||||
int overrideWidth = 0,
|
||||
int overrideHeight = 0)
|
||||
{
|
||||
if (document == null)
|
||||
{
|
||||
LastDrawnCount = 0;
|
||||
return TargetTexture;
|
||||
}
|
||||
|
||||
var output = EnsureTarget(overrideWidth, overrideHeight);
|
||||
var material = ResolveMaterial();
|
||||
if (output == null || material == null)
|
||||
{
|
||||
LastDrawnCount = 0;
|
||||
return output;
|
||||
}
|
||||
|
||||
_buffer.Upload(document.Splats, channelFilter, layerFilter);
|
||||
LastDrawnCount = _buffer.Count;
|
||||
if (!_buffer.HasGpuBuffer)
|
||||
{
|
||||
if (clearBeforeDraw)
|
||||
Clear(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
_commandBuffer ??= new CommandBuffer { name = "Aetheria Render Splats" };
|
||||
_commandBuffer.Clear();
|
||||
_commandBuffer.SetRenderTarget(output);
|
||||
if (clearBeforeDraw)
|
||||
_commandBuffer.ClearRenderTarget(false, true, clearColor);
|
||||
|
||||
_commandBuffer.SetGlobalBuffer(SplatBufferPropertyId, _buffer.Buffer);
|
||||
_commandBuffer.SetGlobalInt(SplatCountPropertyId, _buffer.Count);
|
||||
_commandBuffer.SetGlobalInt(ChannelFilterPropertyId, channelFilter);
|
||||
_commandBuffer.SetGlobalMatrix(ViewportToClipPropertyId, BuildViewportToClip(document.Viewport));
|
||||
_commandBuffer.DrawProcedural(
|
||||
Matrix4x4.identity,
|
||||
material,
|
||||
math.max(0, materialPass),
|
||||
MeshTopology.Triangles,
|
||||
6,
|
||||
_buffer.Count);
|
||||
Graphics.ExecuteCommandBuffer(_commandBuffer);
|
||||
return output;
|
||||
}
|
||||
|
||||
public RenderTexture Render(
|
||||
AetheriaRuntimeRenderSplatsViewportDocument document,
|
||||
int overrideWidth,
|
||||
int overrideHeight,
|
||||
int overrideChannelFilter)
|
||||
{
|
||||
var previousChannelFilter = channelFilter;
|
||||
channelFilter = overrideChannelFilter;
|
||||
try
|
||||
{
|
||||
return Render(document, overrideWidth, overrideHeight);
|
||||
}
|
||||
finally
|
||||
{
|
||||
channelFilter = previousChannelFilter;
|
||||
}
|
||||
}
|
||||
|
||||
public RenderTexture RenderLayer(
|
||||
AetheriaRuntimeRenderSplatsViewportDocument document,
|
||||
int overrideWidth,
|
||||
int overrideHeight,
|
||||
int overrideLayerFilter,
|
||||
int overrideMaterialPass,
|
||||
GraphicsFormat overrideTargetFormat,
|
||||
Color overrideClearColor)
|
||||
{
|
||||
var previousLayerFilter = layerFilter;
|
||||
var previousMaterialPass = materialPass;
|
||||
var previousTargetFormat = targetFormat;
|
||||
var previousClearColor = clearColor;
|
||||
layerFilter = overrideLayerFilter;
|
||||
materialPass = overrideMaterialPass;
|
||||
targetFormat = overrideTargetFormat;
|
||||
clearColor = overrideClearColor;
|
||||
try
|
||||
{
|
||||
return Render(document, overrideWidth, overrideHeight);
|
||||
}
|
||||
finally
|
||||
{
|
||||
layerFilter = previousLayerFilter;
|
||||
materialPass = previousMaterialPass;
|
||||
targetFormat = previousTargetFormat;
|
||||
clearColor = previousClearColor;
|
||||
}
|
||||
}
|
||||
|
||||
public RenderTexture RenderLayerToTarget(
|
||||
AetheriaRuntimeRenderSplatsViewportDocument document,
|
||||
RenderTexture output,
|
||||
int overrideLayerFilter,
|
||||
int overrideMaterialPass,
|
||||
Color overrideClearColor)
|
||||
{
|
||||
var previousTargetTexture = targetTexture;
|
||||
var previousLayerFilter = layerFilter;
|
||||
var previousMaterialPass = materialPass;
|
||||
var previousClearColor = clearColor;
|
||||
targetTexture = output;
|
||||
layerFilter = overrideLayerFilter;
|
||||
materialPass = overrideMaterialPass;
|
||||
clearColor = overrideClearColor;
|
||||
try
|
||||
{
|
||||
return Render(document, output != null ? output.width : 0, output != null ? output.height : 0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
targetTexture = previousTargetTexture;
|
||||
layerFilter = previousLayerFilter;
|
||||
materialPass = previousMaterialPass;
|
||||
clearColor = previousClearColor;
|
||||
}
|
||||
}
|
||||
|
||||
private Material ResolveMaterial()
|
||||
{
|
||||
if (splatMaterial != null)
|
||||
return splatMaterial;
|
||||
|
||||
if (_ownedSplatMaterial != null)
|
||||
return _ownedSplatMaterial;
|
||||
|
||||
var shader = Shader.Find("Aetheria/Render Splats");
|
||||
if (shader == null)
|
||||
return null;
|
||||
|
||||
_ownedSplatMaterial = new Material(shader)
|
||||
{
|
||||
hideFlags = HideFlags.DontSave
|
||||
};
|
||||
return _ownedSplatMaterial;
|
||||
}
|
||||
|
||||
private RenderTexture EnsureTarget(int overrideWidth, int overrideHeight)
|
||||
{
|
||||
if (targetTexture != null)
|
||||
return targetTexture;
|
||||
|
||||
var targetWidth = math.max(1, overrideWidth > 0 ? overrideWidth : width);
|
||||
var targetHeight = math.max(1, overrideHeight > 0 ? overrideHeight : height);
|
||||
if (_ownedTargetTexture != null &&
|
||||
_ownedTargetTexture.width == targetWidth &&
|
||||
_ownedTargetTexture.height == targetHeight &&
|
||||
_ownedTargetTexture.graphicsFormat == targetFormat)
|
||||
{
|
||||
return _ownedTargetTexture;
|
||||
}
|
||||
|
||||
ReleaseOwnedTarget();
|
||||
var descriptor = new RenderTextureDescriptor(targetWidth, targetHeight)
|
||||
{
|
||||
depthBufferBits = 0,
|
||||
graphicsFormat = targetFormat,
|
||||
msaaSamples = 1,
|
||||
sRGB = false,
|
||||
useMipMap = false,
|
||||
autoGenerateMips = false
|
||||
};
|
||||
_ownedTargetTexture = new RenderTexture(descriptor)
|
||||
{
|
||||
name = "Aetheria Render Splats",
|
||||
filterMode = FilterMode.Bilinear,
|
||||
wrapMode = TextureWrapMode.Clamp
|
||||
};
|
||||
_ownedTargetTexture.Create();
|
||||
return _ownedTargetTexture;
|
||||
}
|
||||
|
||||
private void Clear(RenderTexture output)
|
||||
{
|
||||
_commandBuffer ??= new CommandBuffer { name = "Aetheria Render Splats" };
|
||||
_commandBuffer.Clear();
|
||||
_commandBuffer.SetRenderTarget(output);
|
||||
_commandBuffer.ClearRenderTarget(false, true, clearColor);
|
||||
Graphics.ExecuteCommandBuffer(_commandBuffer);
|
||||
}
|
||||
|
||||
private static Matrix4x4 BuildViewportToClip(AetheriaRuntimeViewportBounds viewport)
|
||||
{
|
||||
viewport ??= new AetheriaRuntimeViewportBounds();
|
||||
var minX = (float)math.min(viewport.MinX, viewport.MaxX);
|
||||
var minY = (float)math.min(viewport.MinY, viewport.MaxY);
|
||||
var maxX = (float)math.max(viewport.MinX, viewport.MaxX);
|
||||
var maxY = (float)math.max(viewport.MinY, viewport.MaxY);
|
||||
var width = math.max(0.0001f, maxX - minX);
|
||||
var height = math.max(0.0001f, maxY - minY);
|
||||
|
||||
return new Matrix4x4(
|
||||
new Vector4(2f / width, 0, 0, 0),
|
||||
new Vector4(0, 2f / height, 0, 0),
|
||||
new Vector4(0, 0, 1, 0),
|
||||
new Vector4(-(maxX + minX) / width, -(maxY + minY) / height, 0, 1));
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_buffer.Dispose();
|
||||
_commandBuffer?.Release();
|
||||
_commandBuffer = null;
|
||||
DestroyOwnedMaterial();
|
||||
ReleaseOwnedTarget();
|
||||
LastDrawnCount = 0;
|
||||
}
|
||||
|
||||
private void DestroyOwnedMaterial()
|
||||
{
|
||||
if (_ownedSplatMaterial == null)
|
||||
return;
|
||||
|
||||
Destroy(_ownedSplatMaterial);
|
||||
_ownedSplatMaterial = null;
|
||||
}
|
||||
|
||||
private void ReleaseOwnedTarget()
|
||||
{
|
||||
if (_ownedTargetTexture == null)
|
||||
return;
|
||||
|
||||
_ownedTargetTexture.Release();
|
||||
Destroy(_ownedTargetTexture);
|
||||
_ownedTargetTexture = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
Shader "Aetheria/Render Splats"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_ValueScale("Value Scale", Float) = 1
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "Add"
|
||||
Cull Off
|
||||
ZWrite Off
|
||||
ZTest Always
|
||||
BlendOp Add
|
||||
Blend One One
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 4.5
|
||||
#pragma vertex Vert
|
||||
#pragma fragment Frag
|
||||
#include "UnityCG.cginc"
|
||||
#define AETHERIA_SPLAT_PASS
|
||||
#include "AetheriaRenderSplatsCore.hlsl"
|
||||
ENDHLSL
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "Max"
|
||||
Cull Off
|
||||
ZWrite Off
|
||||
ZTest Always
|
||||
BlendOp Max
|
||||
Blend One One
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 4.5
|
||||
#pragma vertex Vert
|
||||
#pragma fragment Frag
|
||||
#include "UnityCG.cginc"
|
||||
#define AETHERIA_SPLAT_PASS
|
||||
#include "AetheriaRenderSplatsCore.hlsl"
|
||||
ENDHLSL
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "Alpha"
|
||||
Cull Off
|
||||
ZWrite Off
|
||||
ZTest Always
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 4.5
|
||||
#pragma vertex Vert
|
||||
#pragma fragment Frag
|
||||
#include "UnityCG.cginc"
|
||||
#define AETHERIA_SPLAT_PASS
|
||||
#include "AetheriaRenderSplatsCore.hlsl"
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a1aa8658e37f433cb08a29ab01f4e8e5
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
preprocessorOverride: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
#ifndef AETHERIA_RENDER_SPLATS_CORE_INCLUDED
|
||||
#define AETHERIA_RENDER_SPLATS_CORE_INCLUDED
|
||||
|
||||
struct AetheriaSplat
|
||||
{
|
||||
float4 centerHalfExtent;
|
||||
float4 rotationChannelFalloff;
|
||||
float4 layerSource;
|
||||
float4 sourceFrequencyPhase;
|
||||
float4 value;
|
||||
};
|
||||
|
||||
StructuredBuffer<AetheriaSplat> _AetheriaSplats;
|
||||
float4x4 _AetheriaViewportToClip;
|
||||
int _AetheriaSplatCount;
|
||||
int _AetheriaChannelFilter;
|
||||
float _ValueScale;
|
||||
|
||||
float hash21(float2 p)
|
||||
{
|
||||
p = frac(p * float2(123.34, 456.21));
|
||||
p += dot(p, p + 45.32);
|
||||
return frac(p.x * p.y);
|
||||
}
|
||||
|
||||
float valueNoise(float2 p)
|
||||
{
|
||||
float2 i = floor(p);
|
||||
float2 f = frac(p);
|
||||
float a = hash21(i);
|
||||
float b = hash21(i + float2(1, 0));
|
||||
float c = hash21(i + float2(0, 1));
|
||||
float d = hash21(i + float2(1, 1));
|
||||
float2 u = f * f * (3 - 2 * f);
|
||||
return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y) * 2 - 1;
|
||||
}
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 position : SV_POSITION;
|
||||
float2 localUv : TEXCOORD0;
|
||||
nointerpolation uint instanceId : TEXCOORD1;
|
||||
};
|
||||
|
||||
Varyings Vert(uint vertexId : SV_VertexID, uint instanceId : SV_InstanceID)
|
||||
{
|
||||
static const float2 corners[6] =
|
||||
{
|
||||
float2(-1, -1),
|
||||
float2(1, -1),
|
||||
float2(1, 1),
|
||||
float2(-1, -1),
|
||||
float2(1, 1),
|
||||
float2(-1, 1)
|
||||
};
|
||||
|
||||
AetheriaSplat splat = _AetheriaSplats[instanceId];
|
||||
float2 local = corners[vertexId];
|
||||
float2 scaled = local * splat.centerHalfExtent.zw;
|
||||
float c = splat.rotationChannelFalloff.x;
|
||||
float s = splat.rotationChannelFalloff.y;
|
||||
float2 world = splat.centerHalfExtent.xy + float2(
|
||||
scaled.x * c - scaled.y * s,
|
||||
scaled.x * s + scaled.y * c);
|
||||
|
||||
Varyings output;
|
||||
output.position = mul(_AetheriaViewportToClip, float4(world, 0, 1));
|
||||
output.localUv = local;
|
||||
output.instanceId = instanceId;
|
||||
return output;
|
||||
}
|
||||
|
||||
float ResolveFalloff(float2 localUv, int falloff)
|
||||
{
|
||||
float distance01 = saturate(length(localUv));
|
||||
if (falloff == 0)
|
||||
return 1;
|
||||
if (falloff == 1)
|
||||
return saturate(1 - distance01);
|
||||
if (falloff == 3)
|
||||
{
|
||||
float t = smoothstep(0, 1, distance01);
|
||||
return t;
|
||||
}
|
||||
|
||||
return 1 - smoothstep(0, 1, distance01);
|
||||
}
|
||||
|
||||
float4 Frag(Varyings input) : SV_Target
|
||||
{
|
||||
AetheriaSplat splat = _AetheriaSplats[input.instanceId];
|
||||
int channel = (int)round(splat.rotationChannelFalloff.z);
|
||||
if (_AetheriaChannelFilter >= 0 && channel != _AetheriaChannelFilter)
|
||||
discard;
|
||||
|
||||
int falloff = (int)round(splat.rotationChannelFalloff.w);
|
||||
float alpha = ResolveFalloff(input.localUv, falloff);
|
||||
clip(alpha - 0.0001);
|
||||
|
||||
int sourceKind = (int)round(splat.layerSource.y);
|
||||
float source = 1;
|
||||
if (sourceKind == 1 || sourceKind == 2)
|
||||
{
|
||||
float2 frequency = splat.sourceFrequencyPhase.xy;
|
||||
float2 phase = splat.sourceFrequencyPhase.zw;
|
||||
float timeOffset = sourceKind == 2 ? _Time.y * splat.layerSource.z : 0;
|
||||
source = valueNoise(input.localUv * frequency + phase + timeOffset);
|
||||
if (splat.layerSource.w != 0)
|
||||
source = abs(source);
|
||||
}
|
||||
|
||||
return splat.value * (alpha * source * _ValueScale);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 91df759011f84ed8b003bb7828809e0b
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
preprocessorOverride: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -23,7 +23,8 @@
|
|||
"org.gamecult.cultmath": "file:../../CultMath",
|
||||
"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-source-v1.0.3-r2",
|
||||
"org.gamecult.eve.surface": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.1.0",
|
||||
"org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.1.1",
|
||||
"org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.1.1",
|
||||
"org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.1.2",
|
||||
"org.gamecult.eve.unity-uitoolkit": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.0",
|
||||
"com.unity.modules.accessibility": "1.0.0",
|
||||
"com.unity.modules.adaptiveperformance": "1.0.0",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameCult.Caching;
|
||||
using GameCult.Eve.PluginFields;
|
||||
using MessagePack;
|
||||
|
||||
#nullable enable
|
||||
|
|
@ -1305,7 +1306,7 @@ namespace GameCult.Aetheria.State.Verse
|
|||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed class AetheriaRuntimeViewportBounds
|
||||
public sealed class AetheriaRuntimeViewportBounds : IEveFieldsViewport
|
||||
{
|
||||
[Key(0)]
|
||||
public double MinX { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GameCult.Caching;
|
||||
using GameCult.Eve.PluginFields;
|
||||
using MessagePack;
|
||||
|
||||
#nullable enable
|
||||
|
|
@ -52,7 +53,7 @@ namespace GameCult.Aetheria.State.Verse
|
|||
|
||||
[CultDocument("gamecult.fields.splats", "gamecult.fields.splats.v1")]
|
||||
[MessagePackObject]
|
||||
public sealed class AetheriaRuntimeRenderSplatsViewportDocument
|
||||
public sealed class AetheriaRuntimeRenderSplatsViewportDocument : IEveFieldsSplatsDocument
|
||||
{
|
||||
[Key(0)]
|
||||
public string Schema { get; set; } = AetheriaRuntimeDaemonSchemas.RenderSplatsViewport;
|
||||
|
|
@ -84,10 +85,14 @@ namespace GameCult.Aetheria.State.Verse
|
|||
|
||||
[Key(9)]
|
||||
public AetheriaRuntimeRenderSplatSoa Splats { get; set; } = new AetheriaRuntimeRenderSplatSoa();
|
||||
|
||||
IEveFieldsViewport IEveFieldsSplatsDocument.Viewport => Viewport;
|
||||
IReadOnlyList<IEveFieldsSplatLayer> IEveFieldsSplatsDocument.Layers => Layers;
|
||||
IEveFieldsSplatSoa IEveFieldsSplatsDocument.Splats => Splats;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed class AetheriaRuntimeRenderSplatLayerDefinition
|
||||
public sealed class AetheriaRuntimeRenderSplatLayerDefinition : IEveFieldsSplatLayer
|
||||
{
|
||||
[Key(0)]
|
||||
public string LayerKey { get; set; } = "";
|
||||
|
|
@ -121,7 +126,7 @@ namespace GameCult.Aetheria.State.Verse
|
|||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed class AetheriaRuntimeRenderSplatSoa
|
||||
public sealed class AetheriaRuntimeRenderSplatSoa : IEveFieldsSplatSoa
|
||||
{
|
||||
[Key(0)]
|
||||
public int Count { get; set; }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
"rootNamespace": "GameCult.Aetheria.State.Unity",
|
||||
"references": [
|
||||
"GameCult.Eve.Surface",
|
||||
"GameCult.Eve.PluginFields",
|
||||
"GameCult.Mesh",
|
||||
"CultMath",
|
||||
"MessagePack"
|
||||
|
|
|
|||
|
|
@ -323,6 +323,13 @@
|
|||
"source": "local",
|
||||
"dependencies": {}
|
||||
},
|
||||
"org.gamecult.eve.plugin-fields": {
|
||||
"version": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.1.1",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {},
|
||||
"hash": "0b099274a4e2b4c301eced4322166837792f585a"
|
||||
},
|
||||
"org.gamecult.eve.surface": {
|
||||
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.1.0",
|
||||
"depth": 0,
|
||||
|
|
@ -333,14 +340,15 @@
|
|||
"hash": "e10821f1cc81f619479c6507438f6a097d1f0ce2"
|
||||
},
|
||||
"org.gamecult.eve.unity-scene": {
|
||||
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.1.1",
|
||||
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.1.2",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {
|
||||
"org.gamecult.cultlib": "1.0.3",
|
||||
"org.gamecult.eve.plugin-fields": "0.1.1",
|
||||
"org.gamecult.eve.surface": "0.1.0"
|
||||
},
|
||||
"hash": "7e65154d7f42cf1c4ac55871c35676e7ccd2e5b2"
|
||||
"hash": "3e23fff486f2d29451cad59eafc7a6a2d4ac460b"
|
||||
},
|
||||
"org.gamecult.eve.unity-uitoolkit": {
|
||||
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue