Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

QuickLod - Fast asynchronous lod system

Discussion in 'Assets and Asset Store' started by chillersanim, Mar 29, 2014.

  1. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    Hello @acaussin

    I've looked into the issue.
    When importing QuickLod, Unity 5.6 seems to get rid of the input settings sometimes (tested the import a few times).
    So maybe it is a good idea to reimport QuickLod to your solution.

    If that doesn't fix your problem, then please see the attached screenshot of the correct input settings.
    CorrectMainDemoSceneInput.PNG

    Greetings
    Chillersanim
     
  2. acaussin

    acaussin

    Joined:
    Apr 3, 2017
    Posts:
    4
    Yes I tried with an empty project, same problem.

    Just saw you last post with your screen I will try that, thanks !
     
  3. acaussin

    acaussin

    Joined:
    Apr 3, 2017
    Posts:
    4
    Every time I tried to re-import, Unity crash, so I entered Input settings manually and the camera works now.

    For the GroupSwitchDemo I have another Exception, but I can use it anyway :
    ArgumentException: Getting control 1's position in a group with only 1 controls when doing Repaint
    Aborting
    UnityEngine.GUILayoutGroup.GetNext () (at C:/buildslave/unity/build/Runtime/IMGUI/Managed/LayoutGroup.cs:115) .......
    UnityEngine.GUILayout.Label (System.String text, UnityEngine.GUIStyle style, UnityEngine.GUILayoutOption[] options) (at C:/buildslave/unity/build/Runtime/IMGUI/Managed/GUILayout.cs:15)
    QLDemo.FrameRate.DoMyWindow (Int32 windowID) (at Assets/QuickLod/DemoScene/Scripts/FrameRate.cs:181)

    Thanks
     
  4. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    Thank you for reporting this.

    It sounds like another breaking change from Unity.
    Will take a look what could cause this.

    Do you get an exception message when Unity crashes?
    Is there something in the log?

    Greetings
    Chillersanim
     
  5. acaussin

    acaussin

    Joined:
    Apr 3, 2017
    Posts:
    4
    I had this error.log by re-importing QuickLod (empty project with only QuickLod)
    not sure it is usefull

    Unity Editor [version: Unity 5.6.1f1_2860b30f0b54]
    Unity.exe caused an Access Violation (0xc0000005)
    in module Unity.exe at 0033:00000000.
    Error occurred at 2017-05-22_145340.
    C:\Program Files\Unity\Editor\Unity.exe, run by acaussin.
    10% memory in use.
    65435 MB physical memory [58404 MB free].
    75163 MB paging file [66844 MB free].
    134217728 MB user address space [134214912 MB free].
    Write to location 00000000 caused an access violation.

    Context:
    RDI: 0x0808c670 RSI: 0x005fcf60 RAX: 0x427ec858
    RBX: 0x07de5130 RCX: 0x0808c670 RDX: 0x4270e938
    RIP: 0x00000000 RBP: 0x00000000 SegCs: 0x00000033
    EFlags: 0x00010202 RSP: 0x005fcca8 SegSs: 0x0000002b
    R8: 0x005fcc40 R9: 0xda82ee23 R10: 0x00000000
    R11: 0x005fcca0 R12: 0x005fcf60 R13: 0x627b8b60
    R14: 0x00000001 R15: 0x00000000

    Bytes at CS:EIP:
    ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??

    Stack:
    0x005fcca8: 405413fa 00000001 07de5130 00000000 ..T@....0Q......
    0x005fccb8: 07de5130 00000000 005fcf60 00000000 0Q......`._.....
    0x005fccc8: 005fccf8 00000000 005fcf60 00000000 .._.....`._.....
    0x005fccd8: 08034ca0 00000000 43c61640 00000001 .L......@..C....
    0x005fcce8: 40908da9 00000001 fffffffe ffffffff ...@............
    0x005fccf8: 07de0420 00000000 07de04a0 00000000 ...............
    0x005fcd08: 07de04b0 00000000 fffffffe ffffffff ................
    0x005fcd18: 9bea647c 0000d3eb 00000001 00000000 |d..............
    0x005fcd28: 405439b1 00000001 000025dc 00000001 .9T@.....%......
    0x005fcd38: 627b8b68 00000000 00000384 00000000 h.{b............
    0x005fcd48: 00000384 00000000 43cec520 00000001 ........ ..C....
    0x005fcd58: 40779415 00000001 ffffd462 00000000 ..w@....b.......
    0x005fcd68: 00000020 00000000 627b8b60 00000000 .......`.{b....
    0x005fcd78: 627ba780 00000000 627bacb0 00000000 ..{b......{b....
    0x005fcd88: 414718cd 00000001 fffffffe ffffffff ..GA............
    0x005fcd98: 43b23620 00000001 046dc360 00000000 6.C....`.m.....
    0x005fcda8: 005fd080 00000000 429914c0 00000001 .._........B....
    0x005fcdb8: 42991508 00000001 00000000 00000000 ...B............
    0x005fcdc8: 005fd000 00000000 00000000 00000000 .._.............
    0x005fcdd8: 42991508 00000001 00000000 00000000 ...B............
    0x005fcde8: fffffffe ffffffff 9bea653c 0000d3eb ........<e......
    0x005fcdf8: 005fce60 00000000 005fd1b8 00000000 `._......._.....
    0x005fce08: 40c62cd7 00000001 005fd1b8 00000000 .,.@......_.....
    0x005fce18: 005fd000 00000000 9bea656c 0000d3eb .._.....le......
     
  6. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    Hello @acaussin

    I can confirm that reimporting QuickLod leads to a crash.
    I've sent a bugreport to Unity and am now investigating what could cause this crash.

    Will come back to you when I know more.

    Greetings
    Chillersanim
     
    hopeful likes this.
  7. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    @acaussing

    I got an E-Mail from Unity QA.
    They were able to reproduce the crash, their developers are currently looking into it.

    In the meantime.
    For me, Unity only crashes when I have a QuickLod releated scene open while reimporting.
    So creating a new scene before importing should prevent the crash.

    Edit:
    The releated issue tracker can be found here:
    https://issuetracker.unity3d.com/is...ash-when-reimporting-assets-from-assets-store

    Greetings
    Chillersanim
     
    hopeful likes this.
  8. N00MKRAD

    N00MKRAD

    Joined:
    Dec 31, 2013
    Posts:
    210
    Any chance to get your website back up?
     
  9. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    Hello @N00MKRAD

    I'm terribly sorry for this late reply. I was (and still am) very bussy with my examens and new work situation.

    I appologise for the fact, that the website is down.
    The webpage was hosted on a friends website, which is now down as well.
    I'm trying to recover my part of the website and bring it back up.

    In the mean time, if you have any questions to how something works, please read the documentation provided with the asset or ask me.
    I'll try to reply as fast as I can.

    Thank you.
    Chillersanim
     
    twobob likes this.
  10. N00MKRAD

    N00MKRAD

    Joined:
    Dec 31, 2013
    Posts:
    210
    No problem.

    I actually bought your asset in the meantime, currently only using it for lights, but it's working really well, especially since my world is infinite and generated on the fly.
     
    twobob likes this.
  11. StarFluke

    StarFluke

    Joined:
    Jan 19, 2013
    Posts:
    39
    Hello,

    I really enjoyed using your LOD solution during development of my infinite universe project's phase 3: the planet generator. You can see a video of QLOD handling the trees around my planet at http//:www.starfluke.com .
    Is there any plan to update QLOD for 2018.1?

    Thanks,
    Game Daddy
     
    twobob likes this.
  12. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    VERSION HISTORY

    Version history
    *** Version 1.6 (08.03.2015) ***

    New features:
    • Component: GsGroupSwitch.cs for hiding object groups depending on trigger inputs
    • Component: GsDistanceTrigger.cs as a distance based trigger
    • Component: GsCollisionTrigger.cs as a collision based trigger
    • Component: LodObjectChildSwitch.cs which enables and disables all child objects depending on the distance
    • Feature: The GroupSwitch feature has been implemented, it’s especially usefull to cull interior objects and remove them from all calculations.
    • Feature: Added a GameObject option: “Quick Lod/Add to group switch” to add the selection directly to a groupswitch in the scene
    • Feature: Added a GameObject option: “Quick Lod/Remove from group switch” to remove the selection directly from all group switches in the scene.
    • Interface: IGsTriggerBase.cs as for all triggers. Implement it and directly use your component as a trigger.
    • Struct: IntVector3.cs which works as a normal vector but with integer values
    • Struct: IntBounds3.cs which stores a bounding box with integer values
    New files:
    • LodObjectChildSwitch.cs
    • Containers/IntVector3.cs
    • Containers/IntBounds3.cs
    • GroupSwitch/GsGroupSwitch.cs
    • GroupSwitch/GsCollisionTrigger.cs
    • GroupSwitch/GsDistanceTrigger.cs
    • GroupSwitch/IGsTriggerBase.cs
    • Editor/GroupSwitch/GroupSwitchSelector.cs
    • Editor/GroupSwitch/GsEditor.cs
    • Editor/GroupSwitch/GsHierarchyHelper.cs
    • Editor/GroupSwitch/GsTriggerSelector.cs
    • Editor/GizmosModels/QLRangeSphere.obj
    • Editor/Materials/QLManagedObjects.mat
    • Editor/Materials/QLRangeColor.mat
    • Editor/Materials/QLRectangle.png
    • Editor/Materials/QLRectangleActive.mat
    • Editor/Materials/QLRectangleInactive.mat
    • Editor/Materials/QLRimHighlightShader.shader
    Modified:
    • Behaviour: Improved the visual feedback for ranges, now using a mesh with material instead of Gizmos
    • Behaviour: Changed the way managed objects are highlighted to make them much easier to find
    • Behaviour: Custom editor scripts now store the state of all expanders
    • Code: In class LodObjectBase added method GetOptimalLevelDistances(float, int):float[] which calculates optimal cull distances
    • Code: In class LodManagerBase added virtual property OptimalSourceBorder:float which returns an optimal border with for lod sources to use
    • Code: In class LodManagerBase added virtual method HandleSourceMovement(LodSource, Vector3):void which handles the source movement
    • Code: In class LodManagerCubic added method WorldToCellPosition(Vector3):IntVector3 to get the cell index in which the given point lies
    • Code: In class LodManagerCubic added method CellToWorldPosition(IntVector3):Vector3 to get the center point of the given cell position
    • Code: In class LodManagerCubic added method RecalculateGridSpace():void to recalculate the grid space depending on the scene
    • Code: In class LodManagerCubic added method RecalculateCellSize():void to recalculate the cell size depending on the grid size
    • Performance: Improved the algorithm to determine which cells are active, optimised the time complexity from O(n) to O(1)
    • Performance: Improved the underlying data structure for storing objects, improving the access time a lot
    • Performance: Improved many small algorithms
    • Performance: Changed the way existing cells are deactivated, now they are deactivated over multiple frames, removing short spikes
    • Performance: The chunk levels are now only recalculated when a lod source moves from one cell to another
    • Performance: Removed the Update method from the LodObjectBase class which improves the performance a lot!
    • Refactoring: Modified the methods RecalculateDistances() in LodObjectReplacement and LodObjectMesh to use the new base method.
    • Refactoring: Replaced Linq queries with code in time critical code parts for better performance.
    • Refactoring: Replaced some lists with sets to improve lockup performance
    • Refactoring: Modified some code in order to speed up the garbage collection.
    • Refactoring: Changed the way lod objects are managed to allow them to get registered and deregistered when the lod level changes
    • Refactoring: Changed the way lod objects check for position changes and improved the performance a lot.
    • Refactoring: Cells now store which camera is relevant for them, which reduces the impact of multiple cameras
    • Refactoring: The amount of priority levels is now adjustable with the constant: LodManagerBase.PriorityLevelAmount:int
    Fixed bugs:
    • Fixed bug that prevented the LodObjectMesh to correctly setup the lods when the given mesh had no number
    • Fixed bug that crashed unity when a new LodManagerCubic was added to a scene without QuickLod components
    • Fixed bug that prevented the LodManager to be exclusive when the game was started or stoped with a disabled LodManager
    • Fixed editor bug that prevented LodSources to work in the game view when they were disabled in the editor settings
    • Fixed editor bug that caused lod objects not to register to the LodManagerCubic when resizing the grid
    • Fixed editor bug which lead to unpredicted results when a LodManager was reset
    • Fixed rare bug that could prevent cells to be removed when an object was removed from them
    *** Version 1.5 (16.01.2015) ***
    New features:
    • Component: LodObjectSkinnedMesh.cs for skinned mesh renderer
    • Feature: Added support for multiple scene views in the editor
    • Feature: The class LodObjectBase.cs now offers some events for extended notifications
    • Feature: The class LodManagerCubic.cs can now handle cell sizes for each axis individual
    • Feature: The class LodManagerCubic.cs can now highlight all managed lod objects
    • Feature: The class LodSource.cs now also has a local distance multiplier.
    • Feature: The class LodSource.cs can now observe camera components
    • Feature: The class LodSource.cs can now update the ViewAngle:float and LocalDistanceMultiplier:float depending on the FoV
    • Feature: The class LodSource.cs now uses a custom border width when using the falloff mode [HardWithBorder]
    New files:
    • LodObjectSkinnedMesh.cs
    • Containers/GridColumn.cs
    • Containers/GridRow.cs
    • Containers/GridCell.cs
    • Editor/QLEditorTools
    • Editor/Materials/QLManagedObjects.mat
    Modified:
    • Behaviour: Improved general performance by caching values and optimizing algorithms
    • Behaviour: Automatic recalculating of the grid space now also considers the size of the owner
    • Behaviour: Changed the algorithm to draw the grid. It should be clearer to use now.
    • Behaviour: Optimized the way the LodSource handles distance multipliers
    • Behaviour: Optimized the way the grid is being managed.
    • Behaviour: In class LodManagerBase, the property Sources now only contains the lod sources which should be used (now reflects editor settings)
    • Code: In class LodObjectBase added method GetLodAmount():int which returns the amount of lod levels that are setup
    • Code: In class LodManagerBase added virtual method NextStep():void which can be used as update notification for game and editor
    • Code: In class LodManagerBase added static method UpdateLodObjectDistance(LodObjectBase):void which recalculates the distance for the given lod object
    • Code: In class LodManagerBase added static method UpdateLodObjectDistance(LodObjectBase, IEnumerable):void, same as other, but with custom lod source collection
    • Code: In class LodManagerCubic added property CellSize:Vector3 which is new used to define the cell size
    • Code: In class LodSource.cs added property LocalDistanceMultiplier:bool
    • Code: In class LodSource.cs added property UseGlobalDistanceMultiplier:bool
    • Code: In class LodSource.cs added property ObserveCamera:bool
    • Code: In class LodSource.cs added property ObservedCameraComponent:Camera (readonly)
    • Code: In class LodSource.cs added property UpdateAngleMarginFromCamera:bool
    • Code: In class LodSource.cs added property UpdateLocalMultiplierWithFoV:bool
    • Code: In class LodSource.cs added property DefaultCameraFoV:float
    • Code: In class LodSource.cs added property BorderWidth:float
    • Code: Grid components now store their parent for faster access
    • Refactoring: Rewriten most API documentation with a loot of examples
    • Refactoring: In class LodManagerBase changed property ViewportObject:GameObject to ViewportObjects:GameObjects[] (Changed type and name)
    • Refactoring: In class LodManagerBase changed property ViewportSources:LodSource to ViewportObjects:LodSources[] (Changed type and name)
    • Refactoring: In class LodSource.cs added method GetDistanceToCell(Vector3, float) which replaces GetDistanceToChunk(Vector3, float)
    • Refactoring: Replaced class ChunkXReference.cs with GridColumn.cs
    • Refactoring: Replaced class ChunkYReference.cs with GridRow.cs
    • Refactoring: Replaced class ChunkZReference.cs with GridCell.cs
    Obsolete:
    • File: Containers/ChunkXReference.cs
    • File: Containers/ChunkYReference.cs
    • File: Containers/ChunkZReference.cs
    • Method: In class LodSource.cs the method GetDistanceToChunk(Vector3, float) has been replaced by the method GetDistanceToCell(Vector3, float)
    • Property: In class LodManagerCubic.cs the property ChunkSize:float has been replaced by the property CellSize:Vector3
    Fixed bugs:
    • Fixed stuttering when using multiple scene views
    • Fixed bug where lod objects wouldn’t deregister from cell properly when moving
    • Fixed bug where empty cells could cause unwanted overhead
    *** Version 1.4 (21.06.2014) ***
    New features:
    • Compatibility: Now compatible with Unity 4.1 and above (Previously only 4.4+)
    • Compatibility: Added compatibility with InstantOC, you can now switch the active lod system with the property “ActiveLodSystem” when InstantOC is present
    • Feature: Chunks in front of the camera can now be priorized over chunks behind the camera
    • Feature: Chunks behind the camera can now be ignored
    Modified:
    • Behaviour: Reduced the sensitivity that causes a chunk prioritiy recalculation in the class “LodSource”
    • Behaviour: When using the “LodObjectMesh”, the meshRenderer gets deactivated when no mesh is defined -> Prevents render overhead
    • Behaviour: Changed the method call of “FindObjectsOfType()” to “FindObjectsOfType(typeof(Class))” for compatibility reasons
    • Behaviour: Better performance through caching values.
    • Code: Added properties “UseOtherLodSystem”, “ActiveLodSystem” and “ActivateLightsOnSwitchToQuickLod” to the class “LodManagerBase”
    • Code: Added methods “ActivateQuickLod()” and “DeactivateQuickLod()” to the class “LodObjectBase”
    • Code: Added some code in the method “GetDistanceToChunk()” in the class “LodSource” that handles field of view
    • Code: Added property “UseViewAngle” in the class “LodSource”, to activate and deactivate the chunk prioritizing algorithmus
    • Code: Added property “Falloff” in the class “LodSource”, to choose between three different falloff modes
    • Code: Added property “IgnoreHiddenChunks” in the class “LodSource”, to define if chunks outside the angle margin should be deactivated
    • Code: Added property “AngleMargin” in the class “LodSource”, to define the angle at which the prioritizing algorithmus starts working
    • Help: Updated the help section for all components with the new functions
    • Help: Updated the manual_en.pdf with the new functions
    • Refactoring: Removed some deprecated code in the “TestGUI” class
    Fixed bugs:
    • Fixed a formula in “TestPlacement.cs” that caused the placed objects to be missplaced in certain cases
    • Fixed minor bug that some settings were not directly visible in the editor
    *** Version 1.3 (01.06.2014) ***
    New features:
    • Editor: New menu item to select the lod manager [Edit/Quick Lod/Select Lod Manager]
    • Editor: New menu item to prepare the scene for lightmapping [Edit/Quick Lod/Prepare For Lightmapping]
    • Feature: When creating a custom LodObject, you can now use the “LodObjectAddFields” attribute to display fields in the inspector
    • Feature: LodObjectMesh can now automaticly assign lod levels in the editor (Depending on the mesh name, containing folder and the containing object)
    • Feature: LodObjects now automaticly generate lod levels when first added to a game object
    Modified:
    • Behaviour: Removed the warnings on the actions “Generate All” and “Optimize Distances” and implemented undo for them
    • Behaviour: Changed the minimum chunk size to 5
    • Behaviour: The maximum amount of chunks per axis is now set to 100, previously unlimited (Prevents memory overflow and lag)
    • Behaviour: The example scene now includes prefabs for the LodObjectMesh component
    • Refactoring: The property “Local Hide Mode” in the class “LodObjectReplacement” is now obsolete as the functionality of the “MeshRenderer” type is replaced by the “LodObjectMesh” class
    • Refactoring: The property “Default Hide Mode” in the class “LodManagerBase” is now obsolete as it is no longer used
    • Refactoring: Removed the “Default Hide Mode” from the LodManagerCubic inspector (“LMCEditor.cs”)
    • Refactoring: The file “OverwriteGlobalAttribute.cs” has been renamed to “LodObjectAddFieldAttribute.cs”
    • Refactoring: Changed the namespace of the demo scripts so that they don’t use a custom category in the component list (new path: Components/QLDemo/)
    Obsolete:
    • File: Attributes/OverwriteGlobalAttribute.cs
    Fixed bugs:
    • Fixed small bug, that prevented the LodObject to deregister when the option “Exclude from manager” was activated
    • Fixed a rare bug, where a LodObject could be registered multiple times
      You can now properly change the “Current Lod Level” on a lod object when no lod manager is present and the “Exclude From Manager” is deactivated
    *** Version 1.2 (20.04.2014) ***
    New features:
    • Component: A new lod object component has been added, which replaces the mesh depending on the distance
    • Editor: Added some automatisations for easier setup
      Autogenerate lod levels for lod objects
      • Recalculate the optimal distances for lod objects (beta)
      • Recalculate the grid space for the lod manager
      • Recalculate the chunk size for the lod manager
      • Recalculate the optimal max update distance for lod sources
    • Editor: Added a help field to all components with some info how to use the component
    • Feature: LodObjects can now be excluded from the manager
    • Feature: Made a difference between absolute and relative distance for upcoming features
    • Feature: Added an option to the lod manager to ignore objects outside the grid
    New files:
    • LodObjectMesh.cs
    • LodStructureGameobject.cs
    • LodStructureMesh.cs
    • LodHelperAttribute.cs
    • OverwriteGlobalAttribute.cs
    • LodLevelListDown.png
    • LodLevelListUp.png
    Modified:
    • Help: Updated the “Manual_EN.pdf” with new informations
    • Refactoring: Changed “LOREditor.cs” to “LOBEditor.cs” and made it usable for both lodObject components
    • Refactoring: Restructured some base classes
    • Refactoring: Moved the lod object registering and deregistering to “LodObjectBase.cs”
    • Refactoring: Optimized some code for better performance
    • Refactoring: Made “LodStructure.cs” generic
    • Refactoring: Reworked the “TestScene.unity”
    Fixed bugs:
    • Fixed a rare bug where the objects were registered on a wrong way when Unity was restarted
    • Fixed a bug that sometimes occured when the lod object was reverted to prefab settings
    • Fixed a bug which could happen when the local hide mode was used
    *** Version 1.1 (07.04.2014) ***
    • Initial Release
     
    Willbkool_FPCS likes this.
  13. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    API http://chillersanim.bplaced.net:80/html/Introduction_00.htm

    DOCS PAGE

    Documents and links


    All documents and external links for QuickLod can be found on this page.
    If you think that some information are missing, or when you didn’t find any information to a specific problem, please ask on the forum or contact me: chillersanim@gmail.com

    Documents
    QuickLod Manual (PDF)
    Contains basic information about QuickLod.
    It covers the following chapters:

    • Setup guide
    • Component description
    • Tips and tricks
    How autosetup works (PFD)
    Describes how the automatic lod level setup in QuickLod works.
    It covers the following themes:

    • Autosetup for LodObjectReplacement
    • Autosetup for LodObjectMesh & LodObjectSkinnedMesh
    • Naming conventions
    • Supported file structures
    Links
    Forum
    If you have general questions which other people could also have, then please ask them here.
    It’s also the main source for updates and news concerning QuickLod.

    Asset Store
    If you want to buy QuickLod, you can do that on the asset store.
    Once you’ve bought QuickLod, you’ll get all updates for free.

    API Documentation
    If you want to work with the source code of QuickLod, this API documentation may be useful.
    It contains descriptions to all components, remarks to certain features and example codes for common use cases.
     

    Attached Files:

  14. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    QuickLod Features

    This page shows and explains most features.
    Click on a feature to get more information to it.

    Basic features
    • Ready to use lod system
      Implementing QuickLod is as easy as adding a few components. You don’t need to write a single line of code, everything is already available.
    • Unlimited lod levels
      You can define as many LOD levels as you want. Whether you use two levels for a brick or 10 levels for a building is up to you.
    • Multiple cameras
      Split screen games, surveillance camera, MMO… QuickLod supports an infinite amount of cameras at once.
    • Multiple LOD object types
      QuickLod offers for various situations specialized Lod Objects. This helps you to get the most out of your game.
      • Child replacement (Similar to LodGroups)
      • Mesh replacement
      • Skinned mesh replacement
      • Child activator/deactivator
      See here for more information. <- this link was irrecoverable Sorry

    • Component management
      Not only meshes can be managed, but also single components. Want a particle system with reduced quality at a certain distance? Want to deactivate a lamp when it’s far away? It’s all possible with QuickLod
    • Group Switch
      When distance based deactivation is not enough, you can always use the group switch. This gives you even finer control over when objects are deactivated.
    • Triggers
      They are used to control the group switches.
      • Collision trigger
      • Distance trigger
    • Mobile friendly
      The performance usage is highly optimized. Additionally you can define how much performance QuickLod can use. This and more makes QuickLod a good choice for mobile 3D games
    • Individual distance multipliers
      There’s a global distance multiplier, but additionally each camera has its own distance multiplier. This allows you to zoom a single camera or lower the view distance of another one.
    • Automated FoV support
      You can restrict QuickLod to only manage objects in front of a camera instead of all objects around it. This can be automated by observing the camera component.
    • Automated zoom support
      When you zoom the camera by changing the FoV, QuickLod can automatically adjust the local distance multiplier to keep the quality the same.
    • InstantOC compatible
      You can use QuickLod together with InstantOC.
      This feature is currently in beta phase and not fully functional
    • Constant time complexity → O(1)
      It doesn’t matter how many objects are in your scene. QuickLod has a constant time complexity, which means that it won’t use more CPU resources when you add more objects. This is especially useful when you want to create big and/or detail rich scenes.
    Editor features
    • Works in editor
      QuickLod works in the editor as it works in the game. This allows you to try all settings directly without starting the game. It also helps with lagging editors duo to large scenes.
    • Multiple viewports
      When working in the editor, you can use as many scene views as you want.
    • Lod level preview
      You can preview all LOD levels directly with a slider.
    • Custom inspector editor for all components
      All components come with a custom inspector to simplify the work process
    • Gizmos
      Want to see what QuickLod does? Do you have problems with the setup or does something not work? With over 10 editor gizmos, you can see exactly what happens.
    • Automatic lod level setup
      The LOD levels can be generated automatically. When you add a component, it will try to set itself up.
    • Automatic distance optimization
      The LOD level distances and camera view distances can be automatically optimized.
    • Light map support
      QuickLod can prepare your scene for light mapping. Although it just activates the high quality LOD level, this can already save a lot of time.
    • Checks for valid input
      All components check for valid input. This prevents long searching for bugs caused by invalid user inputs.
    Developer features
    • Full source code included
      QuickLod comes with the full source code. There are no dll’s and you can read and edit everything.
    • Built as framework
      QuickLod is built as a framework. You can expand it by reusing existing classes and helper methods.
    • Base classes available
      Most components derive from base classes. Those base classes do most of the work. You can create new components which inherit from those base classes and they will be compatible with all other QuickLod components.
    • Fully commented source code
      All classes, fields, properties, methods, constructors, enums, constants, etc. are fully commented. Code parts are commented so that you can study the code more easily.
    • With ReSharper and StyleCop formatted code
      Using tools such as ReSharper and StyleCop, the code has a standardized format.
    • Full API documentation with code examples
      The whole API is documented with remarks and code examples. The API documentation can be found here.
    • Ready to use events
      There are multiple events you can use. This can be used to react to distance changes and LOD level changes immediately.


    The link for the extra component-lod-object was irrecoverable - Sorry
     
  15. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Component Pages


    The component pages offer detailed information about the different components used in QuickLod.

    Lod Manager
    The main component of QuickLod. It manages and optimizes the calculation process and makes QuickLod what it is, a blazing fast lod system.

    Lod Object
    The actual lod object. It manages the different lod levels based on the distance to the nearest camera.
    There are multiple different Lod Objects available, all specialized for different tasks.

    Lod Source
    The distance calculator. It’s used for every camera, but can be used on any game object, not just cameras.
    It’s used for all distance calculations and offers additional features like camera observation.

    Group Switch (WIP)
    A special component, which activates and deactivates all managed objects based on trigger inputs.
    It can be used to cull all objects inside a space when they aren’t used.

    Triggers (WIP)
    The triggers used by the group switch.
    They check for certain conditions and based on the result set the trigger state to true or false.
    You can think of them as switches.

    Observers (WIP)
    An observer which handles the observation of a lod object.
    It handles the registering and deregistering of all events.
    Useful when you want to extend a lod object.
     
    Last edited: May 3, 2018
  16. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Component: Lod Manager


    The Lod Manager is the main component in QuickLod.
    It optimizes the calculation process handles changes made to the scene and works as bridge between the Lod Objects and Lod Sources.

    There can be only one Lod Manager component in the scene.
    If you want to change the active Lod Manager, you need to destroy the old one and create the new one.
    If you want to select the current Lod Manager, you can do so by using the menu option:
    Edit/Quick Lod/Select QuickLod Manager

    All Lod Managers derive from the LodManagerBase.cs class, which already handles:

    • Registering and deregistering of all Lod Objects and Lod Sources
    • Handling of Lod Object position changes
    • Handling of Lod Source position changes
    • System management when InstantOC is available
    • Management of editor cameras for all viewports
    Lod Manager Cubic
    There is currently only one Lod Manager available, the LodManagerCubic.
    This Lod Manager only updates a defined amount of objects per frame instead of all objects at once.
    This frees the CPU for other tasks, and thanks to many optimizations, you won’t see much of this delayed update.


    General settings
    You can define a global distance multiplier.
    This distance multiplier is applied to all distances before calculating the lod level.
    This can be used as a quality setting, or to export to different devises without changing all distances manually.

    You can also define the amount of objects you want to update per frame.
    This number is not always the exact amount of objects which are recalculated, as QuickLod won’t calculate more objects than necessary, and every active cell gets at least one update per frame.

    Grid

    The LodManagerCubic uses a 3D grid to optimize the calculation process. That allows it to only recalculate objects which are inside the update range of any Lod Source.

    In this simplified example, you see a grid with a Lod Source in the centre (Red dot).
    The Lod Source has an update range which is indicated by the black circle.
    Only cells inside the update range will be updated.

    That reduces the amount of objects which need to be recalculated drastically.

    Grid boundary and cell size
    The grid is defined by a boundary, which again is defined by a start point and a size.
    The cells of the grid can be scaled on all axes, but to prevent a memory overflow, you can’t have more than 500 cells per axis.

    • Cell update interval
      You can define the interval in which the active cells and priority levels will be recalculated. This interval is in frames between each recalculation.
      A recalculation will only occur, when any lod source has actually moved and changed the cell in which it was.
    • Max cell deactivations
      After recalculating the newly active cells, the LodManagerCubic will deactivate the content of all cells no longer active. When the camera is moving fast and many cells need to be deactivated, this can cause a frame rate drop as many objects need to be deactivated at once.
      To prevent that, the LodManagerCubic stores which cells should be deactivated and only deactivates a bunch of them per frame.
      How many cells are deactivated per frame can be controlled with the “Max cell deactivations” value.

    • Clamp objects to grid
      As the grid has a limited size, it can happen that a lod object leaves its boundary.
      This shouldn’t happen normally, but you can still define how QuickLod should react in this case.
      With the option “Clamp objects to grid”, you can tell QuickLod to clamp all objects outside the boundary to the nearest cell. If you choose to deactivate this option, all objects outside the boundary will simply be ignored.
    Priority levels
    Also the Lod Manager uses priority levels for the cells.
    By default, there are 4 priority levels, but this amount can be changed.
    A cell which is nearby a Lod Source gets a lower priority number than a cell which is far away.
    The lower the priority number, the more objects are updated per frame.
    A cell with the priority number 0 gets the most updates.

    This results in optimized update behaviour, as objects nearby the camera get updated more often than objects further away.
    This is useful, as it reduces the visible impact of the delayed update a lot.

    No delay
    If you want to deactivate the delayed update and just update all objects at once, then you only need to set the “Updates per frame” to a really high number.
    The Lod Manager won’t update more objects than available.
    The delayed mode is recommended for performance reasons.



    Editor settings
    There are a bunch of editor settings, which can be used to find the cause of a problem, see how QuickLod works and optimize settings.


    • Use sources
      Define whether the user created Lod Sources should be used in the editor or not.
      When activated, all user created Lod Sources will be used in the editor, else not.
      This option only works in edit mode.
    • Use viewport
      Define whether the scene views should be used as Lod Sources or not.
      When activated, all scene views will be used as Lod Sources, else not.
      This option only works in edit mode.
    • Viewport multiplier
      The distance multiplier to use for all viewport sources.
      This has only an effect when “Use viewport” is activated.
    • Viewport update distance
      The update distance for all viewport Lod Sources.
      Using the “Auto” option gives the best result.
      This has only an effect when “Use viewport” is activated.
    Editor visualizations
    Editor visualizations are limited to the LodManagerCubic.
    Custom made Lod Managers can implement their own visualizations.


    • Draw used cells
      Draws all cells which at least have one Lod Object inside.
    • Draw cell leve
      Draws the cell level for all used cells.
      The cell level is represented by a colour, where green stays for a low priority number and red stays for high priority number.
      Be aware that a low priority number has actually a higher priority.
    • Draw grid
      Draws the outline of the grid with the cell size visible.
    • Draw object cell
      Draws for all selected Lod Objects the cell in which they are.
    • Draw managed objects
      Redraws all managed Lod Objects with a specific material.
      This can be used to find objects which aren’t managed.
    • Managed objects material
      The material used to highlight the managed objects.
      Default: QLManagedObjects
    • Draw when deselected
      Also draw the visuals when the Lod Manager is not selected.
    • Draw in debug
      Also draw the visuals when in play mode.
     
    Last edited: May 3, 2018
  17. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Component: Lod Object


    The Lod Objects are simple components which define what happens when the distance changes.
    They wait until the Lod Manager gives them a distance, then they calculate the new lod level.
    With that lod level, they decide what to do.

    A Lod Object can do whatever it wants to do with the given distance information and the lod level.
    It can change the mesh in the mesh filter, activate and deactivate child objects, adjust a variable in a component, or whatever you want it to do.

    All Lod Objects derive from the LodObjectBase.cs class.
    This class already handles many basic features such as registering, deregistering, position change handling, optimal distance calculation and editor visualizations.

    Workflow
    The default work process of a Lod Object is the following:

    1. Register to the Lod Manager
    2. Wait for next distance calculation
    3. Calculate new lod level
    4. Does something with the new lod level (and go back to step 3)
    5. When no longer needed, deregister from Lod Manager
    Distance overload

    A Lod Object receives two distances; the real distance and a relative distance.

    The real distance is just the distance in world units.
    The relative distance is the real distance multiplied with all distance multipliers.
    Both distances are measured to the nearest camera.

    Be aware that if you use two cameras with different local distance multipliers, it can happen that the relative distance is taken from one, while the real distance is taken from the other.

    Example:
    Imagine the red dots are cameras and the rings indicate a relative distance of 1 meter.
    For the relative distance camera A is thus the nearest one.
    But camera B has the shorter real distance.

    Moving objects
    QuickLod optimizes objects which don’t move.
    Unmoving objects should be marked as static in order to prevent unnecessary calculations.
    Moving objects must be marked as static as position changes need to be considered.

    When an object is only rotated or scaled but not moved, it can be marked as static too.

    Override lod level
    If you want to set the lod level manually, you can do so by activating the option “Exclude from manager”. This will unlock the lod level slider and you can define the desired lod level. A lod level smaller than 0 is equal to invisible or deactivated.

    If you want to override the lod level by code, you must enable the option too, as else the Lod Manager will reset the lod level.

    Available Lod Objects
    There are currently 4 different Lod Object types implemented.

    Lod Object Replacement
    This Lod Object is similar to the LodGroups from Unity. It enables and disables referenced game objects depending on the lod level.

    The most common way to use this Lod Object is to create an empty and drop all lod level objects as children on it. Then add a LodObjectReplacement component to the parent object.

    In this example taken from the hierarchy window, the StreetLamp_01 is the parent object, while the three Lod_x objects represent the different lod level objects.

    Those objects need to be referenced in the LodObjectReplacement.
    Only the object of the current lod level is active, all other levels will be deactivated.

    You should choose this Lod Object when:

    • You need to use multiple game objects for the different lod levels
    • You want to replace components over different lod levels
    • You want to replace whole object hierarchies
    Lod Object Mesh
    This Lod Object needs a mesh filter component on the corresponding game object.
    It replaces the mesh in the mesh filter depending on the lod level.

    Try to use this Lod Object whenever possible as it only needs a single game object and thus uses less memory than the LodObjectReplacement.

    You just need to reference the meshes it should use.
    If you want to use the Autosetup feature, you might want to take a look into the document How Autosetup Works (PDF)

    You should choose this Lod Object when:

    • You want to replace the mesh in the mesh filter
    • Whenever possible
    Lod Object Skinned Mesh
    It’s equal to the LodObjectMesh, but used for animated meshes (skinned meshes).
    It uses the SkinnedMeshRenderer instead of the MeshFilter.

    Lod Object Child Switch
    This Lod Object activates and deactivates all child objects based on the distance.

    This can be used to activate and deactivate many objects at once instead of giving them all a separate Lod Object.
    This is normally needed for patches of details like grass, trash or other small objects.

    It can also be used to deactivate many objects at a given distance to remove them from physics calculation or other resource heavy tasks.

    This component is a simple version of the GroupSwitch, but is limited to distance based triggering and can only manage child objects.
    If you want more control over which objects should be managed and when, then you might want to take a look at the GroupSwitch component.

    You should choose this Lod Object when:

    • You want to activate/deactivate all child objects at once
    Choose the correct Lod Object
    If you want to choose the correct Lod Object for a given game object, you can ask the following questions and stop at the first one you can answer with yes:

    Do I want to replace components or multiple hierarchies?
    Use the LodObjectReplacement

    Do I have multiple skinned meshes?
    Use the LodObjectSkinnedMesh

    Do I have multiple unskinned meshes?
    Use the LodObjectMesh

    Do I simply want to activate/deactivate all children based on the distance?
    Use the LodObjectChildSwitch

    Do I want to do something fancy that doesn’t work with any given Lod Object?
    Create a new Lod Object or contact me: chillersanim@gmail.com
     
  18. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Component: Lod Source


    All distance calculations are done by the Lod Source.
    It acts as a centre point from which the distances to all Lod Objects are calculated.
    It’s normally used by cameras, but can be added to any game object which should act as a centre point.

    There is no limit of Lod Sources you can use at once.
    But similar to lights, each lod source adds another calculation pass for the distance calculation.
    It is thus recommended to not to use tons of Lod Sources at once.

    Performance
    The performance impact of a Lod Source depends on the Lod Manager used.
    In general it’s a good idea not to use more Lod Sources than necessary.

    With the LodManagerCubic, each Lod Source only affects cells in its update range.
    Cells outside the update range are ignored by this Lod Source.
    It is thus crucial to choose a good max update distance, see below.

    Max Update Distance
    The max update distance represents the range in which a Lod Source can update Lod Objects.

    As the max update distance has a big impact on performance, it’s critical to choose the optimal value.
    The shorter this distance, the better the performance.
    You should take some cases into account to choose the best distance value.

    • Largest LOD level distance
      The update distance doesn’t need to be larger than the largest used lod level distance of any Lod Object.
      Using the automated distance calculation takes all Lod Objects in the scene into account and calculates the optimal distance for the scene.
    • Camera view distance
      When the camera view distance is smaller than the largest LOD level distance, you should take the view distance instead.
    View angle
    In order to reduce the amount of chunks to calculate, you can restrict a Lod Source to a certain view angle. With this restriction, all chunks outside this view angle will be ignored.
    This reduces the amount of chunks drastically and improves the update interval for all active chunks a lot.

    As a downside, you can have objects popping (sudden appearance of objects) into the screen when you turn around the camera, so this restriction should not be used on fast rotating cameras.
    This option is perfect for stationary cameras or cameras with a small field of view.

    There are three view angle modes available.
    The following summary should help you to choose the best one for your use case.

    Hard
    Uses only the view angle and ignores everything outside it.
    This can lead to many visual artefacts and should only be used when this doesn’t matter (surveillance camera, reflection camera, etc.)

    • Fastest mode
    • Best culling behaviour
    • Causes more popping
    • Can lead to artefacts at the screen border
    Hard with border
    Uses the view angle and adds a border to it.
    This prevents visual artefacts when the camera doesn’t rotate to fast.
    It should be used when the artefacts from the hard mode are obtrusive.

    • Good culling behaviour
    • Prevents most popping
    • Slow
    • Not usable for fast rotating cameras
    Smooth
    This uses a gradual falloff for cells outside the view angle.
    It has a poor cell culling behaviour but still better than nothing.
    On the other hand it is usable for fast rotating cameras.

    • Usable for fast rotating cameras
    • There’s usually no popping
    • Slow
    • Bad culling behaviour
    Camera observation
    Some settings in the Lod Source depend on settings in the camera.
    When those settings change, the Lod Source settings should also change.

    When you know that the camera settings can change, you should activate the camera observation.
    This allows the Lod Source to react to any changes made to the camera so that you don’t need to worry about it.

    When the Lod Source observes the camera, you can tell it which settings it should manage.
    Managed settings cannot be changed directly, as they depend on the camera settings

    Local distance multiplier
    Depends on the field of view from the camera.
    You define a default field of view for which the local distance multiplier is 1.
    When the field of view in the camera changes, the local distance multiplier is automatically updated.

    View angle
    The view angle depends on the field of view and the aspect ratio of the camera.


    Annd that's the ballgame.
    Hope it helps you recover your old website content man ;)
     
  19. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Last edited: May 3, 2018
  20. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    @twobob
    Wow, thank you very much for that.
    I need to find some time to get a new Webpage up and running; in the meantime your work will be the replacement.
    Currently I don't have much time duo to my studies and job, but I'll try to make some time.

    Also I'm sorry that I didn't put any time into updating QuickLod, my apologies.
    I'll do a test with the newest Unity version and then start thinking what to do next.
    Please let me know when there are any bugs, problems, urgent needs, so that I know where to start.
    Thank you!

    Greetings
    Chillersanim
     
    twobob likes this.
  21. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    I had the time, skills, and inclination. You needed it doing. Happy to help.
    No pressure on updates man. (EDIT: Maybe wait till ECS stabilizes?)

    Enjoy your ife
     
  22. imaewyn

    imaewyn

    Joined:
    Apr 23, 2016
    Posts:
    207
    @chillersan @twobob where Can I find working manual?
     
  23. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
  24. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    Alternatively, a manual is included in the asset as pdf. However that is more of a getting started than a complete manual.
     
  25. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    A short update from my side.
    I'm currently working on a new algorithm and datastructure that should improve performance and allow multiple update distance groups.
    That would allow the system to use short update distances for small objects (forks, cups, ...) while using large update distances for large objects (trees, houses, ...).
    Duo to work and study, I can't give you an eta.
     
    twobob and hopeful like this.
  26. imaewyn

    imaewyn

    Joined:
    Apr 23, 2016
    Posts:
    207
  27. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058
    Hmm you are right. I have removed it. Have to reference the one in the package or ask chillersanim for one
     
  28. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    Hello all.
    I wanted to give you some heads-up on my progress.

    Progress
    I found some time to work on QuickLod and implemented the new datastructure.
    Now I am doing some performance comparisons with the old data structure, it's looking good so far.
    Afterwards, I plan to implement the new LodManager, do some tests and then release the next version.

    Website
    The QuickLod website used to be a part of a friends website.
    This is no longer possible, so now I have to find out how to host my own website.
    Because I don't have much experience with web-stuff, this will probably take some time.
    In the meantime, if anything is unclear, please use the documentation provided in the asset or by @twobob or write here. :)

    The new data structure
    I'm just going to talk a little about the new data structure, this might get a little technical.
    The new data structure is a modified version of a range tree.
    Size
    It covers an initially small area of 3x3x3 units.
    As soon as an object is added, it grows its size until the object is included, the growth is exponential.
    Alternatively, if objects get removed, the size is reduced if possible.
    Tree
    In order to effectively manage the objects, it partitions the area into nodes. Each node covers an area in the world space and contains all objects within that space.
    Each node is either a leaf containing the objects, or a sub-tree containing more nodes.
    If an object is added to a leaf, and the amount of objects exceeds a maximum, that leaf is subdivided into multiple child nodes and becomes a sub-tree.
    On the other hand, if an object is removed and the amount of objects in a sub-tree falls bellow a minimum, the sub-tree is collapsed into a leaf again.
    Partitioning
    When subdividing a leaf, it is cut along each world axis by a fixed amount of cuts.
    By doing that, it creates a sub-tree, consisting of (#cuts + 1)^3 child nodes.
    #Cuts is currently 2, but any value larger than 1 would work.
    Memory
    In order to make use of memory caching, the tree is kept flat, this is achieved by having many objects in a single leaf, and by having many child nodes in a single (sub-)tree.
    Also nodes use a node pool in order to prevent memory garbage.

    tl;dr
    I finished implementing the new data structure, it's a self regulating spatial tree.
    Now I'm going to implement new features and then release a new version.
    Also I'm working on a new website, but that can take some time.

    upload_2018-7-17_13-41-1.png
    Initial tree

    upload_2018-7-17_13-42-14.png
    Growth after adding some items

    upload_2018-7-17_13-44-19.png
    Tree with many objects and some sub-trees (Red is the bounding box, green level 1, yellow level 2)

    Greetings
    Chillersanim
     
    twobob and hopeful like this.
  29. Liminal-Ridges

    Liminal-Ridges

    Joined:
    Oct 21, 2015
    Posts:
    255
    Hello and congratulations for your product. I currently have an asset that gets a mesh as input and produces a group of lods. What more does this asset do?
     
  30. julianr

    julianr

    Joined:
    Jun 5, 2014
    Posts:
    1,210
    If you need any help with setting up the website, feel free to contact me.
     
    hopeful likes this.
  31. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    Hello @VavylonaEntertainment

    It sounds like you have a mesh simplifier, that generates lod meshes, correct?
    That is not what QuickLod does.

    QuickLod is a level of detail manager, so you have to provide the meshes and it makes sure that the correct mesh is shown.
    Additionally, it offers much functionality, like area culling, object group culling, enabling/disabling expensive components based on distance, etc.

    Basically, it does was the Unity integrated lod system does, but offers more features and hooks to allow you to improve performance even more.

    Greetings
    Chillersanim
     
    Liminal-Ridges likes this.
  32. Liminal-Ridges

    Liminal-Ridges

    Joined:
    Oct 21, 2015
    Posts:
    255
    Thank you Chillersanim for the information
     
  33. chillersanim

    chillersanim

    Joined:
    Mar 31, 2013
    Posts:
    219
    Hello all.

    I need to inform you, that I will discontinue the development of QuickLod.
    I don't have the time or ressources to keep improving QuickLod duo to my studies.
    I was working on a new data structure, but now I don't even have time for that.
    Also QuickLod hasn't been sold for quite some time thus I believe that QuickLod isn't necessary anymore.

    If you are still using QuickLod and have problems, please let me know.
    I will keep on helping with bugs or problems, but wont add new features.

    Thank you all who bought and used QuickLod.
    This was a good experience for me and I hope that my tool could help you somehow.

    Greetings
    Chillersanim
     
    julianr likes this.
  34. julianr

    julianr

    Joined:
    Jun 5, 2014
    Posts:
    1,210
    Good luck! and thanks for creating this asset, it was very useful to me in the early development of my game, before I moved to streaming assets.
     
    Last edited: Feb 18, 2019
    chillersanim likes this.
  35. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,624
    All good things eventually come to an end. I wish you well! :)
     
    chillersanim likes this.