Ich versuche, meine Fluidsimulation zu optimieren, indem ich einen räumlichen Suchalgorithmus implementieren habe, über den ich online gelesen habe, aber ich habe Schwierigkeiten, es mit Unitys Jobsystem zu arbeiten. < /p>
Ich habe es Sehr begrenzte Erfahrungen mit Unitys Jobsystem und räumlichen Suchalgorithmen, daher bin ich mir nicht ganz sicher, was einige Fehler verursacht. Ich bekomme viele Lecks im Konsolenprotokoll < /p>
Ich glaube, ich habe meine Spatialllookup -Klasse mit dem Jobsystem von Unity kompatibel gemacht, aber das Hauptproblem sind die Lecks, die ich nicht finden und beheben kann < /p>
Hier ist der Code für mein Jobsystem und mein Spatialllookup- und Zellklassen < /p>
Klassen: < /p>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.Collections;
using Unity.Mathematics;
public class SpatialLookup
{
public NativeArray cells; // Array of cells for spatial indexing
private float cellSize;
public int gridHeight; // Number of rows
public int gridWidth; // Number of columns
public SpatialLookup(float smoothingRadius, int cameraWidth, int cameraHeight, int maxMoleculesPerCell, Allocator allocator)
{
this.cellSize = smoothingRadius;
this.gridWidth = (int)Math.Ceiling(cameraWidth / cellSize); // Calculated number of columns
this.gridHeight = (int)Math.Ceiling(cameraHeight / cellSize); // Calculated number of rows
cells = new NativeArray(gridWidth * gridHeight, allocator); // Create cells array
// Create a cell for each space in the array
for (int i = 0; i < cells.Length; i++)
{
cells = new Cell(maxMoleculesPerCell, allocator);
}
}
public (int, int) GetCellIndex(float2 position)
{
// Calculate the cell a molecule belongs in based on its position
int cellX = (int)math.clamp(position.x / cellSize, 0, gridWidth - 1);
int cellY = (int)math.clamp(position.y / cellSize, 0, gridHeight - 1);
return (cellX, cellY);
}
public void AddMolecule(int index, float2 position)
{
var (cellX, cellY) = GetCellIndex(position); // Get cell index
if (IsValidCell(cellX, cellY)) // If valid...
{
cells[cellX + cellY * gridWidth].Add(index); // Add molecule index to the cell
}
}
public NativeArray GetNeighbouringMolecules(float2 position, Allocator allocator)
{
NativeList neighbours = new NativeList(allocator);
(int cellX, int cellY) = GetCellIndex(position);
// Loop through the neighbouring cells (3x3 around current cell)
for (int dx = -1; dx = 0 && cellY < gridHeight;
}
public void Dispose()
{
// Dispose resources for each cell so there are no leaks (bad)
for (int i = 0; i < cells.Length; i++)
{
cells.MoleculeIndices.Dispose();
}
if (cells.IsCreated)
cells.Dispose(); // Dispose cell array
}
}
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using System.Collections.Generic;
public struct Cell
{
public NativeArray MoleculeIndices; // Holds indicies of molecules (from molecules list) in this cell
public int Count; // Holds the number of molecules currently in the cell
public Cell(int maxSize, Allocator allocator)
{
MoleculeIndices = new NativeArray(maxSize, allocator);
Count = 0;
}
// woah we learnt this in lesson
public void Add(int index)
{
if (Count < MoleculeIndices.Length)
{
MoleculeIndices[Count++] = index;
}
}
public void Clear()
{
Count = 0; // Clear cell
}
}
< /code>
Jobsystem < /p>
int maxNeighboursPerCell = 1000;
public float smoothingRadius = 2f;
public float restDensity = 1f;
public float pressureMultiplier = 1f;
public float deltaTime;
///
/// Calculates the repulsive force between the molecules
///
public void CalculateForces()
{
SpatialLookup spatialLookup = new SpatialLookup(smoothingRadius, 18, 10, maxNeighboursPerCell, Allocator.Temp);
int moleculeCount = molecules.Count;
if (molecules.Count == 0) { return; }
deltaTime = Time.deltaTime;
// Create the native arrays for the job. I use native arrays to take advantage of the multithreading used in Jobs
NativeArray positions = new(moleculeCount, Allocator.TempJob);
NativeArray velocities = new(moleculeCount, Allocator.TempJob);
NativeArray densities = new(moleculeCount, Allocator.TempJob);
NativeArray pressures = new(moleculeCount, Allocator.TempJob);
NativeArray neighbourMoleculesPos = new(moleculeCount, Allocator.TempJob);
NativeArray neighbourArray = new NativeArray(moleculeCount * maxNeighboursPerCell, Allocator.TempJob); // Or other appropriate allocator
// Copy data to the arrays
for (int i = 0; i < moleculeCount; i++)
{
positions = molecules.position;
velocities = molecules.velocity;
}
GetNeighbourMoleculesJob neighbourJob = new()
{
positions = positions,
neighbouringMoleculesPos = neighbourMoleculesPos,
spatialLookup = spatialLookup,
neighbouringMoleculesInt = neighbourArray,
maxNeighboursPerCell = maxNeighboursPerCell,
};
JobHandle neighbourHandle = neighbourJob.Schedule(moleculeCount, 64);
CalculateDensitiesJob densityJob = new()
{
positions = positions,
velocities = velocities,
densities = densities,
smoothingRadius = smoothingRadius,
deltaTime = deltaTime
};
JobHandle densityHandle = densityJob.Schedule(moleculeCount, 64, neighbourHandle);
CalculatePressureForcesJob pressureJob = new()
{
positions = positions,
velocities = velocities,
densities = densities,
pressures = pressures,
smoothingRadius = smoothingRadius,
restDensity = restDensity,
pressureMultiplier = pressureMultiplier,
deltaTime = deltaTime
};
JobHandle pressureHandle = pressureJob.Schedule(moleculeCount, 64, densityHandle);
pressureHandle.Complete();
for (int i = 0; i < moleculeCount; i++)
{
molecules.ApplyForce(pressures);
}
positions.Dispose();
velocities.Dispose();
densities.Dispose();
pressures.Dispose();
neighbourMoleculesPos.Dispose();
neighbourArray.Dispose();
}
public static float KernelSmoother(float x, float r)
{
if (x >= r) return 0;
float volume = (math.PI * math.pow(r, 4) / 6);
return (r - x) * (r - x) / volume;
}
public static float KernelSmootherGradient(float x, float r)
{
if (x >= r) return 0;
float scale = 12 / (math.pow(r, 4) * math.PI);
return (x - r) * scale;
}
}
[BurstCompile]
struct CalculateDensitiesJob : IJobParallelFor
{
[ReadOnly] public NativeArray positions;
[ReadOnly] public NativeArray velocities;
[WriteOnly] public NativeArray densities;
public float smoothingRadius;
public float deltaTime;
public void Execute(int i)
{
float density = 0f;
const float mass = 1f;
float2 m1Pos = positions + velocities * deltaTime;
for (int j = 0; j < positions.Length; j++)
{
float dst = math.length(positions[j] - m1Pos);
float influence = MoleculeManager.KernelSmoother(dst, smoothingRadius);
density += mass * influence;
}
densities[i] = density;
}
}
[BurstCompile]
struct CalculatePressureForcesJob : IJobParallelFor
{
[ReadOnly] public NativeArray positions;
[ReadOnly] public NativeArray velocities;
[ReadOnly] public NativeArray densities;
public NativeArray pressures;
public float smoothingRadius;
const float mass = 1f;
public float restDensity;
public float pressureMultiplier;
public float deltaTime;
public void Execute(int i)
{
float2 pressureForce = float2.zero;
float2 acceleration = pressures[i] / densities[i]; // Approximate acceleration
float2 predictedVelocity = velocities[i] + acceleration * deltaTime;
float2 m1Pos = positions[i] + predictedVelocity * deltaTime;
for (int j = 0; j < positions.Length; j++)
{
if (i == j) continue;
float dst = math.length(m1Pos - positions[j]);
if (dst == 0) continue;
float2 dir = (m1Pos - positions[j]) / dst;
float slope = MoleculeManager.KernelSmootherGradient(dst, smoothingRadius);
float density = densities[i];
float sharedPressure = CalculateSharedPressure(density, densities[j]);
pressureForce += sharedPressure * mass * slope * dir / density;
}
pressures[i] = pressureForce;
}
private readonly float ConvertDensityToPressure(float density, float restDensity, float pressureMultiplier)
{
float densityOffset = density - restDensity;
float pressure = densityOffset * pressureMultiplier;
return pressure;
}
private readonly float CalculateSharedPressure(float density_i, float density_j)
{
float pressure_i = -ConvertDensityToPressure(density_i, restDensity, pressureMultiplier);
float pressure_j = -ConvertDensityToPressure(density_j, restDensity, pressureMultiplier);
return (pressure_i + pressure_j) / 2;
}
}
[BurstCompile]
struct GetNeighbourMoleculesJob : IJobParallelFor
{
[ReadOnly] public NativeArray positions;
[WriteOnly] public NativeArray neighbouringMoleculesPos;
[ReadOnly] public SpatialLookup spatialLookup;
public NativeArray neighbouringMoleculesInt;
public int maxNeighboursPerCell;
public void Execute(int i)
{
// Get neighbouring molecules for the position
int count = 0; // Track how many neighbouring molecules are found
NativeArray tempNeighbours = spatialLookup.GetNeighbouringMolecules(positions[i], Allocator.Temp);
count = tempNeighbours.Length;
// Store neighbouring molecule positions
for (int j = 0; j < count; j++)
{
neighbouringMoleculesPos[i * maxNeighboursPerCell + j] = positions[tempNeighbours[j]];
}
}
}
< /code>
Wenn es eine bessere Möglichkeit gibt, dies zu handhaben, wäre das sehr geschätzt. Danke!
Implementierung der räumlichen Lookup in der Unity -Fluid -Simulation ⇐ C#
-
- Similar Topics
- Replies
- Views
- Last post