Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Custom Spots Filter Generator Module
#1
Hey,

Trying to write a custom generator node that takes in a set of spots, applies a filter function, and then outputs the new modified list.

In my case, I am filtering based on the rotation to prevent poles on my rollercoaster from connecting to inverted pieces of track.

It seemed to work well when I was using a small test track, but scaling it up to larger tracks I am getting crazy results where its adding hundreds of spots that should not have even been in the original input list? Probably I'm doing something wrong in the node.

Heres my code:

Code:
using UnityEngine;
using System.Collections;
using FluffyUnderware.DevTools;
using System.Collections.Generic;

namespace FluffyUnderware.Curvy.Generator.Modules
{
    [ModuleInfo("Custom/Spot Angle Filter",ModuleName="Spot Angle Filter", Description="Filter spots based on their rotation")]
    public class SpotAngleFilter : CGModule
    {
       
        [HideInInspector]
        [InputSlotInfo(typeof(CGSpots), Name = "Spots", DisplayName = "Spots")]
        public CGModuleInputSlot InData = new CGModuleInputSlot();

        [HideInInspector]
        [OutputSlotInfo(typeof(CGSpots), Name = "Spots", DisplayName = "Spots")]
        public CGModuleOutputSlot OutData = new CGModuleOutputSlot();

        #region ### Serialized Fields ###
        #endregion
        #region ### Public Properties ###

        // Gets whether the module is properly configured i.e. has everything needed to work like intended
        public override bool IsConfigured
        {
            get
            {
                return base.IsConfigured;
            }
        }

        // Gets whether the module and all its dependencies are fully initialized
        public override bool IsInitialized
        {
            get
            {
                return base.IsInitialized;
            }
        }
       
        #endregion

        #region ### Unity Callbacks ###
        /*! \cond UNITY */
        protected override void OnEnable()
        {
            base.OnEnable();
            //Properties.MinWidth = 250;
            //Properties.LabelWidth = 80;
        }

#if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();
        }
#endif

        public override void Reset()
        {
            base.Reset();
        }

        /*! \endcond */
        #endregion

        #region ### Module Overrides ###

        public override void Refresh()
        {
            base.Refresh();
            /* Add Module processing code in here */

            CGSpots spots = InData.GetData<CGSpots>();
            List<CGSpot> outSpots = new List<CGSpot>();

            foreach (CGSpot spot in spots.Spots.Array)
            {
                Vector3 angle = spot.Rotation * Vector3.forward;
                float dot = Vector3.Dot(Vector3.forward, angle);
                if (dot > 0)
                {
                    outSpots.Add(spot);
                    //outSpots.Add(new CGSpot(outSpots.Count, spot.Position, spot.Rotation, spot.Scale)); // doesn't work..
                }

            }

            OutData.ClearData();
            OutData.SetData(new CGSpots(outSpots));

        }

        // Called when a module's state changes (Link added/removed, Active toggles etc..)
        //public override void OnStateChange()
        //{
        //    base.OnStateChange();
        //}

        // Called after a module was copied to a template
        //public override void OnTemplateCreated()
        //{
        //    base.OnTemplateCreated();
        //}

        //Called in multiple situations to clear all the outputs generated by this module. One example is when you click on the "Clear output" button in the Curvy Generator's toolbar
        public override bool DeleteAllOutputManagedResources()
        {
            OutData.ClearData();

            return base.DeleteAllOutputManagedResources();
        }

        #endregion
    }
}
Reply
#2
Hi
I am working on it. Should be able to answer in the next hours.
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
#3
Hey Aka, Thanks for your reply. I ended up fixing it myself - it was my bad use of the SubArray<> class where I was using spots.Spots.Array.Count instead of spots.Spots.Count - it was accessing the unused, but allocated elements of the array

For anyone who may want it in the future, here is the fixed code. I note that I had to change the original volume spots generation to use full rotation so the spots are generated at the correct angle for this filter to check their angle, then this module compares the angle to the horizon, filters spots based on that, and then sets the spots to default rotation so they always face the ground.

Code:
using UnityEngine;
using System.Collections;
using FluffyUnderware.DevTools;
using System.Collections.Generic;

namespace FluffyUnderware.Curvy.Generator.Modules
{
    [ModuleInfo("Custom/Spot Angle Filter",ModuleName="Spot Angle Filter", Description="Filter spots based on their rotation")]
    public class SpotAngleFilter : CGModule
    {
       
        [HideInInspector]
        [InputSlotInfo(typeof(CGSpots), Name = "Spots", DisplayName = "Spots")]
        public CGModuleInputSlot InData = new CGModuleInputSlot();

        [HideInInspector]
        [OutputSlotInfo(typeof(CGSpots), Name = "Spots", DisplayName = "Spots")]
        public CGModuleOutputSlot OutData = new CGModuleOutputSlot();

        #region ### Serialized Fields ###
        #endregion
        #region ### Public Properties ###

        // Gets whether the module is properly configured i.e. has everything needed to work like intended
        public override bool IsConfigured
        {
            get
            {
                return base.IsConfigured;
            }
        }

        // Gets whether the module and all its dependencies are fully initialized
        public override bool IsInitialized
        {
            get
            {
                return base.IsInitialized;
            }
        }
       
        #endregion

        #region ### Unity Callbacks ###
        /*! \cond UNITY */
        protected override void OnEnable()
        {
            base.OnEnable();
            //Properties.MinWidth = 250;
            //Properties.LabelWidth = 80;
        }

#if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();
        }
#endif

        public override void Reset()
        {
            base.Reset();
        }

        /*! \endcond */
        #endregion

        #region ### Module Overrides ###

        public override void Refresh()
        {
            base.Refresh();
            /* Add Module processing code in here */

            CGSpots spots = InData.GetData<CGSpots>();
            List<CGSpot> outSpots = new List<CGSpot>();

            for (int i=0; i<spots.Spots.Count; i++)
            {
                CGSpot spot = spots.Spots.Array[i];
                Vector3 angle = spot.Rotation * Vector3.up;

                float dot = Vector3.Dot(Vector3.up, angle);
                if (dot > 0)
                {
                    spot.Rotation = Quaternion.identity;
                    outSpots.Add(spot);
                }
            }
           
            OutData.SetData(new CGSpots(outSpots));
        }

        // Called when a module's state changes (Link added/removed, Active toggles etc..)
        //public override void OnStateChange()
        //{
        //    base.OnStateChange();
        //}

        // Called after a module was copied to a template
        //public override void OnTemplateCreated()
        //{
        //    base.OnTemplateCreated();
        //}

        //Called in multiple situations to clear all the outputs generated by this module. One example is when you click on the "Clear output" button in the Curvy Generator's toolbar
        //public override bool DeleteAllOutputManagedResources()
        //{
        //    return base.DeleteAllOutputManagedResources();
        //}

        #endregion
    }
}
Reply
#4
Hi

Thanks for sharing the solution.

Do you have any thoughts or suggestions about the SubArray struct?
To avoid such issues, I could hide SubArray.Array to the public, while providing an indexer:

Code:
        /// <summary>
        ///  Returns the array element at the given index
        /// </summary>
        public T this[int index]
        {
            get => Array[index];
            set => Array[index] = value;
        }

The issue with this being that SubArray, and the whole array pooling thing, are heavily orientated towards performance. So I prefer to keep the SubArray.Array public to allow for better performance. But I see that it can lead to confusion. I purposely named SubArray.Count that way, instead of Length, to avoid accidentally using the Length of SubArray.Array instead of the one of SubArray.
Anything thoughts?

PS: I will provide that indexer in the next update
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
Exclamation Extending Curvy Generator for Advanced Lofting - Feasibility Check amutp 2 4 03-27-2024, 07:25 AM
Last Post: amutp
  8.8.0 is live, and it improves Curvy Generator greatly _Aka_ 0 7 03-27-2024, 03:23 AM
Last Post: _Aka_
  Generating GO only on CPs in Generator GameDeveloperek4123 1 6 03-04-2024, 11:06 AM
Last Post: _Aka_
Question Volume Spots inter group distance Sacryn 1 3 02-27-2024, 04:08 PM
Last Post: _Aka_

Forum Jump: