Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Guide to custom placing stuff on spline
#11
If you do want to follow the path of scenario C, then check DeformMeshes, and especially its Action, which definition starts after the following comment: //the action that does the mesh deformation for a specific spot
Please consider leaving a review for Curvy. This will help a lot keeping Curvy relevant in the eyes of the Asset Store algorithm.
Reply
#12
Heya, thanks for the detail responses. Generators added an extra layer of complexity when it came to 2 things.

1 - Binding my own custom Wall behavior data onto them. (Being forced to add component my wall behavior on every refresh on the gameobjects it creates. 

2 - There was a lot of issues with when it refreshes. I found on single frame collision checks not firing off when needed with the curvygenerator. Almost as if there was a 1 frame delay. Also a lot of state changes I needed seemed finicky with its pooling as well. I can do some more tests, but I found it didn't work great when trying to move a spline, updating the wall blocks, and then trying to refresh state or collision data.

Another problem is that its still not fast enough for what I need. I'm getting 30ms when trying to move the splines around with deformation. That's far too low for something realtime.

CurvyGenerator also only allows the choice of picking 3 of the default updates to pick when to update. Which I believe is conflicting with my collision/state code
Reply
#13
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;
}
Reply
#14
(11-23-2023, 02:41 AM)Lupos Wrote: 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.
Just in case you missed it, the Curvy Generator already processes multiple meshes in parallel. More about this further in the post.


(11-23-2023, 02:41 AM)Lupos Wrote: 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
A) If your meshes are predefined, definitely bake a set of all possible deformations for each mesh.
B) I honestly don't know how much gain you can get by using the parallelization of the job system instead of the "regular" parallelization the generator already uses.
C) I am not very experienced with compute shaders. I fear that the cpu/gpu communication associated with compute shaders will nullify any benefit.

(11-23-2023, 02:41 AM)Lupos Wrote: 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.
The spline already have a cache (which you implicitely use by calling the "fast" API methods), no need for the curvy generator to make a cache out of the spline. The spots have more to do with modularity of the curvy generator rather than with performance.
Please consider leaving a review for Curvy. This will help a lot keeping Curvy relevant in the eyes of the Asset Store algorithm.
Reply
#15
Really appreciate the detailed responses!

I've read that a lot of work was put into jobs/burst to allow for the most out of parallelization compared to native C# threading. 
On top of this, there is also an API to generate meshes in parallel.

Code:
Mesh.ApplyAndDisposeWritableMeshData(meshDataArray, mesh);

My idea is to batch all meshes into a IJobParallel and modify and build out the vertices using that above (or similar) method.

The current largest bottle neck is me calling DistanceToTF(), InterpolateAndGetTangentFast(), along with a few others below.

[Image: Ntfm440.png]



I've already noted that it'd prob be a good idea to pre-sort / cache information regarding the sourceMesh vertices to deform faster.
Instead of calculating the GetVertexZDistance for every vertex, I pre-cache all possible unique Z values based on the vertex, and or sort the vertices similar to you by z. Whichever ends up running faster when parallelized. 


I've read the code for DeformMesh and noticed you had ways to use versions of the API that were thread safe and thus could be ran in parallel. 
If I could understand how you did this and what I could possibly do for my own implementation that'd be great.
Getting the DistanceToTF and Interpolate working for jobs is a different matter I still need to work out.


I'll start by testing deforming meshes with jobs, and then deforming them with Mesh.ApplyAndDisposeWritableMeshData to see how good the benefits are. If I can get that working its just a matter of making those functions above to work with it.

As a quick follow up, if in the end caching specific rotations is the best option, how can I go about limiting the angles the spline can create? I noticed it in the curvy generator but haven't yet figured out where it does this.


A) Would you suggest pre-caching all possible rotations offline and storing them as assets?
B) Pre-caching them at game start
C) Caching when generated on use using a mix of parallization + caching


The walls also need to support destruction which I've yet to figure out what method Ill use. They'll likely have pre-cached destruction data needed to deform as well. 
The plan is to have 3 different wall types, but to allow upgrading them which can change the visuals. They also need to support adding multiple sub meshes for other upgrades to the walls.
Reply
#16
(11-23-2023, 10:57 PM)Lupos Wrote: I've read the code for DeformMesh and noticed you had ways to use versions of the API that were thread safe and thus could be ran in parallel.
If I could understand how you did this and what I could possibly do for my own implementation that'd be great.
What API are you referring to? Curvy's or Unity's. What members you want to use that were not thread safe?


(11-23-2023, 10:57 PM)Lupos Wrote: Getting the DistanceToTF and Interpolate working for jobs is a different matter I still need to work out.
They should be thread safe. Have you encountered any error?
Also, you might be able to avoid using DistanceToTF by working with TF values instead of distances. By subdividing your spline into sections with equal TF length instead of equal distance, you will have sections that mght not have the same length, but computation will be faster.

(11-23-2023, 10:57 PM)Lupos Wrote: As a quick follow up, if in the end caching specific rotations is the best option, how can I go about limiting the angles the spline can create? I noticed it in the curvy generator but haven't yet figured out where it does this.

Are you speaking about the Angle Threhold parameter of the Shape Extrusion module? If yes, then it does not limit the angle of a spline, it only limits the angle between successive points when rasterizing a spline.

(11-23-2023, 10:57 PM)Lupos Wrote: A) Would you suggest pre-caching all possible rotations offline and storing them as assets?
B) Pre-caching them at game start
C) Caching when generated on use using a mix of parallization + caching
I would go with A, until the size overhead is provenly problematic.
Please consider leaving a review for Curvy. This will help a lot keeping Curvy relevant in the eyes of the Asset Store algorithm.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Curvy Line Renderer for UI Spline? gekido 3 6 04-04-2024, 12:56 PM
Last Post: _Aka_
  Get position of all control points for a spline gekido 1 6 03-28-2024, 10:08 PM
Last Post: _Aka_
Bug Changing spline connection in inspector causes splines to revert to defaults lacota 3 6 03-18-2024, 07:55 PM
Last Post: _Aka_
  GO can't fit end of the spline GameDeveloperek4123 3 14 03-04-2024, 11:06 AM
Last Post: _Aka_

Forum Jump: