Graphics Settings + Disabling Minimap Asteroids

Created graphics settings data structure
Added nebula quality option to graphics settings
Added option to display asteroids in minimap (expensive)
This commit is contained in:
Reinier Vens 2022-07-18 08:44:54 +01:00
commit b93d2d213b
25 changed files with 1733 additions and 257 deletions

View file

@ -89,7 +89,7 @@ Material:
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _Scale: 4.6483793
- _Scale: 1.6860973
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1

View file

@ -2,14 +2,15 @@
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Sector Map UI
m_Shader: {fileID: 4800000, guid: 16ca943590e909145a2f5b7aaeef334e, type: 3}
m_ShaderKeywords:
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
@ -59,6 +60,7 @@ Material:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _ColorMask: 15

BIN
Assets/Resources/Settings.asset (Stored with Git LFS)

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -1355,7 +1355,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 8c03374f22d0a3d4882018de66894a84, type: 3}
m_Name:
m_EditorClassIdentifier:
GridTransform: {fileID: 1172538221}
GridCamera: {fileID: 2103364771}
Settings: {fileID: 11400000, guid: cd2344e2001a37544aab0960c164d4ff, type: 2}
NebulaSurfaceHeight: {fileID: 8400000, guid: 2fc21a9d3e9647948b56e384cd9378b3, type: 2}
NebulaPatchHeight: {fileID: 8400000, guid: 06ec5ef8a5830fc44b1ac1a6e123add5, type: 2}
@ -1374,7 +1374,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
downSample: 0
quality: 1
quality: 2
cloudShader: {fileID: 4800000, guid: 84e97169589c5e94e8521fe4deb2e3f8, type: 3}
--- !u!4 &971662241 stripped
Transform:
@ -2493,6 +2493,11 @@ PrefabInstance:
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4533226043457584178, guid: 3d8d9cbf10b12214e98891c1f03c1e99,
type: 3}
propertyPath: CloudRenderer
value:
objectReference: {fileID: 965376329}
- target: {fileID: 4533226043457584179, guid: 3d8d9cbf10b12214e98891c1f03c1e99,
type: 3}
propertyPath: m_Pivot.x

View file

@ -254,6 +254,11 @@ public class ActionGameManager : MonoBehaviour
ItemManager = new ItemManager(CultCache, Settings.GameplaySettings, Debug.Log);
ZoneRenderer.ItemManager = ItemManager;
// If hiding minimap asteroids, turn them off to start with
if (!PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap)
ZoneRenderer.ShowAsteroidUI = false;
// TODO: Process Stories
// _loadoutPath = GameDataDirectory.CreateSubdirectory("Loadouts");

View file

@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 54
executionOrder: 55
icon: {instanceID: 0}
userData:
assetBundleName:

View file

@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 53
executionOrder: 54
icon: {instanceID: 0}
userData:
assetBundleName:

View file

@ -12,6 +12,7 @@ public class PlayerSettings
[Key(3)] public Dictionary<string, string> HashedStoryFiles = new Dictionary<string, string>();
[Key(4)] public PlayerGameplaySettings GameplaySettings = new PlayerGameplaySettings();
[Key(5)] public PlayerInputSettings InputSettings = new PlayerInputSettings();
[Key(6)] public PlayerGraphicsSettings GraphicsSettings = new PlayerGraphicsSettings();
public string FormatTemperature(float t)
{
@ -56,9 +57,24 @@ public class PlayerGameplaySettings
[Key(1)] public int SignificantDigits = 3;
}
[MessagePackObject]
public class PlayerGraphicsSettings
{
[Key(0)] public Quality NebulaQuality = Quality.Normal;
[Key(1)] public bool ShowAsteroidsInMinimap;
}
[MessagePackObject]
public class PlayerInputSettings
{
[Key(0)] public Dictionary<(string action, int binding), string> InputActionMap = new Dictionary<(string action, int binding), string>();
[Key(1)] public List<string> ActionBarInputs = new List<string>();
}
public enum Quality
{
Low,
Normal,
High,
Ultra
}

View file

