Add Unity fields projection adapter
This commit is contained in:
parent
17d1e3e781
commit
3e23fff486
19 changed files with 450 additions and 4 deletions
|
|
@ -6,8 +6,9 @@
|
|||
"com.unity.modules.physics": "1.0.0",
|
||||
"com.unity.modules.uielements": "1.0.0",
|
||||
"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-source-v1.0.3-r2",
|
||||
"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.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.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"
|
||||
},
|
||||
"testables": [
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
"com.unity.modules.physics": "1.0.0",
|
||||
"com.unity.modules.uielements": "1.0.0",
|
||||
"org.gamecult.cultlib": "file:../../../CultLib/artifacts/unity/org.gamecult.cultlib",
|
||||
"org.gamecult.eve.plugin-fields": "file:../../../EvePlugins/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields",
|
||||
"org.gamecult.eve.surface": "file:../../packages/org.gamecult.eve.surface",
|
||||
"org.gamecult.eve.unity-scene": "file:../../packages/org.gamecult.eve.unity-scene",
|
||||
"org.gamecult.eve.unity-uitoolkit": "file:../../packages/org.gamecult.eve.unity-uitoolkit"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@
|
|||
"source": "local",
|
||||
"dependencies": {}
|
||||
},
|
||||
"org.gamecult.eve.plugin-fields": {
|
||||
"version": "file:../../../EvePlugins/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields",
|
||||
"depth": 0,
|
||||
"source": "local",
|
||||
"dependencies": {}
|
||||
},
|
||||
"org.gamecult.eve.surface": {
|
||||
"version": "file:../../packages/org.gamecult.eve.surface",
|
||||
"depth": 0,
|
||||
|
|
@ -36,6 +42,7 @@
|
|||
"source": "local",
|
||||
"dependencies": {
|
||||
"org.gamecult.cultlib": "1.0.3",
|
||||
"org.gamecult.eve.plugin-fields": "0.1.1",
|
||||
"org.gamecult.eve.surface": "0.1.0"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,3 +14,8 @@ provides every bootstrap port. Provider, surface, and Verse IDs are optional
|
|||
selection filters; they are not product knowledge required by the client.
|
||||
|
||||
The package never imports provider product assemblies.
|
||||
|
||||
`fields.surface` projection consumes the plugin-owned
|
||||
`org.gamecult.eve.plugin-fields` contracts. `EveFieldsSplatRasterizer` owns the
|
||||
Unity structured-buffer and RenderTexture lowering without importing provider
|
||||
document classes.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c2c7df6e8d34f3ba491b20a450d17cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GameCult.Eve.PluginFields;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameCult.Eve.UnityScene.Fields
|
||||
{
|
||||
public sealed class EveFieldsSplatBuffer : IDisposable
|
||||
{
|
||||
public const string SplatBufferPropertyName = "_EveFieldsSplats";
|
||||
public const string SplatCountPropertyName = "_EveFieldsSplatCount";
|
||||
public const string ViewportToClipPropertyName = "_EveFieldsViewportToClip";
|
||||
public const string ChannelFilterPropertyName = "_EveFieldsChannelFilter";
|
||||
|
||||
private const int SplatStrideBytes = 80;
|
||||
private EveFieldsGpuSplat[] splats = Array.Empty<EveFieldsGpuSplat>();
|
||||
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(IEveFieldsSplatSoa source, int channelFilter = -1, int layerFilter = -1)
|
||||
{
|
||||
Count = Pack(source, channelFilter, layerFilter);
|
||||
EnsureGpuCapacity(Count);
|
||||
if (Count <= 0)
|
||||
return false;
|
||||
buffer.SetData(splats, 0, 0, Count);
|
||||
return true;
|
||||
}
|
||||
|
||||
private int Pack(IEveFieldsSplatSoa source, int channelFilter, int layerFilter)
|
||||
{
|
||||
if (source == null || source.Count <= 0)
|
||||
return 0;
|
||||
EnsureCpuCapacity(source.Count);
|
||||
var count = 0;
|
||||
for (var index = 0; index < source.Count; index++)
|
||||
{
|
||||
var channel = Read(source.Channel, index, 0);
|
||||
var layer = Read(source.LayerIndex, index, -1);
|
||||
if ((channelFilter >= 0 && channel != channelFilter) ||
|
||||
(layerFilter >= 0 && layer != layerFilter))
|
||||
continue;
|
||||
var halfExtentX = (float)Read(source.HalfExtentX, index, 0);
|
||||
var halfExtentY = (float)Read(source.HalfExtentY, index, 0);
|
||||
if (halfExtentX <= 0 || halfExtentY <= 0)
|
||||
continue;
|
||||
splats[count++] = new EveFieldsGpuSplat
|
||||
{
|
||||
CenterHalfExtent = new Vector4((float)Read(source.CenterX, index, 0), (float)Read(source.CenterY, index, 0), halfExtentX, halfExtentY),
|
||||
RotationChannelFalloff = new Vector4((float)Read(source.RotationCos, index, 1), (float)Read(source.RotationSin, index, 0), channel, Read(source.Falloff, index, EveFieldsSplatFalloffs.Smooth)),
|
||||
LayerSource = new Vector4(layer, Read(source.SourceKind, index, EveFieldsSplatSourceKinds.Constant), (float)Read(source.AnimationSpeed, index, 0), (float)Read(source.SourceFlags, index, 0)),
|
||||
SourceFrequencyPhase = new Vector4((float)Read(source.FrequencyX, index, 1), (float)Read(source.FrequencyY, index, 1), (float)Read(source.PhaseX, index, 0), (float)Read(source.PhaseY, index, 0)),
|
||||
Value = new Vector4((float)Read(source.ValueR, index, 0), (float)Read(source.ValueG, index, 0), (float)Read(source.ValueB, index, 0), (float)Read(source.ValueA, index, 1))
|
||||
};
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void EnsureCpuCapacity(int count)
|
||||
{
|
||||
if (splats.Length >= count) return;
|
||||
var next = 1;
|
||||
while (next < count) next <<= 1;
|
||||
splats = new EveFieldsGpuSplat[next];
|
||||
}
|
||||
|
||||
private void EnsureGpuCapacity(int count)
|
||||
{
|
||||
if (buffer != null && buffer.IsValid() && capacity >= count) return;
|
||||
buffer?.Release();
|
||||
buffer = null;
|
||||
capacity = 0;
|
||||
if (count <= 0) return;
|
||||
capacity = 1;
|
||||
while (capacity < count) capacity <<= 1;
|
||||
buffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capacity, SplatStrideBytes);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
buffer?.Release();
|
||||
buffer = null;
|
||||
capacity = 0;
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
private static double Read(IReadOnlyList<double> values, int index, double fallback) =>
|
||||
values != null && index >= 0 && index < values.Count ? values[index] : fallback;
|
||||
private static int Read(IReadOnlyList<int> values, int index, int fallback) =>
|
||||
values != null && index >= 0 && index < values.Count ? values[index] : fallback;
|
||||
|
||||
private struct EveFieldsGpuSplat
|
||||
{
|
||||
public Vector4 CenterHalfExtent;
|
||||
public Vector4 RotationChannelFalloff;
|
||||
public Vector4 LayerSource;
|
||||
public Vector4 SourceFrequencyPhase;
|
||||
public Vector4 Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0638cfafda354c8785255c44861df08d
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
using GameCult.Eve.PluginFields;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace GameCult.Eve.UnityScene.Fields
|
||||
{
|
||||
public class EveFieldsSplatRasterizer : MonoBehaviour
|
||||
{
|
||||
[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 EveFieldsSplatBuffer splatBuffer = new EveFieldsSplatBuffer();
|
||||
private CommandBuffer commandBuffer;
|
||||
private RenderTexture ownedTargetTexture;
|
||||
private Material ownedSplatMaterial;
|
||||
private static readonly int SplatBufferId = Shader.PropertyToID(EveFieldsSplatBuffer.SplatBufferPropertyName);
|
||||
private static readonly int SplatCountId = Shader.PropertyToID(EveFieldsSplatBuffer.SplatCountPropertyName);
|
||||
private static readonly int ViewportToClipId = Shader.PropertyToID(EveFieldsSplatBuffer.ViewportToClipPropertyName);
|
||||
private static readonly int ChannelFilterId = Shader.PropertyToID(EveFieldsSplatBuffer.ChannelFilterPropertyName);
|
||||
|
||||
public RenderTexture TargetTexture => targetTexture != null ? targetTexture : ownedTargetTexture;
|
||||
public int LastDrawnCount { get; private set; }
|
||||
public int ChannelFilter { get => channelFilter; set => channelFilter = value; }
|
||||
public int LayerFilter { get => layerFilter; set => layerFilter = value; }
|
||||
|
||||
public RenderTexture Render(IEveFieldsSplatsDocument 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; }
|
||||
splatBuffer.Upload(document.Splats, channelFilter, layerFilter);
|
||||
LastDrawnCount = splatBuffer.Count;
|
||||
if (!splatBuffer.HasGpuBuffer) { if (clearBeforeDraw) Clear(output); return output; }
|
||||
commandBuffer ??= new CommandBuffer { name = "Eve Fields Splats" };
|
||||
commandBuffer.Clear();
|
||||
commandBuffer.SetRenderTarget(output);
|
||||
if (clearBeforeDraw) commandBuffer.ClearRenderTarget(false, true, clearColor);
|
||||
commandBuffer.SetGlobalBuffer(SplatBufferId, splatBuffer.Buffer);
|
||||
commandBuffer.SetGlobalInt(SplatCountId, splatBuffer.Count);
|
||||
commandBuffer.SetGlobalInt(ChannelFilterId, channelFilter);
|
||||
commandBuffer.SetGlobalMatrix(ViewportToClipId, BuildViewportToClip(document.Viewport));
|
||||
commandBuffer.DrawProcedural(Matrix4x4.identity, material, Mathf.Max(0, materialPass), MeshTopology.Triangles, 6, splatBuffer.Count);
|
||||
Graphics.ExecuteCommandBuffer(commandBuffer);
|
||||
return output;
|
||||
}
|
||||
|
||||
public RenderTexture RenderLayerToTarget(IEveFieldsSplatsDocument document, RenderTexture output, int overrideLayerFilter, int overrideMaterialPass, Color overrideClearColor)
|
||||
{
|
||||
var oldTarget = targetTexture; var oldLayer = layerFilter; var oldPass = materialPass; var oldClear = 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 = oldTarget; layerFilter = oldLayer; materialPass = oldPass; clearColor = oldClear; }
|
||||
}
|
||||
|
||||
private Material ResolveMaterial()
|
||||
{
|
||||
if (splatMaterial != null) return splatMaterial;
|
||||
if (ownedSplatMaterial != null) return ownedSplatMaterial;
|
||||
var shader = Shader.Find("Eve/Fields/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 = Mathf.Max(1, overrideWidth > 0 ? overrideWidth : width);
|
||||
var targetHeight = Mathf.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 = "Eve Fields Splats", filterMode = FilterMode.Bilinear, wrapMode = TextureWrapMode.Clamp };
|
||||
ownedTargetTexture.Create();
|
||||
return ownedTargetTexture;
|
||||
}
|
||||
|
||||
private void Clear(RenderTexture output)
|
||||
{
|
||||
commandBuffer ??= new CommandBuffer { name = "Eve Fields Splats" };
|
||||
commandBuffer.Clear(); commandBuffer.SetRenderTarget(output); commandBuffer.ClearRenderTarget(false, true, clearColor); Graphics.ExecuteCommandBuffer(commandBuffer);
|
||||
}
|
||||
|
||||
private static Matrix4x4 BuildViewportToClip(IEveFieldsViewport viewport)
|
||||
{
|
||||
var minX = (float)System.Math.Min(viewport?.MinX ?? 0, viewport?.MaxX ?? 0);
|
||||
var minY = (float)System.Math.Min(viewport?.MinY ?? 0, viewport?.MaxY ?? 0);
|
||||
var maxX = (float)System.Math.Max(viewport?.MinX ?? 0, viewport?.MaxX ?? 0);
|
||||
var maxY = (float)System.Math.Max(viewport?.MinY ?? 0, viewport?.MaxY ?? 0);
|
||||
var spanX = Mathf.Max(0.0001f, maxX - minX); var spanY = Mathf.Max(0.0001f, maxY - minY);
|
||||
return new Matrix4x4(new Vector4(2f / spanX, 0, 0, 0), new Vector4(0, 2f / spanY, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(-(maxX + minX) / spanX, -(maxY + minY) / spanY, 0, 1));
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
splatBuffer.Dispose(); commandBuffer?.Release(); commandBuffer = null;
|
||||
if (ownedSplatMaterial != null) { Destroy(ownedSplatMaterial); ownedSplatMaterial = null; }
|
||||
ReleaseOwnedTarget(); LastDrawnCount = 0;
|
||||
}
|
||||
|
||||
private void ReleaseOwnedTarget()
|
||||
{
|
||||
if (ownedTargetTexture == null) return;
|
||||
ownedTargetTexture.Release(); Destroy(ownedTargetTexture); ownedTargetTexture = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3c38a5ac2cea4201943817fbdf766974
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
Shader "Eve/Fields/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"
|
||||
#include "EveFieldsSplatsCore.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"
|
||||
#include "EveFieldsSplatsCore.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"
|
||||
#include "EveFieldsSplatsCore.hlsl"
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 830df1cf91684771a9254a4b28613f6f
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
preprocessorOverride: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef EVE_FIELDS_SPLATS_CORE_INCLUDED
|
||||
#define EVE_FIELDS_SPLATS_CORE_INCLUDED
|
||||
|
||||
struct EveFieldsSplat
|
||||
{
|
||||
float4 centerHalfExtent;
|
||||
float4 rotationChannelFalloff;
|
||||
float4 layerSource;
|
||||
float4 sourceFrequencyPhase;
|
||||
float4 value;
|
||||
};
|
||||
|
||||
StructuredBuffer<EveFieldsSplat> _EveFieldsSplats;
|
||||
float4x4 _EveFieldsViewportToClip;
|
||||
int _EveFieldsSplatCount;
|
||||
int _EveFieldsChannelFilter;
|
||||
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) };
|
||||
EveFieldsSplat splat = _EveFieldsSplats[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(_EveFieldsViewportToClip, 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) return smoothstep(0, 1, distance01);
|
||||
return 1 - smoothstep(0, 1, distance01);
|
||||
}
|
||||
|
||||
float4 Frag(Varyings input) : SV_Target
|
||||
{
|
||||
EveFieldsSplat splat = _EveFieldsSplats[input.instanceId];
|
||||
int channel = (int)round(splat.rotationChannelFalloff.z);
|
||||
if (_EveFieldsChannelFilter >= 0 && channel != _EveFieldsChannelFilter) discard;
|
||||
float alpha = ResolveFalloff(input.localUv, (int)round(splat.rotationChannelFalloff.w));
|
||||
clip(alpha - 0.0001);
|
||||
int sourceKind = (int)round(splat.layerSource.y);
|
||||
float source = 1;
|
||||
if (sourceKind == 1 || sourceKind == 2)
|
||||
{
|
||||
float timeOffset = sourceKind == 2 ? _Time.y * splat.layerSource.z : 0;
|
||||
source = valueNoise(input.localUv * splat.sourceFrequencyPhase.xy + splat.sourceFrequencyPhase.zw + timeOffset);
|
||||
if (splat.layerSource.w != 0) source = abs(source);
|
||||
}
|
||||
return splat.value * (alpha * source * _ValueScale);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c57c2586f57942f39323935e46133e86
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -2,7 +2,8 @@
|
|||
"name": "GameCult.Eve.UnityScene",
|
||||
"rootNamespace": "GameCult.Eve.UnityScene",
|
||||
"references": [
|
||||
"GameCult.Eve.Surface"
|
||||
"GameCult.Eve.Surface",
|
||||
"GameCult.Eve.PluginFields"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using GameCult.Eve.PluginFields;
|
||||
using GameCult.Eve.UnityScene.Fields;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameCult.Eve.UnityScene.Tests
|
||||
{
|
||||
public sealed class EveFieldsUnitySceneProjectionTests
|
||||
{
|
||||
[Test]
|
||||
public void RasterizerConsumesPluginOwnedDocumentContract()
|
||||
{
|
||||
var render = typeof(EveFieldsSplatRasterizer).GetMethod(
|
||||
"Render",
|
||||
new[] { typeof(IEveFieldsSplatsDocument), typeof(int), typeof(int) });
|
||||
|
||||
Assert.That(render, Is.Not.Null);
|
||||
Assert.That(typeof(EveFieldsSplatRasterizer).Assembly.GetReferencedAssemblies().Any(assembly =>
|
||||
assembly.Name?.Contains("Aetheria", StringComparison.OrdinalIgnoreCase) == true), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PackageContainsGenericFieldsShader()
|
||||
{
|
||||
Assert.That(Shader.Find("Eve/Fields/Splats"), Is.Not.Null);
|
||||
Assert.That(File.Exists("Packages/org.gamecult.eve.unity-scene/Runtime/Fields/EveFieldsSplatsCore.hlsl"), Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d07cc4537e64f12adfa8930ded4fe96
|
||||
|
|
@ -3,7 +3,8 @@
|
|||
"rootNamespace": "GameCult.Eve.UnityScene.Tests",
|
||||
"references": [
|
||||
"GameCult.Eve.Surface",
|
||||
"GameCult.Eve.UnityScene"
|
||||
"GameCult.Eve.UnityScene",
|
||||
"GameCult.Eve.PluginFields"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,14 @@
|
|||
"embeddedDocuments"
|
||||
],
|
||||
"supportedPlugins": [
|
||||
{
|
||||
"pluginId": "fields.surface",
|
||||
"capabilities": [
|
||||
"field.surface2d",
|
||||
"gravity.surface"
|
||||
],
|
||||
"projectionAdapter": "EveFieldsSplatRasterizer"
|
||||
},
|
||||
{
|
||||
"pluginId": "sai.vn",
|
||||
"capabilities": [
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
{
|
||||
"name": "org.gamecult.eve.unity-scene",
|
||||
"displayName": "Eve Unity Scene Lowering",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"unity": "2021.3",
|
||||
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
|
||||
"dependencies": {
|
||||
"org.gamecult.cultlib": "1.0.3",
|
||||
"org.gamecult.eve.plugin-fields": "0.1.1",
|
||||
"org.gamecult.eve.surface": "0.1.0"
|
||||
},
|
||||
"keywords": [
|
||||
|
|
|
|||
Reference in a new issue