From 4598f9307014d602e52ad37b18c4dae887b32593 Mon Sep 17 00:00:00 2001 From: C09 <100433934+CI09@users.noreply.github.com> Date: Sun, 10 Nov 2024 17:29:53 +0100 Subject: [PATCH 1/5] Begin implementing primitive multicellular matrix --- src/microbe_stage/IMembraneDataSource.cs | 8 +- src/microbe_stage/MembraneShapeGenerator.cs | 37 +++++++-- .../systems/MicrobeVisualsSystem.cs | 78 ++++++++++++++++++- 3 files changed, 114 insertions(+), 9 deletions(-) diff --git a/src/microbe_stage/IMembraneDataSource.cs b/src/microbe_stage/IMembraneDataSource.cs index 1a160cda79b..72065a3feba 100644 --- a/src/microbe_stage/IMembraneDataSource.cs +++ b/src/microbe_stage/IMembraneDataSource.cs @@ -18,14 +18,18 @@ public interface IMembraneDataSource /// public struct MembraneGenerationParameters : IMembraneDataSource { - public MembraneGenerationParameters(Vector2[] hexPositions, int hexPositionCount, MembraneType type) + public MembraneGenerationParameters(Vector2[] hexPositions, int hexPositionCount, MembraneType type, Vector2[]? multicellularPositions, Vector2? thisCellPosition) { HexPositions = hexPositions; + MulticellularPositions = multicellularPositions; + CellPositionInMulticellular = thisCellPosition; HexPositionCount = hexPositionCount; Type = type; } public Vector2[] HexPositions { get; } + public Vector2[]? MulticellularPositions { get; } + public Vector2? CellPositionInMulticellular { get; } public int HexPositionCount { get; } public MembraneType Type { get; } @@ -108,7 +112,7 @@ public static MembranePointData GetOrComputeMembraneShape(IReadOnlyList, which should be /// checked for existing data before computing new data) /// - public MembranePointData GenerateShape(Vector2[] hexPositions, int hexCount, MembraneType membraneType) + public MembranePointData GenerateShape(Vector2[] hexPositions, int hexCount, MembraneType membraneType, + Vector2[]? cellPositions, Vector2? thisCellPosition) { // The length in pixels (probably not accurate?) of a side of the square that bounds the membrane. // Half the side length of the original square that is compressed to make the membrane. @@ -109,7 +110,7 @@ public MembranePointData GenerateShape(Vector2[] hexPositions, int hexCount, Mem // ReSharper restore PossibleLossOfFraction // Get new membrane points for vertices2D - GenerateMembranePoints(hexPositions, hexCount, membraneType); + GenerateMembranePoints(hexPositions, hexCount, membraneType, cellPositions, thisCellPosition); // This makes a copy of the vertices so the data is safe to modify in further calls to this method return new MembranePointData(hexPositions, hexCount, membraneType, vertices2D); @@ -117,12 +118,13 @@ public MembranePointData GenerateShape(Vector2[] hexPositions, int hexCount, Mem public MembranePointData GenerateShape(ref MembraneGenerationParameters parameters) { - return GenerateShape(parameters.HexPositions, parameters.HexPositionCount, parameters.Type); + return GenerateShape(parameters.HexPositions, parameters.HexPositionCount, parameters.Type, + parameters.MulticellularPositions, parameters.CellPositionInMulticellular); } public MembranePointData GenerateShape(IMembraneDataSource parameters) { - return GenerateShape(parameters.HexPositions, parameters.HexPositionCount, parameters.Type); + return GenerateShape(parameters.HexPositions, parameters.HexPositionCount, parameters.Type, null, null); } /// @@ -464,7 +466,8 @@ private static ArrayMesh BuildEngulfMesh(Vector2[] vertices2D, int vertexCount, return generatedMesh; } - private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, MembraneType membraneType) + private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, MembraneType membraneType, + Vector2[]? cellPositions, Vector2? thisCellPosition) { // Move all the points in the source buffer close to organelles // This operation used to be iterative but this is now a much faster version that moves things all the way in @@ -479,6 +482,30 @@ private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, Membra startingBuffer[i] = closestOrganelle + movement; } + // Multicellular matrix + if (thisCellPosition != null && cellPositions != null) + { + for (int i = 0, end = startingBuffer.Count; i < end; ++i) + { + // Make into constant unless you will forget + var multicellularHexDistanceMultiplier = 20; + + Vector2 movement = default; + + foreach (var cellPosition in cellPositions) + { + // Not normalizing due to need to keep proportions + var multicellularDirection = (cellPosition * multicellularHexDistanceMultiplier) + - (thisCellPosition * multicellularHexDistanceMultiplier + startingBuffer[i]); + + if (multicellularDirection != null) + movement += multicellularDirection.Value; + } + + startingBuffer[i] = startingBuffer[i] + movement; + } + } + float circumference = 0.0f; for (int i = 0, end = startingBuffer.Count; i < end; ++i) diff --git a/src/microbe_stage/systems/MicrobeVisualsSystem.cs b/src/microbe_stage/systems/MicrobeVisualsSystem.cs index 1e80e9b86d0..05175ccfa6f 100644 --- a/src/microbe_stage/systems/MicrobeVisualsSystem.cs +++ b/src/microbe_stage/systems/MicrobeVisualsSystem.cs @@ -11,6 +11,7 @@ using DefaultEcs; using DefaultEcs.System; using Godot; +using HarmonyLib; using World = DefaultEcs.World; /// @@ -136,8 +137,17 @@ protected override void Update(float delta, in Entity entity) ref var materialStorage = ref entity.Get(); + MembranePointData? data = null; + // Background thread membrane generation - var data = GetMembraneDataIfReadyOrStartGenerating(ref cellProperties, ref organelleContainer); + if (entity.Has()) + { + data = GetMulticellularMembraneDataIfReadyOrStartGenerating(ref cellProperties, ref organelleContainer, ref entity.Get()); + } + else + { + data = GetMembraneDataIfReadyOrStartGenerating(ref cellProperties, ref organelleContainer); + } if (data == null) { @@ -258,7 +268,71 @@ protected override void PostUpdate(float state) } } - membranesToGenerate.Enqueue(new MembraneGenerationParameters(hexes, hexCount, cellProperties.MembraneType)); + membranesToGenerate.Enqueue(new MembraneGenerationParameters(hexes, hexCount, cellProperties.MembraneType, null, null)); + + // Immediately start some jobs to give background threads something to do while the main thread is busy + // potentially setting up other visuals + StartMembraneGenerationJobs(); + + return null; + } + + private MembranePointData? GetMulticellularMembraneDataIfReadyOrStartGenerating(ref CellProperties cellProperties, + ref OrganelleContainer organelleContainer, ref EarlyMulticellularSpeciesMember multicellular) + { + // TODO: should we consider the situation where a membrane was requested on the previous update but is not + // ready yet? This causes extra memory usage here in those cases. + var hexes = MembraneComputationHelpers.PrepareHexPositionsForMembraneCalculations( + organelleContainer.Organelles!.Organelles, out var hexCount); + + var hash = MembraneComputationHelpers.ComputeMembraneDataHash(hexes, hexCount, cellProperties.MembraneType); + + var cachedMembrane = ProceduralDataCache.Instance.ReadMembraneData(hash); + + if (cachedMembrane != null) + { + // TODO: hopefully this can't get into a permanent loop where 2 conflicting membranes want to + // re-generate on each game update cycle + if (!cachedMembrane.MembraneDataFieldsEqual(hexes, hexCount, cellProperties.MembraneType)) + { + CacheableDataExtensions.OnCacheHashCollision(hash); + cachedMembrane = null; + } + } + + if (cachedMembrane != null) + { + // Membrane was ready now + return cachedMembrane; + } + + // Need to generate a new membrane + + lock (pendingGenerationsOfMembraneHashes) + { + if (!pendingGenerationsOfMembraneHashes.Add(hash)) + { + // Already queued, don't need to queue again + + // Return the unnecessary array that there won't be a cache entry to hold to the pool + ArrayPool.Shared.Return(hexes); + + return null; + } + } + + List positions = new List(); + + foreach (var cell in multicellular.Species.Cells) + { + var cartesian = Hex.AxialToCartesian(cell.Position); + positions.AddItem(new Vector2(cartesian.X, cartesian.Z)); + } + + var thisCartesian = Hex.AxialToCartesian(multicellular.Species.Cells[multicellular.MulticellularBodyPlanPartIndex].Position); + var thisVector2 = new Vector2(thisCartesian.X, thisCartesian.Z); + + membranesToGenerate.Enqueue(new MembraneGenerationParameters(hexes, hexCount, cellProperties.MembraneType, positions.ToArray(), thisVector2)); // Immediately start some jobs to give background threads something to do while the main thread is busy // potentially setting up other visuals From 710b2258732c4ecbeb9cbb5e79e46eee11383fbb Mon Sep 17 00:00:00 2001 From: C09 <100433934+CI09@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:14:17 +0100 Subject: [PATCH 2/5] Attempt at fixing constant membrane re-generation --- src/microbe_stage/IMembraneDataSource.cs | 22 ++++++++++++++-- src/microbe_stage/MembranePointData.cs | 8 +++++- src/microbe_stage/MembraneShapeGenerator.cs | 10 ++++--- .../systems/MicrobeVisualsSystem.cs | 26 +++++++++++-------- 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/microbe_stage/IMembraneDataSource.cs b/src/microbe_stage/IMembraneDataSource.cs index 72065a3feba..8bd5cf952cf 100644 --- a/src/microbe_stage/IMembraneDataSource.cs +++ b/src/microbe_stage/IMembraneDataSource.cs @@ -9,6 +9,9 @@ public interface IMembraneDataSource { public Vector2[] HexPositions { get; } + + public Vector2[]? MulticellularPositions { get; } + public int HexPositionCount { get; } public MembraneType Type { get; } } @@ -150,11 +153,11 @@ public static long ComputeMembraneDataHash(this IMembraneDataSource dataSource) public static bool MembraneDataFieldsEqual(this IMembraneDataSource dataSource, IMembraneDataSource other) { - return dataSource.MembraneDataFieldsEqual(other.HexPositions, other.HexPositionCount, other.Type); + return dataSource.MembraneDataFieldsEqual(other.HexPositions, other.HexPositionCount, other.Type, other.MulticellularPositions); } public static bool MembraneDataFieldsEqual(this IMembraneDataSource dataSource, Vector2[] otherPoints, - int otherPointCount, MembraneType otherType) + int otherPointCount, MembraneType otherType, Vector2[]? multicellularPositions) { if (!dataSource.Type.Equals(otherType)) return false; @@ -166,6 +169,21 @@ public static bool MembraneDataFieldsEqual(this IMembraneDataSource dataSource, var sourcePoints = dataSource.HexPositions; + if (dataSource.MulticellularPositions != null) + { + if (!dataSource.MulticellularPositions.Equals(multicellularPositions)) + { + return false; + } + GD.Print("elo"); + } + else + { + if (multicellularPositions != null) + return false; + GD.Print("olelo"); + } + for (int i = 0; i < count; ++i) { if (sourcePoints[i] != otherPoints[i]) diff --git a/src/microbe_stage/MembranePointData.cs b/src/microbe_stage/MembranePointData.cs index 65da4bad70a..238176bb14c 100644 --- a/src/microbe_stage/MembranePointData.cs +++ b/src/microbe_stage/MembranePointData.cs @@ -23,11 +23,12 @@ public sealed class MembranePointData : IMembraneDataSource, ICacheableData private bool disposed; public MembranePointData(Vector2[] hexPositions, int hexPositionCount, MembraneType type, - IReadOnlyList verticesToCopy) + IReadOnlyList verticesToCopy, Vector2[]? multicellularPositions) { HexPositions = hexPositions; Type = type; HexPositionCount = hexPositionCount; + MulticellularPositions = multicellularPositions; // Setup mesh to be generated (on the main thread) only when required finalMesh = new Lazy<(ArrayMesh Mesh, int SurfaceIndex)>(() => @@ -82,6 +83,11 @@ public MembranePointData(Vector2[] hexPositions, int hexPositionCount, MembraneT /// public Vector2[] HexPositions { get; } + /// + /// Positions of other cells in multicellular organism + /// + public Vector2[]? MulticellularPositions { get; } + public int HexPositionCount { get; } public MembraneType Type { get; } diff --git a/src/microbe_stage/MembraneShapeGenerator.cs b/src/microbe_stage/MembraneShapeGenerator.cs index e5a545fa83c..555d72e546b 100644 --- a/src/microbe_stage/MembraneShapeGenerator.cs +++ b/src/microbe_stage/MembraneShapeGenerator.cs @@ -112,8 +112,10 @@ public MembranePointData GenerateShape(Vector2[] hexPositions, int hexCount, Mem // Get new membrane points for vertices2D GenerateMembranePoints(hexPositions, hexCount, membraneType, cellPositions, thisCellPosition); + GD.Print(cellPositions == null); + // This makes a copy of the vertices so the data is safe to modify in further calls to this method - return new MembranePointData(hexPositions, hexCount, membraneType, vertices2D); + return new MembranePointData(hexPositions, hexCount, membraneType, vertices2D, cellPositions); } public MembranePointData GenerateShape(ref MembraneGenerationParameters parameters) @@ -483,12 +485,12 @@ private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, Membra } // Multicellular matrix - if (thisCellPosition != null && cellPositions != null) + /*if (thisCellPosition != null && cellPositions != null) { for (int i = 0, end = startingBuffer.Count; i < end; ++i) { // Make into constant unless you will forget - var multicellularHexDistanceMultiplier = 20; + var multicellularHexDistanceMultiplier = 1; Vector2 movement = default; @@ -504,7 +506,7 @@ private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, Membra startingBuffer[i] = startingBuffer[i] + movement; } - } + }*/ float circumference = 0.0f; diff --git a/src/microbe_stage/systems/MicrobeVisualsSystem.cs b/src/microbe_stage/systems/MicrobeVisualsSystem.cs index 05175ccfa6f..7c1d019181d 100644 --- a/src/microbe_stage/systems/MicrobeVisualsSystem.cs +++ b/src/microbe_stage/systems/MicrobeVisualsSystem.cs @@ -240,7 +240,7 @@ protected override void PostUpdate(float state) { // TODO: hopefully this can't get into a permanent loop where 2 conflicting membranes want to // re-generate on each game update cycle - if (!cachedMembrane.MembraneDataFieldsEqual(hexes, hexCount, cellProperties.MembraneType)) + if (!cachedMembrane.MembraneDataFieldsEqual(hexes, hexCount, cellProperties.MembraneType, null)) { CacheableDataExtensions.OnCacheHashCollision(hash); cachedMembrane = null; @@ -285,6 +285,16 @@ protected override void PostUpdate(float state) var hexes = MembraneComputationHelpers.PrepareHexPositionsForMembraneCalculations( organelleContainer.Organelles!.Organelles, out var hexCount); + List positions = new List(); + + foreach (var cell in multicellular.Species.Cells) + { + var cartesian = Hex.AxialToCartesian(cell.Position); + positions.AddItem(new Vector2(cartesian.X, cartesian.Z)); + } + + var positionsArray = positions.ToArray(); + var hash = MembraneComputationHelpers.ComputeMembraneDataHash(hexes, hexCount, cellProperties.MembraneType); var cachedMembrane = ProceduralDataCache.Instance.ReadMembraneData(hash); @@ -293,10 +303,12 @@ protected override void PostUpdate(float state) { // TODO: hopefully this can't get into a permanent loop where 2 conflicting membranes want to // re-generate on each game update cycle - if (!cachedMembrane.MembraneDataFieldsEqual(hexes, hexCount, cellProperties.MembraneType)) + if (!cachedMembrane.MembraneDataFieldsEqual(hexes, hexCount, cellProperties.MembraneType, positionsArray)) { CacheableDataExtensions.OnCacheHashCollision(hash); cachedMembrane = null; + + GD.Print("uhm"); } } @@ -321,18 +333,10 @@ protected override void PostUpdate(float state) } } - List positions = new List(); - - foreach (var cell in multicellular.Species.Cells) - { - var cartesian = Hex.AxialToCartesian(cell.Position); - positions.AddItem(new Vector2(cartesian.X, cartesian.Z)); - } - var thisCartesian = Hex.AxialToCartesian(multicellular.Species.Cells[multicellular.MulticellularBodyPlanPartIndex].Position); var thisVector2 = new Vector2(thisCartesian.X, thisCartesian.Z); - membranesToGenerate.Enqueue(new MembraneGenerationParameters(hexes, hexCount, cellProperties.MembraneType, positions.ToArray(), thisVector2)); + membranesToGenerate.Enqueue(new MembraneGenerationParameters(hexes, hexCount, cellProperties.MembraneType, positionsArray, thisVector2)); // Immediately start some jobs to give background threads something to do while the main thread is busy // potentially setting up other visuals From fc34db9edd999c25afc7a8fa86a3acc994bfd477 Mon Sep 17 00:00:00 2001 From: C09 <100433934+CI09@users.noreply.github.com> Date: Wed, 13 Nov 2024 18:33:05 +0100 Subject: [PATCH 3/5] Make multicellular matrix data flow work --- src/microbe_stage/IMembraneDataSource.cs | 21 ++++++++++------ src/microbe_stage/MembraneShapeGenerator.cs | 25 ++++++++----------- .../systems/MicrobeVisualsSystem.cs | 8 +++--- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/microbe_stage/IMembraneDataSource.cs b/src/microbe_stage/IMembraneDataSource.cs index 8bd5cf952cf..9cca39bb36c 100644 --- a/src/microbe_stage/IMembraneDataSource.cs +++ b/src/microbe_stage/IMembraneDataSource.cs @@ -1,6 +1,7 @@ using System; using System.Buffers; using System.Collections.Generic; +using System.Linq; using Godot; /// @@ -96,7 +97,7 @@ public static MembranePointData GetOrComputeMembraneShape(IReadOnlyList 0); } public static bool MembraneDataFieldsEqual(this IMembraneDataSource dataSource, IMembraneDataSource other) @@ -171,17 +174,21 @@ public static bool MembraneDataFieldsEqual(this IMembraneDataSource dataSource, if (dataSource.MulticellularPositions != null) { - if (!dataSource.MulticellularPositions.Equals(multicellularPositions)) + if (multicellularPositions == null) + return false; + + if (!dataSource.MulticellularPositions.SequenceEqual(multicellularPositions)) { return false; } - GD.Print("elo"); } else { if (multicellularPositions != null) + { return false; - GD.Print("olelo"); + + } } for (int i = 0; i < count; ++i) diff --git a/src/microbe_stage/MembraneShapeGenerator.cs b/src/microbe_stage/MembraneShapeGenerator.cs index 555d72e546b..9dc7e95b25f 100644 --- a/src/microbe_stage/MembraneShapeGenerator.cs +++ b/src/microbe_stage/MembraneShapeGenerator.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Godot; using Array = Godot.Collections.Array; @@ -485,28 +486,24 @@ private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, Membra } // Multicellular matrix - /*if (thisCellPosition != null && cellPositions != null) + if (thisCellPosition != null && cellPositions != null) { + // Make into constant unless you will forget + var multicellularHexDistanceMultiplier = 10f; + + + for (int i = 0, end = startingBuffer.Count; i < end; ++i) { - // Make into constant unless you will forget - var multicellularHexDistanceMultiplier = 1; + - Vector2 movement = default; + var movement = thisCellPosition.Value; - foreach (var cellPosition in cellPositions) - { - // Not normalizing due to need to keep proportions - var multicellularDirection = (cellPosition * multicellularHexDistanceMultiplier) - - (thisCellPosition * multicellularHexDistanceMultiplier + startingBuffer[i]); - - if (multicellularDirection != null) - movement += multicellularDirection.Value; - } + GD.Print(movement); startingBuffer[i] = startingBuffer[i] + movement; } - }*/ + } float circumference = 0.0f; diff --git a/src/microbe_stage/systems/MicrobeVisualsSystem.cs b/src/microbe_stage/systems/MicrobeVisualsSystem.cs index 7c1d019181d..932a968a603 100644 --- a/src/microbe_stage/systems/MicrobeVisualsSystem.cs +++ b/src/microbe_stage/systems/MicrobeVisualsSystem.cs @@ -232,7 +232,7 @@ protected override void PostUpdate(float state) var hexes = MembraneComputationHelpers.PrepareHexPositionsForMembraneCalculations( organelleContainer.Organelles!.Organelles, out var hexCount); - var hash = MembraneComputationHelpers.ComputeMembraneDataHash(hexes, hexCount, cellProperties.MembraneType); + var hash = MembraneComputationHelpers.ComputeMembraneDataHash(hexes, hexCount, cellProperties.MembraneType, false); var cachedMembrane = ProceduralDataCache.Instance.ReadMembraneData(hash); @@ -290,12 +290,12 @@ protected override void PostUpdate(float state) foreach (var cell in multicellular.Species.Cells) { var cartesian = Hex.AxialToCartesian(cell.Position); - positions.AddItem(new Vector2(cartesian.X, cartesian.Z)); + positions.Add(new Vector2(cartesian.X, cartesian.Z)); } var positionsArray = positions.ToArray(); - var hash = MembraneComputationHelpers.ComputeMembraneDataHash(hexes, hexCount, cellProperties.MembraneType); + var hash = MembraneComputationHelpers.ComputeMembraneDataHash(hexes, hexCount, cellProperties.MembraneType, true); var cachedMembrane = ProceduralDataCache.Instance.ReadMembraneData(hash); @@ -307,8 +307,6 @@ protected override void PostUpdate(float state) { CacheableDataExtensions.OnCacheHashCollision(hash); cachedMembrane = null; - - GD.Print("uhm"); } } From b94ded6b1f2f3d2a033a4dbe72c354c3622ca329 Mon Sep 17 00:00:00 2001 From: dligr Date: Sat, 16 Nov 2024 16:49:47 +0300 Subject: [PATCH 4/5] Project membrane vertices onto Voronoi edges --- src/microbe_stage/MembraneShapeGenerator.cs | 77 +++++++++++++++------ 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/src/microbe_stage/MembraneShapeGenerator.cs b/src/microbe_stage/MembraneShapeGenerator.cs index 9dc7e95b25f..d5d7b4302b0 100644 --- a/src/microbe_stage/MembraneShapeGenerator.cs +++ b/src/microbe_stage/MembraneShapeGenerator.cs @@ -485,26 +485,6 @@ private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, Membra startingBuffer[i] = closestOrganelle + movement; } - // Multicellular matrix - if (thisCellPosition != null && cellPositions != null) - { - // Make into constant unless you will forget - var multicellularHexDistanceMultiplier = 10f; - - - - for (int i = 0, end = startingBuffer.Count; i < end; ++i) - { - - - var movement = thisCellPosition.Value; - - GD.Print(movement); - - startingBuffer[i] = startingBuffer[i] + movement; - } - } - float circumference = 0.0f; for (int i = 0, end = startingBuffer.Count; i < end; ++i) @@ -576,5 +556,62 @@ private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, Membra vertices2D[i] = point + movement; } + + var average = Vector2.Zero; + + foreach (var vertex in vertices2D) + { + average += vertex; + } + + average /= vertices2D.Count; + + // Multicellular matrix + if (thisCellPosition != null && cellPositions != null) + { + // Make into constant unless you will forget + var multicellularHexDistanceMultiplier = 10f; + + for (int i = 0; i < vertices2D.Count; ++i) + { + var relativeVertex = vertices2D[i] - average; + + float minMultiplier = float.MaxValue; + + foreach (var cellPos in cellPositions) + { + if (cellPos == thisCellPosition) + continue; + + // Coordinates of such a point on the Voronoi edge, that a line from the cell's center to this + // point is perpendicular to the edge. + var edge = (cellPos + thisCellPosition.Value) * 0.5f; + + var relativeEdge = (edge - thisCellPosition.Value) * 2.0f; + + float dotProduct = relativeVertex.Dot(relativeEdge); + + // If the dotproduct is less that this (arbitrary) value, then this edge faces away + // from our vertex, so it doesn't need to be considered + if (dotProduct <= 0.5f) + continue; + + // The vertex pos, when multiplied by this, should be placed at the edge + float multiplier = relativeEdge.LengthSquared() / dotProduct; + + if (multiplier < minMultiplier) + minMultiplier = multiplier; + } + + vertices2D[i] = average + relativeVertex * minMultiplier; + } + + for (int i = 0, end = startingBuffer.Count; i < end; ++i) + { + var movement = thisCellPosition.Value; + + startingBuffer[i] = startingBuffer[i] + movement; + } + } } } From 06d2cdbceb0f4c9c67754e1cacf423eb0681ee2c Mon Sep 17 00:00:00 2001 From: dligr Date: Sat, 16 Nov 2024 20:54:04 +0300 Subject: [PATCH 5/5] Fix wrong projection --- src/microbe_stage/MembraneShapeGenerator.cs | 23 ++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/microbe_stage/MembraneShapeGenerator.cs b/src/microbe_stage/MembraneShapeGenerator.cs index d5d7b4302b0..6087a7c6634 100644 --- a/src/microbe_stage/MembraneShapeGenerator.cs +++ b/src/microbe_stage/MembraneShapeGenerator.cs @@ -570,12 +570,13 @@ private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, Membra if (thisCellPosition != null && cellPositions != null) { // Make into constant unless you will forget - var multicellularHexDistanceMultiplier = 10f; + var verticeDistanceMultiplier = 0.8f; for (int i = 0; i < vertices2D.Count; ++i) { var relativeVertex = vertices2D[i] - average; + bool facesAnEdge = false; float minMultiplier = float.MaxValue; foreach (var cellPos in cellPositions) @@ -591,19 +592,31 @@ private void GenerateMembranePoints(Vector2[] hexPositions, int hexCount, Membra float dotProduct = relativeVertex.Dot(relativeEdge); - // If the dotproduct is less that this (arbitrary) value, then this edge faces away - // from our vertex, so it doesn't need to be considered - if (dotProduct <= 0.5f) + // If the dotproduct is less that this value, then this edge faces a direction different + // than that of the vertex, so it doesn't need to be considered + if (dotProduct <= 0.0f) continue; // The vertex pos, when multiplied by this, should be placed at the edge float multiplier = relativeEdge.LengthSquared() / dotProduct; if (multiplier < minMultiplier) + { minMultiplier = multiplier; + facesAnEdge = true; + } } - vertices2D[i] = average + relativeVertex * minMultiplier; + if (!facesAnEdge) + { + minMultiplier = 1.0f; + } + else if (minMultiplier > 3.0f) + { + minMultiplier = 1.0f; + } + + vertices2D[i] = average + relativeVertex * minMultiplier * verticeDistanceMultiplier; } for (int i = 0, end = startingBuffer.Count; i < end; ++i)