11-23-2023, 02:41 AM
While CurvyGenerator is no doubt optimized, I'm starting to think I'd either need to use the job system on multiple meshes at once on parallel, or use a compute shader.
Would you possibly have ideas on how I can prepare the spline data for something like that?
I already got my own custom curving working but its rather brute force and slow. I'm thinking this is in part why you rasterize the spline and also generate spots.
I assume rasterizing the spline just pre-caches points in a way thats easy for generation, and generating spots pre-allocates the locations (or transform positions) to spawn stuff.
My idea is either
A) lock the spline angles to only support specific angles (like 10) then build a cache dictionary for each mesh of all possible rotation types and grab from there (instead of generating new ones every frame
B) use jobs to deform the meshes in parallel
C) use a compute shader
//Generator
private void GenerateInstances()
{
var depth = _depth = wallCurvePrefab.SourceBounds.size.z;
var splineDistance = _splineDistance = curvySpline.TFToDistance(1f);
var placeableDistance = _placeableDistance = Mathf.Max(splineDistance - depth, 0f);
var totalPlaceableWalls = _placeableWalls = Mathf.CeilToInt(placeableDistance / depth);
var emptySpace = placeableDistance - totalPlaceableWalls;
var padding = _padding = emptySpace / 2f;
var paddingOffset = padding / 2f;
var depthModifiedScale = 1f + padding;
var distanceOnSpline = 1f;
for (var i = 0; i < totalPlaceableWalls; i++)
{
var wall = GetWallFromPool();
if (i == 0 || i == totalPlaceableWalls - 1)
{
var scale = wall.CachedTransform.localScale;
scale.z = depthModifiedScale;
wall.transform.localScale = scale;
}
else
{
wall.transform.localScale = Vector3.one;
}
if (i == 0)
{
distanceOnSpline += paddingOffset;
}
else
{
distanceOnSpline += (depth * wall.ScaleZ + depth * _wallCurveInstances[i - 1].ScaleZ) / 2f;
}
var tf = curvySpline.DistanceToTF(distanceOnSpline);
curvySpline.InterpolateAndGetTangentFast(tf, out var position, out var tangent, Space.World);
wall.transform.SetPositionAndRotation(position, Quaternion.LookRotation(tangent));
if (curveMeshes) wall.CurveMesh(curvySpline, tangent, distanceOnSpline, dontCreateNewMeshIfPossible);
}
}
//CurveDeformation
[Button]
public void CurveMesh(CurvySpline curvySpline, Vector3 mir, float distanceOnSpline,
bool dontCreateNewMeshIfPossible)
{
if (!IsSetup) return;
ResetMesh();
var copiedVertices = new Vector3[_originalVertices.Length];
// var mesh =sourceMesh;
var bounds = SourceBounds;
var depth = bounds.size.z * ScaleZ;
var halfDepth = depth / 2f;
var startingTangent = Vector3.zero;
_isCurved = false;
for (var i = 0; i < _originalVertices.Length; i++)
{
var vertex = _originalVertices[i];
var zDistance = GetVertexZDistance(vertex);
var startTf = curvySpline.DistanceToTF(distanceOnSpline - halfDepth);
var endTf = curvySpline.DistanceToTF(distanceOnSpline + halfDepth);
_startPosition = curvySpline.InterpolateFast(startTf, Space.World);
_endPosition = curvySpline.InterpolateFast(endTf, Space.World);
var tf = curvySpline.DistanceToTF(distanceOnSpline + depth * (zDistance - 0.5f));
curvySpline.InterpolateAndGetTangentFast(tf, out var position, out var tangent, Space.World);
if (i == 0)
{
startingTangent = tangent;
}
_isCurved = startingTangent != tangent;
var normal = -Vector3.Cross(tangent, Vector3.up).normalized;
var newVertexPosition = normal * vertex.x + position + vertex.y * Vector3.up;
newVertexPosition = transform.InverseTransformPoint(newVertexPosition);
copiedVertices[i] = newVertexPosition;
}
if (dontCreateNewMeshIfPossible)
{
if (!_isCurved) return;
}
meshFilter.sharedMesh = CloneMesh(sourceMesh);
var mesh = meshFilter.sharedMesh;
mesh.vertices = copiedVertices;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
private float GetVertexZDistance(Vector3 vertex)
{
var bounds = sourceMesh.bounds;
return (vertex.z - bounds.min.z) / bounds.size.z;
}
Would you possibly have ideas on how I can prepare the spline data for something like that?
I already got my own custom curving working but its rather brute force and slow. I'm thinking this is in part why you rasterize the spline and also generate spots.
I assume rasterizing the spline just pre-caches points in a way thats easy for generation, and generating spots pre-allocates the locations (or transform positions) to spawn stuff.
My idea is either
A) lock the spline angles to only support specific angles (like 10) then build a cache dictionary for each mesh of all possible rotation types and grab from there (instead of generating new ones every frame
B) use jobs to deform the meshes in parallel
C) use a compute shader
//Generator
private void GenerateInstances()
{
var depth = _depth = wallCurvePrefab.SourceBounds.size.z;
var splineDistance = _splineDistance = curvySpline.TFToDistance(1f);
var placeableDistance = _placeableDistance = Mathf.Max(splineDistance - depth, 0f);
var totalPlaceableWalls = _placeableWalls = Mathf.CeilToInt(placeableDistance / depth);
var emptySpace = placeableDistance - totalPlaceableWalls;
var padding = _padding = emptySpace / 2f;
var paddingOffset = padding / 2f;
var depthModifiedScale = 1f + padding;
var distanceOnSpline = 1f;
for (var i = 0; i < totalPlaceableWalls; i++)
{
var wall = GetWallFromPool();
if (i == 0 || i == totalPlaceableWalls - 1)
{
var scale = wall.CachedTransform.localScale;
scale.z = depthModifiedScale;
wall.transform.localScale = scale;
}
else
{
wall.transform.localScale = Vector3.one;
}
if (i == 0)
{
distanceOnSpline += paddingOffset;
}
else
{
distanceOnSpline += (depth * wall.ScaleZ + depth * _wallCurveInstances[i - 1].ScaleZ) / 2f;
}
var tf = curvySpline.DistanceToTF(distanceOnSpline);
curvySpline.InterpolateAndGetTangentFast(tf, out var position, out var tangent, Space.World);
wall.transform.SetPositionAndRotation(position, Quaternion.LookRotation(tangent));
if (curveMeshes) wall.CurveMesh(curvySpline, tangent, distanceOnSpline, dontCreateNewMeshIfPossible);
}
}
//CurveDeformation
[Button]
public void CurveMesh(CurvySpline curvySpline, Vector3 mir, float distanceOnSpline,
bool dontCreateNewMeshIfPossible)
{
if (!IsSetup) return;
ResetMesh();
var copiedVertices = new Vector3[_originalVertices.Length];
// var mesh =sourceMesh;
var bounds = SourceBounds;
var depth = bounds.size.z * ScaleZ;
var halfDepth = depth / 2f;
var startingTangent = Vector3.zero;
_isCurved = false;
for (var i = 0; i < _originalVertices.Length; i++)
{
var vertex = _originalVertices[i];
var zDistance = GetVertexZDistance(vertex);
var startTf = curvySpline.DistanceToTF(distanceOnSpline - halfDepth);
var endTf = curvySpline.DistanceToTF(distanceOnSpline + halfDepth);
_startPosition = curvySpline.InterpolateFast(startTf, Space.World);
_endPosition = curvySpline.InterpolateFast(endTf, Space.World);
var tf = curvySpline.DistanceToTF(distanceOnSpline + depth * (zDistance - 0.5f));
curvySpline.InterpolateAndGetTangentFast(tf, out var position, out var tangent, Space.World);
if (i == 0)
{
startingTangent = tangent;
}
_isCurved = startingTangent != tangent;
var normal = -Vector3.Cross(tangent, Vector3.up).normalized;
var newVertexPosition = normal * vertex.x + position + vertex.y * Vector3.up;
newVertexPosition = transform.InverseTransformPoint(newVertexPosition);
copiedVertices[i] = newVertexPosition;
}
if (dontCreateNewMeshIfPossible)
{
if (!_isCurved) return;
}
meshFilter.sharedMesh = CloneMesh(sourceMesh);
var mesh = meshFilter.sharedMesh;
mesh.vertices = copiedVertices;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
private float GetVertexZDistance(Vector3 vertex)
{
var bounds = sourceMesh.bounds;
return (vertex.z - bounds.min.z) / bounds.size.z;
}