Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Components not refreshing
#1
I'm trying to use Curvy to read in data, generate meshes from the data, and save just the meshes out to the scene (since they will be static and I don't want the overhead of Curvy), but I'm running into an issue with the components not updating which is preventing me from being able to save out the mesh. I've created a test script (below) to figure out the process, and the debug statements print 0, for the first one giving the length of the spline, and null, for the second one which should be the saved mesh.  I was reading through prior posts in the forum and took the advice to set auto refresh to false and force a refresh before I want to use the results of a component, but that is clearly not working.  I thought it might be an editor specific bug, so I tried running the same script at start and got the same results.  Why is this not working to generate my mesh in a way that I can save it out?  When I go to the scene view afterwards, I can see that everything has been created as expected, it just seems to be happening after I try to access it within the script.

Code:
using UnityEngine;
using FluffyUnderware.Curvy;
using FluffyUnderware.Curvy.Generator.Modules;
using FluffyUnderware.Curvy.Generator;
using FluffyUnderware.Curvy.Shapes;

public class CurvyTest : MonoBehaviour
{
    [ContextMenu("Test")]
    public void Test() {
        // Create the generator and required build components
        CurvyGenerator generator = CurvyGenerator.Create();
        generator.AutoRefresh = false;
        InputSplinePath wirePath = generator.AddModule<InputSplinePath>();
        InputSplinePath crossPath = generator.AddModule<InputSplinePath>();
        BuildShapeExtrusion buildShapeExtrusion = generator.AddModule<BuildShapeExtrusion>();
        BuildVolumeMesh buildVolumeMesh = generator.AddModule<BuildVolumeMesh>();
        CreateMesh createMesh = generator.AddModule<CreateMesh>();

        // Create inputs to generator components

        // Create the wire spline
        CurvySpline wireSpline = CurvySpline.Create();
        CurvySplineSegment controlPoint1 = wireSpline.Add();
        controlPoint1.gameObject.transform.localPosition = new Vector3(0, 0, 0);
        CurvySplineSegment controlPoint2 = wireSpline.Add();
        controlPoint2.gameObject.transform.localPosition = new Vector3(0, 1, 0);
        CurvySplineSegment controlPoint3 = wireSpline.Add();
        controlPoint3.gameObject.transform.localPosition = new Vector3(1, 1, 0);
        CurvySplineSegment controlPoint4 = wireSpline.Add();
        controlPoint4.gameObject.transform.localPosition = new Vector3(1, 2, 0);
        CurvySplineSegment controlPoint5 = wireSpline.Add();
        controlPoint5.gameObject.transform.localPosition = new Vector3(1, 2, 1);

        // Create the circle cross section
        CurvySpline crossSpline = CurvySpline.Create();
        CSCircle circle = crossSpline.gameObject.AddComponent(typeof(CSCircle)) as CSCircle;
        circle.Radius = 0.005f;
        circle.Count = 10;
        crossSpline.Refresh();
        Debug.Log(crossSpline.Length);
        crossSpline.MaxPointsPerUnit = 10 / crossSpline.Length;
        circle.Refresh();

        // Link the splines to the shape extruder
        wirePath.Spline = wireSpline;
        crossPath.Spline = crossSpline;
        CGModuleInputSlot pathInput = buildShapeExtrusion.GetInputSlot("Path");
        CGModuleInputSlot crossInput = buildShapeExtrusion.GetInputSlot("Cross");
        CGModuleOutputSlot pathOutput = wirePath.GetOutputSlot("Path");
        CGModuleOutputSlot crossOutput = crossPath.GetOutputSlot("Path");
        pathInput.LinkTo(pathOutput);
        crossInput.LinkTo(crossOutput);

        // Set shape extruder parameters
        buildShapeExtrusion.Resolution = 100;
        buildShapeExtrusion.CrossResolution = 100;

        // Link the mesh and mesh generator
        CGModuleInputSlot volumeInput = buildVolumeMesh.GetInputSlot("Volume");
        CGModuleOutputSlot volumeOutput = buildShapeExtrusion.GetOutputSlot("Volume");
        volumeInput.LinkTo(volumeOutput);
        CGModuleInputSlot meshInput = createMesh.GetInputSlot("VMesh");
        CGModuleOutputSlot meshOutput = buildVolumeMesh.GetOutputSlot("VMesh");
        meshInput.LinkTo(meshOutput);

        // Save the mesh and destroy the components used to make it
        generator.Refresh(true);
        GameObject mesh = createMesh.SaveToScene(null);
        Debug.Log(mesh);
    }