@ -15,6 +15,7 @@ using Random = UnityEngine.Random;
public class MainMenu : MonoBehaviour
{
public VolumeCloudRenderer CloudRenderer;
public GameSettings Settings;
public ConfirmationDialog Dialog;
public bool InGame;
@ -243,6 +244,17 @@ public class MainMenu : MonoBehaviour
{
_nextMenu.panel.Clear();
_nextMenu.panel.Title.text = TitleSubtitle("graphics", "settings");
_nextMenu.panel.AddField("Nebula Quality",
() => (int)ActionGameManager.PlayerSettings.GraphicsSettings.NebulaQuality,
i =>
{
ActionGameManager.PlayerSettings.GraphicsSettings.NebulaQuality = (Quality)i;
CloudRenderer.quality = ActionGameManager.PlayerSettings.GraphicsSettings.NebulaQuality;
},
Enum.GetNames(typeof(Quality)));
_nextMenu.panel.AddField("Show Asteroids in Minimap",
() => ActionGameManager.PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap,
b => ActionGameManager.PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap = b);
_nextMenu.panel.AddButton("Back",
() =>
{

View file

@ -15,6 +15,7 @@ using int2 = Unity.Mathematics.int2;
public class MapRenderer : MonoBehaviour
{
public ActionGameManager GameManager;
public ZoneRenderer ZoneRenderer;
public TextMeshProUGUI Title;
public Camera MapOverlayCamera;
public Camera GravityCamera;
@ -49,6 +50,10 @@ public class MapRenderer : MonoBehaviour
TintCamera.gameObject.SetActive(true);
InfluenceCamera.gameObject.SetActive(true);
Title.text = $"Zone: {GameManager.Zone.GalaxyZone.Name}";
// If hiding minimap asteroids, turn them back on for the map screen
if (!ActionGameManager.PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap)
ZoneRenderer.ShowAsteroidUI = true;
}
private void OnDisable()
@ -61,6 +66,10 @@ public class MapRenderer : MonoBehaviour
GravityCamera.gameObject.SetActive(false);
TintCamera.gameObject.SetActive(false);
InfluenceCamera.gameObject.SetActive(false);
// If hiding minimap asteroids, turn them back off when leaving the map screen
if (!ActionGameManager.PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap)
ZoneRenderer.ShowAsteroidUI = false;
}
void ReleaseTextures()

View file

@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
executionOrder: 51
icon: {instanceID: 0}
userData:
assetBundleName:

View file

@ -29,14 +29,6 @@ public class HaltonSequence
}
}
public enum Quality
{
Low,
Normal, //Low sample count
High, //High sample count and high shadow sample count.
Ultra
}
/// <summary>
/// Cloud renderer post processing.
/// </summary>
@ -85,6 +77,8 @@ public class VolumeCloudRenderer : EffectBase
private void Start() {
this.EnsureMaterial(true);
if (Application.isPlaying)
quality = ActionGameManager.PlayerSettings.GraphicsSettings.NebulaQuality;
}
[ImageEffectOpaque]

View file

@ -18,20 +18,24 @@ using static Unity.Mathematics.noise;
[RequireComponent( typeof( Camera ) )]
public class VolumeSampling : MonoBehaviour
{
public Transform GridTransform;
public Camera GridCamera;
public GameSettings Settings;
private float _flowScroll;
public RenderTexture NebulaSurfaceHeight;
public RenderTexture NebulaPatchHeight;
public RenderTexture NebulaPatch;
public RenderTexture NebulaTint;
private float _flowScroll;
private Transform _gridTransform;
void Update()
{
if(_gridTransform==null)
_gridTransform = GridCamera?.transform;
// Shader needs to know the position and scale of cameras used to render input textures
if(GridTransform != null)
Shader.SetGlobalVector("_GridTransform", new Vector4(GridTransform.position.x,GridTransform.position.z,GridTransform.localScale.x));
if(GridCamera != null)
Shader.SetGlobalVector("_GridTransform", new Vector4(_gridTransform.position.x,_gridTransform.position.z,GridCamera.orthographicSize*2));
// Volumetric sampling parameters are used by several shaders
Shader.SetGlobalTexture("_NebulaSurfaceHeight", NebulaSurfaceHeight);

View file

@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
executionOrder: 52
icon: {instanceID: 0}
userData:
assetBundleName:

View file

@ -82,6 +82,7 @@ public class ZoneRenderer : MonoBehaviour
private IDisposable[] _perspectiveSubscriptions = new IDisposable[2];
private List<IDisposable> _zoneSubscriptions = new List<IDisposable>();
private PlanetObject[] _suns;
private bool _showAsteroidUI;
public Dictionary<Wormhole, (GameObject gravity, CompassIcon icon)> WormholeInstances = new Dictionary<Wormhole, (GameObject, CompassIcon)>();
private List<ItemPickup> _loot = new List<ItemPickup>();
@ -144,6 +145,22 @@ public class ZoneRenderer : MonoBehaviour
}
}
public bool ShowAsteroidUI
{
get { return _showAsteroidUI; }
set
{
if (value != _showAsteroidUI)
{
_showAsteroidUI = value;
foreach (var beltUI in _beltObjects.Values)
{
beltUI.Filter.gameObject.SetActive(_showAsteroidUI);
}
}
}
}
public void SetIconSize(float size)
{
foreach(var entityInstance in EntityInstances.Values) entityInstance.MapIcon.transform.localScale = Vector3.one * size;
@ -466,7 +483,8 @@ public class ZoneRenderer : MonoBehaviour
Graphics.DrawMeshInstanced(meshes[i].Mesh, 0, meshes[i].Material, _beltMatrices[belt.Key][i]);
}
_beltObjects[belt.Key].Update(belt.Value.Positions);
if(_showAsteroidUI)
_beltObjects[belt.Key].Update(belt.Value.Positions);
}
foreach (var planet in Planets)
@ -510,16 +528,15 @@ public class ZoneRenderer : MonoBehaviour
wormhole.icon.transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg - 90);
}
var fogPos = FogCameraParent.position;
//var fogPos = FogCameraParent.position;
SectorBoundaryBrush.material.SetFloat("_Power", Settings.PlanetSettings.ZoneDepthExponent);
SectorBoundaryBrush.material.SetFloat("_Depth", Settings.PlanetSettings.ZoneDepth + Settings.PlanetSettings.ZoneBoundaryFog);
var startDepth = Zone.PowerPulse(Settings.MinimapZoneGravityRange, Settings.PlanetSettings.ZoneDepthExponent) *
Settings.PlanetSettings.ZoneDepth;
var depthRange = Settings.PlanetSettings.ZoneDepth - startDepth + _maxDepth;
// var startDepth = Zone.PowerPulse(Settings.MinimapZoneGravityRange, Settings.PlanetSettings.ZoneDepthExponent) *
// Settings.PlanetSettings.ZoneDepth;
//var depthRange = Settings.PlanetSettings.ZoneDepth - startDepth + _maxDepth;
// MinimapGravityQuad.material.SetFloat("_StartDepth", startDepth);
// MinimapGravityQuad.material.SetFloat("_DepthRange", depthRange);
Shader.SetGlobalFloat("_GridOffset", Settings.PlanetSettings.ZoneBoundaryFog);
Shader.SetGlobalVector("_GridTransform", new Vector4(fogPos.x, fogPos.z, _viewDistance * 2));
//Shader.SetGlobalFloat("_GridOffset", Settings.PlanetSettings.ZoneBoundaryFog);
// var gravPos = MinimapGravityQuad.transform.position;
// gravPos.y = -Settings.PlanetSettings.ZoneDepth - _maxDepth;
// MinimapGravityQuad.transform.position = gravPos;

View file

@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 55
executionOrder: 58
icon: {instanceID: 0}
userData:
assetBundleName:

View file

@ -127,8 +127,7 @@ void UpdateParticles(uint3 id : SV_DispatchThreadID, int3 groupID : SV_GroupThre
particles[id.x].position.y = gravHeight + floorHeight + headroom *
pow(RandomValue(), heightExponent) +
perlinNoise1D(RandomValue()*1024)*spacing/2;
float noise;
const float3 flowVec = flow(particles[id.x].position, noise);
const float3 flowVec = flow(particles[id.x].position);
particles[id.x].position -= flowVec * lifetime * period;
const float fade = smoothstep(0,ceilingHeight, particles[id.x].position.y);
const float d = pow(density(particles[id.x].position) + .01, 0.1);

View file

@ -12,7 +12,7 @@ MonoImporter:
- HueTexture: {instanceID: 0}
- Heightmap: {fileID: 8400000, guid: 55786e8a3fda620489070358940e3c04, type: 2}
- Target: {instanceID: 0}
executionOrder: 0
executionOrder: -5
icon: {instanceID: 0}
userData:
assetBundleName:

View file

@ -55,27 +55,6 @@ Texture2D<float2> X2_in;
Texture2D<float2> B2_in;
RWTexture2D<float2> X2_out;
// Adjust step (translate & fade towards global velocity field)
[numthreads(8, 8, 1)]
void Adjust(uint2 tid : SV_DispatchThreadID)
{
uint2 dim;
W_out.GetDimensions(dim.x, dim.y);
float2 uv = (tid + 0.5) / dim;
float2 globalUV = (uv - .5) * _FluidTransform.z + _FluidTransform.xy;
float2 gravUV = getUV(globalUV);
float3 globalPos = float3(globalUV.x, -tex2Dlod(_NebulaSurfaceHeight, float4(gravUV, 0, 0)).x, globalUV.x);
float noise;
float3 f = flow(globalPos, noise);
float2 prevUV = uv - Delta;
if(any(prevUV<0)||any(prevUV>1))
W_out[tid] = f.xz;
else W_out[tid] = lerp(U_in.SampleLevel(samplerU_in, prevUV, 0), f.xz, Damping);
}
// Advect step
[numthreads(8, 8, 1)]
void Advect(uint2 tid : SV_DispatchThreadID)
@ -154,3 +133,23 @@ void Jacobi2(uint2 tid : SV_DispatchThreadID)
X2_out[tid] = (X2_in[tid - int2(1, 0)] + X2_in[tid + int2(1, 0)] +
X2_in[tid - int2(0, 1)] + X2_in[tid + int2(0, 1)] + Alpha * B2_in[tid]) / Beta;
}
// Adjust step (translate & fade towards global velocity field)
[numthreads(8, 8, 1)]
void Adjust(uint2 tid : SV_DispatchThreadID)
{
uint2 dim;
W_out.GetDimensions(dim.x, dim.y);
float2 uv = (tid + float2(.5,.5)) / dim;
float2 globalPosXZ = (uv - .5) * _FluidTransform.z + _FluidTransform.xy;
float2 gravUV = getUV(globalPosXZ);
float3 globalPos = float3(globalPosXZ.x, -tex2Dlod(_NebulaSurfaceHeight, float4(gravUV, 0, 0)).x, globalPosXZ.y);
float2 f = flow(globalPos).xz * (_FluidTransform.z / dim.x);
float2 prevUV = uv - Delta;
//if(any(prevUV<0)||any(prevUV>1))
W_out[tid] = f;
//else W_out[tid] = lerp(U_in.SampleLevel(samplerU_in, prevUV, 0), f, Damping);
}

View file

@ -8,215 +8,213 @@ using static Unity.Mathematics.math;
using int2 = Unity.Mathematics.int2;
using Random = UnityEngine.Random;
namespace StableFluids
public class Fluid : MonoBehaviour
{
public class Fluid : MonoBehaviour
#region Editable attributes
[SerializeField] int _resolution = 512;
[SerializeField] float _viscosity = 1e-6f;
[SerializeField] float _damping = .05f;
[SerializeField] float _range = 512;
[SerializeField] Transform _camera;
#endregion
#region Internal resources
[SerializeField, HideInInspector] ComputeShader _compute;
[SerializeField, HideInInspector] Shader _shader;
#endregion
#region Private members
Material _shaderSheet;
int2 _previousCameraIntPosition = int2.zero;
private List<Force> _forces = new List<Force>();
struct Force
{
#region Editable attributes
[SerializeField] int _resolution = 512;
[SerializeField] float _viscosity = 1e-6f;
[SerializeField] float _damping = .05f;
[SerializeField] float _range = 512;
[SerializeField] Transform _camera;
#endregion
#region Internal resources
[SerializeField, HideInInspector] ComputeShader _compute;
[SerializeField, HideInInspector] Shader _shader;
#endregion
#region Private members
Material _shaderSheet;
int2 _previousCameraIntPosition = int2.zero;
private List<Force> _forces = new List<Force>();
struct Force
{
public float2 Position;
public float2 Vector;
public float Exponent;
}
static class Kernels
{
public const int Advect = 0;
public const int Force = 1;
public const int PSetup = 2;
public const int PFinish = 3;
public const int Jacobi1 = 4;
public const int Jacobi2 = 5;
public const int Adjust = 6;
}
int ThreadCount { get { return (_resolution + 7) / 8; } }
int Resolution { get { return ThreadCount * 8; } }
// Vector field buffers
static class VFB
{
public static RenderTexture V1;
public static RenderTexture V2;
public static RenderTexture V3;
public static RenderTexture P1;
public static RenderTexture P2;
}
RenderTexture AllocateBuffer(int componentCount)
{
var format = RenderTextureFormat.ARGBHalf;
if (componentCount == 1) format = RenderTextureFormat.RHalf;
if (componentCount == 2) format = RenderTextureFormat.RGHalf;
var rt = new RenderTexture(Resolution, Resolution, 0, format);
rt.enableRandomWrite = true;
rt.Create();
return rt;
}
#endregion
#region MonoBehaviour implementation
public void AddForce(float2 position, float2 vector, float exponent)
{
_forces.Add(new Force { Position = position, Vector = vector, Exponent = exponent });
}
void OnValidate()
{
_resolution = Mathf.Max(_resolution, 8);
}
void Start()
{
_shaderSheet = new Material(_shader);
VFB.V1 = AllocateBuffer(2);
VFB.V2 = AllocateBuffer(2);
VFB.V3 = AllocateBuffer(2);
VFB.P1 = AllocateBuffer(1);
VFB.P2 = AllocateBuffer(1);
}
void OnDestroy()
{
Destroy(_shaderSheet);
Destroy(VFB.V1);
Destroy(VFB.V2);
Destroy(VFB.V3);
Destroy(VFB.P1);
Destroy(VFB.P2);
}
void Update()
{
var dt = Time.deltaTime;
var dx = 1.0f / Resolution;
var snapLength = _range / _resolution;
// Input point
var cameraIntPosition = int2(
(int)(_camera.position.x / snapLength),
(int)(_camera.position.z / snapLength)
);
var cameraPosition = float2(
cameraIntPosition.x * snapLength,
cameraIntPosition.y * snapLength
);
Shader.SetGlobalVector("_FluidTransform", new Vector4(cameraPosition.x, cameraPosition.y, _range));
var delta = (float2)(cameraIntPosition - _previousCameraIntPosition) / Resolution;
_compute.SetVector("Delta", new Vector4(delta.x,delta.y));
_compute.SetFloat("Damping", _damping);
_compute.SetTexture(Kernels.Adjust, "U_in", VFB.V1);
_compute.SetTexture(Kernels.Adjust, "W_out", VFB.V3);
_compute.Dispatch(Kernels.Adjust, ThreadCount, ThreadCount, 1);
// Common variables
_compute.SetFloat("Time", Time.time);
_compute.SetFloat("DeltaTime", dt);
// Advection
_compute.SetTexture(Kernels.Advect, "U_in", VFB.V3);
_compute.SetTexture(Kernels.Advect, "W_out", VFB.V2);
_compute.Dispatch(Kernels.Advect, ThreadCount, ThreadCount, 1);
// Diffuse setup
var dif_alpha = dx * dx / (_viscosity * dt);
_compute.SetFloat("Alpha", dif_alpha);
_compute.SetFloat("Beta", 4 + dif_alpha);
Graphics.CopyTexture(VFB.V2, VFB.V1);
_compute.SetTexture(Kernels.Jacobi2, "B2_in", VFB.V1);
// Jacobi iteration
for (var i = 0; i < 20; i++)
{
_compute.SetTexture(Kernels.Jacobi2, "X2_in", VFB.V2);
_compute.SetTexture(Kernels.Jacobi2, "X2_out", VFB.V3);
_compute.Dispatch(Kernels.Jacobi2, ThreadCount, ThreadCount, 1);
_compute.SetTexture(Kernels.Jacobi2, "X2_in", VFB.V3);
_compute.SetTexture(Kernels.Jacobi2, "X2_out", VFB.V2);
_compute.Dispatch(Kernels.Jacobi2, ThreadCount, ThreadCount, 1);
}
float2 getUV(float2 pos, float2 camPos, float scale)
{
return -(pos-camPos)/scale + float2(.5f,.5f);
}
// Add external forces
foreach(var force in _forces)
{
var uv = getUV(force.Position, cameraIntPosition, _range);
_compute.SetVector("ForceOrigin", new Vector4(uv.x,uv.y));
_compute.SetFloat("ForceExponent", force.Exponent);
_compute.SetTexture(Kernels.Force, "W_in", VFB.V2);
_compute.SetTexture(Kernels.Force, "W_out", VFB.V3);
_compute.SetVector("ForceVector", new Vector4(force.Vector.x,force.Vector.y));
_compute.Dispatch(Kernels.Force, ThreadCount, ThreadCount, 1);
}
// Projection setup
_compute.SetTexture(Kernels.PSetup, "W_in", VFB.V3);
_compute.SetTexture(Kernels.PSetup, "DivW_out", VFB.V2);
_compute.SetTexture(Kernels.PSetup, "P_out", VFB.P1);
_compute.Dispatch(Kernels.PSetup, ThreadCount, ThreadCount, 1);
// Jacobi iteration
_compute.SetFloat("Alpha", -dx * dx);
_compute.SetFloat("Beta", 4);
_compute.SetTexture(Kernels.Jacobi1, "B1_in", VFB.V2);
for (var i = 0; i < 20; i++)
{
_compute.SetTexture(Kernels.Jacobi1, "X1_in", VFB.P1);
_compute.SetTexture(Kernels.Jacobi1, "X1_out", VFB.P2);
_compute.Dispatch(Kernels.Jacobi1, ThreadCount, ThreadCount, 1);
_compute.SetTexture(Kernels.Jacobi1, "X1_in", VFB.P2);
_compute.SetTexture(Kernels.Jacobi1, "X1_out", VFB.P1);
_compute.Dispatch(Kernels.Jacobi1, ThreadCount, ThreadCount, 1);
}
// Projection finish
_compute.SetTexture(Kernels.PFinish, "W_in", VFB.V3);
_compute.SetTexture(Kernels.PFinish, "P_in", VFB.P1);
_compute.SetTexture(Kernels.PFinish, "U_out", VFB.V1);
_compute.Dispatch(Kernels.PFinish, ThreadCount, ThreadCount, 1);
_previousCameraIntPosition = cameraIntPosition;
}
#endregion
public float2 Position;
public float2 Vector;
public float Exponent;
}
}
static class Kernels
{
public const int Advect = 0;
public const int Force = 1;
public const int PSetup = 2;
public const int PFinish = 3;
public const int Jacobi1 = 4;
public const int Jacobi2 = 5;
public const int Adjust = 6;
}
int ThreadCount { get { return (_resolution + 7) / 8; } }
int Resolution { get { return ThreadCount * 8; } }
// Vector field buffers
static class VFB
{
public static RenderTexture V1;
public static RenderTexture V2;
public static RenderTexture V3;
public static RenderTexture P1;
public static RenderTexture P2;
}
RenderTexture AllocateBuffer(int componentCount)
{
var format = RenderTextureFormat.ARGBHalf;
if (componentCount == 1) format = RenderTextureFormat.RHalf;
if (componentCount == 2) format = RenderTextureFormat.RGHalf;
var rt = new RenderTexture(Resolution, Resolution, 0, format);
rt.enableRandomWrite = true;
rt.Create();
return rt;
}
#endregion
#region MonoBehaviour implementation
public void AddForce(float2 position, float2 vector, float exponent)
{
_forces.Add(new Force { Position = position, Vector = vector, Exponent = exponent });
}
void OnValidate()
{
_resolution = Mathf.Max(_resolution, 8);
}
void Start()
{
_shaderSheet = new Material(_shader);
VFB.V1 = AllocateBuffer(2);
VFB.V2 = AllocateBuffer(2);
VFB.V3 = AllocateBuffer(2);
VFB.P1 = AllocateBuffer(1);
VFB.P2 = AllocateBuffer(1);
}
void OnDestroy()
{
Destroy(_shaderSheet);
Destroy(VFB.V1);
Destroy(VFB.V2);
Destroy(VFB.V3);
Destroy(VFB.P1);
Destroy(VFB.P2);
}
void Update()
{
var dt = max(Time.deltaTime, .01f);
var dx = 1.0f / Resolution;
var snapLength = _range / _resolution;
// Input point
var cameraIntPosition = int2(
(int)(_camera.position.x / snapLength),
(int)(_camera.position.z / snapLength)
);
var cameraPosition = float2(
cameraIntPosition.x * snapLength,
cameraIntPosition.y * snapLength
);
Shader.SetGlobalVector("_FluidTransform", new Vector4(cameraPosition.x, cameraPosition.y, _range));
Shader.SetGlobalTexture("_FluidVelocity", VFB.V1);
var delta = (float2)(cameraIntPosition - _previousCameraIntPosition) / Resolution;
_compute.SetVector("Delta", new Vector4(delta.x,delta.y));
_compute.SetFloat("Damping", _damping);
_compute.SetTexture(Kernels.Adjust, "U_in", VFB.V1);
_compute.SetTexture(Kernels.Adjust, "W_out", VFB.V3);
_compute.Dispatch(Kernels.Adjust, ThreadCount, ThreadCount, 1);
// Common variables
_compute.SetFloat("Time", Time.time);
_compute.SetFloat("DeltaTime", dt);
// Advection
_compute.SetTexture(Kernels.Advect, "U_in", VFB.V3);
_compute.SetTexture(Kernels.Advect, "W_out", VFB.V2);
_compute.Dispatch(Kernels.Advect, ThreadCount, ThreadCount, 1);
// Diffuse setup
var dif_alpha = dx * dx / (_viscosity * dt);
_compute.SetFloat("Alpha", dif_alpha);
_compute.SetFloat("Beta", 4 + dif_alpha);
Graphics.CopyTexture(VFB.V2, VFB.V1);
_compute.SetTexture(Kernels.Jacobi2, "B2_in", VFB.V1);
// Jacobi iteration
for (var i = 0; i < 20; i++)
{
_compute.SetTexture(Kernels.Jacobi2, "X2_in", VFB.V2);
_compute.SetTexture(Kernels.Jacobi2, "X2_out", VFB.V3);
_compute.Dispatch(Kernels.Jacobi2, ThreadCount, ThreadCount, 1);
_compute.SetTexture(Kernels.Jacobi2, "X2_in", VFB.V3);
_compute.SetTexture(Kernels.Jacobi2, "X2_out", VFB.V2);
_compute.Dispatch(Kernels.Jacobi2, ThreadCount, ThreadCount, 1);
}
float2 getUV(float2 pos, float2 camPos, float scale)
{
return -(pos-camPos)/scale + float2(.5f,.5f);
}
// Add external forces
foreach(var force in _forces)
{
var uv = getUV(force.Position, cameraIntPosition, _range);
_compute.SetVector("ForceOrigin", new Vector4(uv.x,uv.y));
_compute.SetFloat("ForceExponent", force.Exponent);
_compute.SetTexture(Kernels.Force, "W_in", VFB.V2);
_compute.SetTexture(Kernels.Force, "W_out", VFB.V3);
_compute.SetVector("ForceVector", new Vector4(force.Vector.x,force.Vector.y));
_compute.Dispatch(Kernels.Force, ThreadCount, ThreadCount, 1);
}
// Projection setup
_compute.SetTexture(Kernels.PSetup, "W_in", VFB.V3);
_compute.SetTexture(Kernels.PSetup, "DivW_out", VFB.V2);
_compute.SetTexture(Kernels.PSetup, "P_out", VFB.P1);
_compute.Dispatch(Kernels.PSetup, ThreadCount, ThreadCount, 1);
// Jacobi iteration
_compute.SetFloat("Alpha", -dx * dx);
_compute.SetFloat("Beta", 4);
_compute.SetTexture(Kernels.Jacobi1, "B1_in", VFB.V2);
for (var i = 0; i < 20; i++)
{
_compute.SetTexture(Kernels.Jacobi1, "X1_in", VFB.P1);
_compute.SetTexture(Kernels.Jacobi1, "X1_out", VFB.P2);
_compute.Dispatch(Kernels.Jacobi1, ThreadCount, ThreadCount, 1);
_compute.SetTexture(Kernels.Jacobi1, "X1_in", VFB.P2);
_compute.SetTexture(Kernels.Jacobi1, "X1_out", VFB.P1);
_compute.Dispatch(Kernels.Jacobi1, ThreadCount, ThreadCount, 1);
}
// Projection finish
_compute.SetTexture(Kernels.PFinish, "W_in", VFB.V3);
_compute.SetTexture(Kernels.PFinish, "P_in", VFB.P1);
_compute.SetTexture(Kernels.PFinish, "U_out", VFB.V1);
_compute.Dispatch(Kernels.PFinish, ThreadCount, ThreadCount, 1);
_previousCameraIntPosition = cameraIntPosition;
}
#endregion
}

View file

@ -42,6 +42,7 @@ uniform sampler2D _NebulaPatch;
uniform sampler2D _NebulaPatchHeight;
uniform sampler2D _NebulaTint;
float4 _NebulaTint_TexelSize;
uniform sampler2D _FluidVelocity;
uniform float3 _GridTransform;
uniform float3 _FluidTransform;
@ -105,6 +106,11 @@ float2 getUV(float2 pos)
return -(pos-_GridTransform.xy)/_GridTransform.z + float2(.5,.5);
}
float2 getUVFluid(float2 pos)
{
return (pos-_FluidTransform.xy)/_FluidTransform.z + float2(.5,.5);
}
float cloudDensity(float3 pos, float surfaceDisp)
{
float2 uv = getUV(pos.xz);
@ -118,11 +124,20 @@ float cloudDensity(float3 pos, float surfaceDisp)
return patchDensity + max(0,floorDensity);
}
float3 flow(float3 pos, out float noise)
// TODO: Get this working?
float2 flowTex(float3 pos)
{
const float2 fluidUv = getUVFluid(pos.xz);
if(any(fluidUv<0)||any(fluidUv>1)) return 0;
const float2 fluidSample = tex2Dlod(_FluidVelocity, half4(fluidUv, 0, 0)).xy;
// TODO: remove magic number for fluid texture dimensions
return float3(fluidSample.x,0,fluidSample.y) * (512 / _FluidTransform.z);
}
float3 flow(float3 pos)
{
const float4 noiseSample1 = Value3D_Deriv( pos / _FlowScale - float3(0,_FlowScroll,0) );
const float4 noiseSample2 = Value3D_Deriv( pos / (_FlowScale * 1.61803398875) - float3(0,_FlowScroll,0) ); // make it golden
noise = noiseSample1.x;
return cross(normalize(noiseSample2.yzw), normalize(noiseSample1.yzw)) * _FlowAmplitude;
}
@ -138,17 +153,16 @@ float density(float3 pos)
if(dist < _SafetyDistance)
{
const float heightFade = smoothstep(_SafetyDistance,_SafetyDistance*.75,dist);
float noise;
const float3 fl = flow(pos, noise);
const float lerp1 = frac(_Time.y / _FlowPeriod + noise);
const float lerp2 = frac(_Time.y / _FlowPeriod + .5 + noise);
const float noise1 = pow(triNoise3d((pos+fl * lerp1 * _FlowPeriod) / _NebulaNoiseScale),_NebulaNoiseExponent) * _NebulaNoiseAmplitude * tri2(lerp1);
const float noise2 = pow(triNoise3d((pos+fl * lerp2 * _FlowPeriod) / _NebulaNoiseScale),_NebulaNoiseExponent) * _NebulaNoiseAmplitude * tri2(lerp2);
const float3 fl = flow(pos);
const float lerp1 = frac(_Time.y / _FlowPeriod);
const float lerp2 = frac(_Time.y / _FlowPeriod + .5);
const float noise1 = pow(triNoise3d((pos+fl * (lerp1 - .5) * _FlowPeriod) / _NebulaNoiseScale),_NebulaNoiseExponent) * _NebulaNoiseAmplitude * tri2(lerp1);
const float noise2 = pow(triNoise3d((pos+fl * (lerp2 - .5) * _FlowPeriod) / _NebulaNoiseScale),_NebulaNoiseExponent) * _NebulaNoiseAmplitude * tri2(lerp2);
pos.y += (noise1 + noise2) * heightFade;
const float lerp3 = frac(_Time.y / _FlowPeriod * 2);
const float lerp4 = frac(_Time.y / _FlowPeriod * 2 + .5);
const float noise3 = pow(triNoise3d((pos+fl * lerp3 * _FlowPeriod / 2) / _NebulaNoiseScale * 8), _NebulaNoiseExponent) * _NebulaNoiseAmplitude * tri2(lerp3) / 2;
const float noise4 = pow(triNoise3d((pos+fl * lerp4 * _FlowPeriod / 2) / _NebulaNoiseScale * 8), _NebulaNoiseExponent) * _NebulaNoiseAmplitude * tri2(lerp4) / 2;
const float lerp3 = frac(_Time.y / _FlowPeriod * 2 + .25);
const float lerp4 = frac(_Time.y / _FlowPeriod * 2 + .75);
const float noise3 = pow(triNoise3d((pos+fl * (lerp3 - .5) * _FlowPeriod / 2) / _NebulaNoiseScale * 8), _NebulaNoiseExponent) * _NebulaNoiseAmplitude * tri2(lerp3) / 2;
const float noise4 = pow(triNoise3d((pos+fl * (lerp4 - .5) * _FlowPeriod / 2) / _NebulaNoiseScale * 8), _NebulaNoiseExponent) * _NebulaNoiseAmplitude * tri2(lerp4) / 2;
pos.y -= (noise3 + noise4) * heightFade;
d += cloudDensity(pos, surfaceDisp);
}

BIN
GameData/PlayerSettings.msgpack (Stored with Git LFS)

Binary file not shown.

BIN
UserSettings/EditorUserSettings.asset (Stored with Git LFS)

Binary file not shown.

File diff suppressed because it is too large Load diff