    public void Start() {
        Test();
    }
}
Reply
#2
Hi,
Is a call to wireSpline.Refresh() after finishing setting it's CPs solving the issue?
Please consider leaving a review for Curvy. This will help a lot keeping Curvy relevant in the eyes of the Asset Store algorithm.
Reply
#3
I added that refresh in as well and it still isn't working, although interestingly that seems to be the only one that isn't necessary.  I printed out the length of the spline before and after refreshing it, and it was the correct length even before the refresh.  The two that aren't updating are crossSpline and createMesh as far as I can tell.
Reply
#4
I will take a look at this tomorrow. Will keep you updated
Please consider leaving a review for Curvy. This will help a lot keeping Curvy relevant in the eyes of the Asset Store algorithm.
Reply
#5
About crossSpline's length being 0, the cause was that circle.Refresh(); needed to be called before. Here is the block of code after my modifications
Code:
// Create the circle cross section
       CurvySpline crossSpline = CurvySpline.Create();
       CSCircle circle = crossSpline.gameObject.AddComponent(typeof(CSCircle)) as CSCircle;
       circle.Radius = 1.005f;
       circle.Count = 10;
       circle.Refresh();
       crossSpline.Refresh();
       Debug.Log(crossSpline.Length);
       crossSpline.MaxPointsPerUnit = 10 / crossSpline.Length;
       crossSpline.Refresh();
       Debug.Log(crossSpline.MaxPointsPerUnit);
The exported mesh is still null though. I am still investigating
Please consider leaving a review for Curvy. This will help a lot keeping Curvy relevant in the eyes of the Asset Store algorithm.
Reply
#6
The second issue was because of a lack to the generator's Initialize method. So here the whole modified code
Code:
using UnityEngine;
using FluffyUnderware.Curvy;
using FluffyUnderware.Curvy.Generator.Modules;
using FluffyUnderware.Curvy.Generator;
using FluffyUnderware.Curvy.Shapes;

public class CurvyTest : MonoBehaviour
{
   [ContextMenu("Test")]
   public void Test()
   {
       // Create the generator and required build components
       CurvyGenerator generator = CurvyGenerator.Create();
       generator.AutoRefresh = false;
       InputSplinePath wirePath = generator.AddModule<InputSplinePath>();
       InputSplinePath crossPath = generator.AddModule<InputSplinePath>();
       BuildShapeExtrusion buildShapeExtrusion = generator.AddModule<BuildShapeExtrusion>();
       BuildVolumeMesh buildVolumeMesh = generator.AddModule<BuildVolumeMesh>();
       CreateMesh createMesh = generator.AddModule<CreateMesh>();

       // Create inputs to generator components

       // Create the wire spline
       CurvySpline wireSpline = CurvySpline.Create();
       CurvySplineSegment controlPoint1 = wireSpline.Add();
       controlPoint1.gameObject.transform.localPosition = new Vector3(0, 0, 0);
       CurvySplineSegment controlPoint2 = wireSpline.Add();
       controlPoint2.gameObject.transform.localPosition = new Vector3(0, 1, 0);
       CurvySplineSegment controlPoint3 = wireSpline.Add();
       controlPoint3.gameObject.transform.localPosition = new Vector3(1, 1, 0);
       CurvySplineSegment controlPoint4 = wireSpline.Add();
       controlPoint4.gameObject.transform.localPosition = new Vector3(1, 2, 0);
       CurvySplineSegment controlPoint5 = wireSpline.Add();
       controlPoint5.gameObject.transform.localPosition = new Vector3(1, 2, 1);

       // Create the circle cross section
       CurvySpline crossSpline = CurvySpline.Create();
       CSCircle circle = crossSpline.gameObject.AddComponent(typeof(CSCircle)) as CSCircle;
       circle.Radius = 0.005f;
       circle.Count = 10;
       circle.Refresh();
       crossSpline.Refresh();
       crossSpline.MaxPointsPerUnit = 10 / crossSpline.Length;
       crossSpline.Refresh();

       // Link the splines to the shape extruder
       wirePath.Spline = wireSpline;
       crossPath.Spline = crossSpline;
       CGModuleInputSlot pathInput = buildShapeExtrusion.GetInputSlot("Path");
       CGModuleInputSlot crossInput = buildShapeExtrusion.GetInputSlot("Cross");
       CGModuleOutputSlot pathOutput = wirePath.GetOutputSlot("Path");
       CGModuleOutputSlot crossOutput = crossPath.GetOutputSlot("Path");
       pathInput.LinkTo(pathOutput);
       crossInput.LinkTo(crossOutput);

       // Set shape extruder parameters
       buildShapeExtrusion.Resolution = 100;
       buildShapeExtrusion.CrossResolution = 100;

       // Link the mesh and mesh generator
       CGModuleInputSlot volumeInput = buildVolumeMesh.GetInputSlot("Volume");
       CGModuleOutputSlot volumeOutput = buildShapeExtrusion.GetOutputSlot("Volume");
       volumeInput.LinkTo(volumeOutput);
       CGModuleInputSlot meshInput = createMesh.GetInputSlot("VMesh");
       CGModuleOutputSlot meshOutput = buildVolumeMesh.GetOutputSlot("VMesh");
       meshInput.LinkTo(meshOutput);

       // Save the mesh and destroy the components used to make it
       generator.Initialize();
       GameObject mesh = createMesh.SaveToScene(null);
       Debug.Log(mesh);
   }

   public void Start()
   {
       Test();
   }
}
Please consider leaving a review for Curvy. This will help a lot keeping Curvy relevant in the eyes of the Asset Store algorithm.
Reply
#7
I hate to revive a pretty old thread, but I'm having the same issue (let me know if I should create a new thread about this). My code is as follows

Code:
public void GenerateColliderVolume() {
    GameObject volumeCollider = new GameObject("Volume Collider");
    volumeCollider.transform.parent = this.gameObject.transform;
    CurvyGenerator generator = volumeCollider.AddComponent<CurvyGenerator>();
    generator.ShowDebug = true;
    generator.AutoRefresh = true;

    InputSplinePath inputSplinePath = generator.AddModule<InputSplinePath>();
    InputSplineShape inputSplineShape = generator.AddModule<InputSplineShape>();
    BuildShapeExtrusion shapeExtrusion = generator.AddModule<BuildShapeExtrusion>();
    BuildVolumeMesh volumeMesh = generator.AddModule<BuildVolumeMesh>();
    CreateMesh createMesh = generator.AddModule<CreateMesh>();

    inputSplinePath.Spline = mySpline; // this is just the Curvy Spline I've already created elsewhere
    inputSplinePath.Path.LinkTo(shapeExtrusion.InPath);

    CSCircle circle = inputSplineShape.gameObject.AddComponent<CSCircle>();
    circle.Count = 4;
    circle.Radius = 1;

    inputSplineShape.Shape = circle.Spline;
    inputSplineShape.OutShape.LinkTo(shapeExtrusion.InCross);
    shapeExtrusion.OutVolume.LinkTo(volumeMesh.InVolume);
    volumeMesh.OutVMesh.LinkTo(createMesh.InVMeshArray);
   
    generator.Initialize(true);
    GameObject finalCollider = createMesh.SaveToScene(null);
    Debug.Log(finalCollider); // it's null
  }

I trigger this function from a custom script attached to a game object with a Curvy Spline component that exposes a button in the inspector (so not at runtime, just in the editor itself).
Code:
[CustomEditor(typeof(MyScript))]
public class MyScriptEditor : Editor {
  public override void OnInspectorGUI() {
    MyScript myScript = (MyScript)target;

    DrawDefaultInspector();

    if (GUILayout.Button("Generate Collider Volume")) {
      myScript.GenerateColliderVolume();
    }
  }
}

By digging into the source Curvy code it looks like SaveToScene is returning null due to createMesh not having any manageable resources. I apologize if this goes against the rules, but I'd just like to help point as far as I got:

in CreateMesh.cs
Code:
public GameObject SaveToScene(Transform parent = null) {
      // SOME INTERNAL CODE
      if (managedResources.Count == 0) {
        Debug.Log("There's your problem");
        return null;
      }
      // SOME MORE INTERNAL CODE
}

I've also tried replacing my code with the previous suggested snippets and ran into the same problem (using manual refreshes and all that). I'm using Unity 2020.2.0f1 and Curvy 7.1.4. I appreciate any advice that can be given.
Reply
#8
Hi
Here is a version of MyScript that has not the issue:

Code:
using FluffyUnderware.Curvy;
using FluffyUnderware.Curvy.Generator;
using FluffyUnderware.Curvy.Generator.Modules;
using FluffyUnderware.Curvy.Shapes;
using UnityEngine;

public class MyScript : MonoBehaviour
{
    public CurvySpline mySpline;
    private CreateMesh createMeshModule;

    public void GenerateColliderVolume()
    {
        GameObject volumeCollider = new GameObject("Volume Collider");
        volumeCollider.transform.parent = this.gameObject.transform;
        CurvyGenerator generator = volumeCollider.AddComponent<CurvyGenerator>();
        generator.ShowDebug = true;
        generator.AutoRefresh = true;

        InputSplinePath inputSplinePath = generator.AddModule<InputSplinePath>();
        InputSplineShape inputSplineShape = generator.AddModule<InputSplineShape>();
        BuildShapeExtrusion shapeExtrusion = generator.AddModule<BuildShapeExtrusion>();
        BuildVolumeMesh volumeMesh = generator.AddModule<BuildVolumeMesh>();
        createMeshModule = generator.AddModule<CreateMesh>();

        inputSplinePath.Spline = mySpline; // this is just the Curvy Spline I've already created elsewhere
        inputSplinePath.Path.LinkTo(shapeExtrusion.InPath);

        CSCircle circle = inputSplineShape.gameObject.AddComponent<CSCircle>();
        circle.Count = 4;
        circle.Radius = 1;
        circle.Refresh();

        inputSplineShape.Shape = circle.Spline;
        inputSplineShape.OutShape.LinkTo(shapeExtrusion.InCross);
        shapeExtrusion.OutVolume.LinkTo(volumeMesh.InVolume);
        volumeMesh.OutVMesh.LinkTo(createMeshModule.InVMeshArray);

        generator.Initialize(true);
        generator.OnRefresh.AddListener(OnGeneratorRefreshed);
    }

    private void OnGeneratorRefreshed(CurvyCGEventArgs aguments)
    {
        aguments.Generator.OnRefresh.RemoveListener(OnGeneratorRefreshed);
        GameObject finalCollider = createMeshModule.SaveToScene(null);
        Debug.Log(finalCollider); // it's null
    }
}


There are two changes:
- calling Refresh() on circle
- saving the mesh in an OnRefresh event listener

I kept the generator.Initialize, even if it is not necessary in this case.

Sorry for the complications. The generator's current initialization process makes it span on possibly multiple frames, so a straight forward code like yours does not always work. Making the generators initialize in one frame is a task in my todo list, but I have to admit that it isn't very high on the list for now, due to the amount of work it involves, and the comparatively low benefits compared to other items on that list. But it should eventually be done.

Thanks for your patience, and have a nice day
Please consider leaving a review for Curvy. This will help a lot keeping Curvy relevant in the eyes of the Asset Store algorithm.
Reply
#9
Thank you very much! The listener approach worked like a charm (And they seem pretty useful. I'll have to look into them more).
Reply
#10
You are welcome. If and when you feel like it, please leave a review for the asset, that helps a lot.
Have a nice day
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
  Adding a point, then refreshing the mesh results in wrong mesh for one frame Jellybit 2 7,093 02-17-2014, 05:29 PM
Last Post: Jellybit

Forum Jump: