Search Unity

[WIP] Easy Isosurface - Unity Tool

Discussion in 'Works In Progress - Archive' started by keenanwoodall, Jul 21, 2015.

  1. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    I've been working on an implementation of the terrain code created in a Lynda tutorial. You can easily create terrains or even metaballs. Here's some example code that creates an isosurface and allows you to have excess control over how it is generated. Most scripts would be a lot shorter, I just wanted to be able to test different features from the same script.
    [Edit]
    I'd love to put this on the asset store, but as I mentioned, this is based off of a tutorial so I want to make sure I have the rights to sell it. I don't want to try and sell code if people think it's a ripoff of a tutorial.
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.Collections;
    5. using Procedural.Isosurface;
    6. using Procedural.Noise;
    7. using Mathx;
    8.  
    9. [RequireComponent(typeof(MeshFilter))]
    10. public class IsosurfaceExample : MonoBehaviour
    11. {
    12.     //--Variables--
    13.         //-Public-
    14.             //Enumerations
    15.     public enum NoiseType{Perlin, Ridged}
    16.             //Parameters:
    17.     [Header("Isosurface")]
    18.     public Isosurface3D isosurface;
    19.     [Header("Noise")]
    20.     public NoiseType noiseType;
    21.     public PerlinObject perlin;
    22.     public RidgedMultifractalObject ridgedMultifractal;
    23.     [Header("Optimization")]
    24.     public bool update = true;
    25.     public bool disableAfterUpdate = true;
    26.     [Header("Additional Parameters")]
    27.     public Transform[] eraseObjects;
    28.     public Transform[] fillObjects;
    29.     public bool applyGradient;
    30.     [Range(-2f, 2f)]
    31.     public float gradientAmount = 0.5f;
    32.     public bool useWorldSpace = true;
    33.     public bool flatSides;
    34.     public bool createCollider = true;
    35.         //-Private-
    36.             //References:
    37.     Mesh mesh;
    38.     MeshCollider collider;
    39.  
    40.     //--Methods--
    41.         //-Initialization-
    42.     void Awake()
    43.     {
    44.         mesh = GetComponent<MeshFilter>().mesh;
    45.  
    46.         collider = GetComponent<MeshCollider>();
    47.         if(collider == null)
    48.             collider = gameObject.AddComponent<MeshCollider>();
    49.         collider.convex = false;
    50.  
    51.         CreateIsosurface();
    52.  
    53.         if(disableAfterUpdate)
    54.             update = false;
    55.         mesh.MarkDynamic();
    56.     }
    57.         //-Repeating-
    58.     void Update()
    59.     {
    60.         if(update)
    61.         {
    62.             CreateIsosurface();
    63.             collider.sharedMesh = null;
    64.             collider.sharedMesh = mesh;
    65.         }
    66.  
    67.         if(disableAfterUpdate)
    68.             update = false;
    69.     }
    70.     void CreateIsosurface()
    71.     {
    72.         isosurface.ClearData();
    73.         if(noiseType == NoiseType.Perlin)
    74.             isosurface.ProcessData(perlin.GetValue, (useWorldSpace) ? transform.position : Vector3.zero);
    75.         else if(noiseType == NoiseType.Ridged)
    76.             isosurface.ProcessData(ridgedMultifractal.GetValue, (useWorldSpace) ? transform.position : Vector3.zero);
    77.  
    78.         if(applyGradient)
    79.             isosurface.ProcessAllData(ApplyGradient);
    80.  
    81.         foreach(Transform fill in fillObjects)
    82.         {
    83.             if(fill != null && fill.gameObject.activeInHierarchy)
    84.             {
    85.                 Vector3Int fillIndexPosition = new Vector3Int();
    86.                 Vector3Int newFillScale = new Vector3Int(fill.localScale.x, fill.localScale.y, fill.localScale.z);
    87.                 isosurface.WorldPositionToArrayIndex(ref fillIndexPosition, fill.position, transform, 1f);
    88.                 isosurface.FillCube(fillIndexPosition, newFillScale);
    89.             }
    90.         }
    91.         foreach(Transform erase in eraseObjects)
    92.         {
    93.             if(erase != null && erase.gameObject.activeInHierarchy)
    94.             {
    95.                 Vector3Int eraseIndexPosition = new Vector3Int();
    96.                 Vector3Int newEraseScale = new Vector3Int(erase.localScale.x, erase.localScale.y, erase.localScale.z);
    97.                 isosurface.WorldPositionToArrayIndex(ref eraseIndexPosition, erase.position, transform, 1f);
    98.                 isosurface.EraseCube(eraseIndexPosition, newEraseScale);
    99.             }
    100.         }
    101.         isosurface.BuildData(ref mesh);
    102.     }
    103.     float[,,] ApplyGradient(float[,,] data)
    104.     {
    105.         for(int x = 0; x < data.GetLength(0) - ((flatSides == true) ? 1 : 0); x++)
    106.             for(int y = 0; y < data.GetLength(1) - ((flatSides == true) ? 1 : 0); y++)
    107.                 for(int z = 0; z < data.GetLength(2) - ((flatSides == true) ? 1 : 0); z++)
    108.                     data[x, y, z] -= ((float)y / ((float)isosurface.size.y / 2f)) - gradientAmount;
    109.         return data;
    110.     }
    111.     void OnDrawGizmos()
    112.     {
    113.         Gizmos.color = Color.green;
    114.         foreach(Transform fill in fillObjects)
    115.             if(fill != null && fill.gameObject.activeInHierarchy)
    116.                 Gizmos.DrawWireCube(fill.position, fill.localScale);
    117.         Gizmos.color = Color.red;
    118.         foreach(Transform erase in eraseObjects)
    119.             if(erase != null && erase.gameObject.activeInHierarchy)
    120.                 Gizmos.DrawWireCube(erase.position, erase.localScale);
    121.         Gizmos.color = Color.white;
    122.     }
    123. }
    124.  
    And here's a video that uses the example code.


    EDIT:
    I uploaded a stripped down version of what the video shows. It can do what was done in the video, but I had to take the example out so I could cleanup and refactor the code.
     

    Attached Files:

    Last edited: Jul 1, 2016
    Arkade likes this.
  2. mangax

    mangax

    Joined:
    Jul 17, 2013
    Posts:
    336
    this looks super interesting!
    am more interested in the part you did which is controlling (adding or subtracting) parts of voxel mesh.
    it will make making worlds by this tool a fun experience.

    now if you are planning to only make these little parts connects, it will be hard to manage later on if i wanted to make alot of modifications, so i suggest adding the ability to scale up these little cube fillers. moreover maybe you can try adding spheres which scale up in spherical fashion and they can merge up with cubes or other terrain.
     
  3. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    I guess I didn't show it off in the video, but you can scale the filler and eraser blocks non-uniformly and it will work perfectly. Right now rotation doesn't work though. Hopefully I can figure it out soon!
     
  4. Arkade

    Arkade

    Joined:
    Oct 11, 2012
    Posts:
    655
    Looks cool. So are you planning to open-source / asset store / use in your own project / ... ?
    Also, do you have a reference to the Lynda tutorial, please? Sounds fascinating (and I've never used it so maybe free sample time ;-) )
    Cheers, R.
     
  5. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    Here's the tutorial: http://www.lynda.com/Unity-3D-tutorials/Advanced-Unity-3D-Game-Programming/160270-2.html
    In response to your question on putting it on the Asset Store, I don't want to run into any legal issues by selling the asset. As I said, it is based off of a tutorial, so even though I've modified it heavily, I'll have to look into whether or not selling it can get me into trouble. I'll contact the guy who made the tutorial to see what he thinks. I'm definitely open to releasing the source, but I guess I'll see what the demand is.
     
  6. mangax

    mangax

    Joined:
    Jul 17, 2013
    Posts:
    336
    hi keen, that sounds good!
    are you planning to publish this tool in asset store? i will be interested to get it!

    am wondering whats your plan for this tool? (what kind of things this tool will achieve in future)
     
  7. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    I'm really not sure haha. I'd love to add a helper script to allow sculpting at runtime or even in the editor. Some sort of texturing system would also be great. For example, If a polygon's normal is facing up it could be grass textured or if it's facing down it could be dirt textured. Another thing I thinking of is coming up with an easy way to create objects on the faces of the mesh. That would be super helpful.
     
  8. Arkade

    Arkade

    Joined:
    Oct 11, 2012
    Posts:
    655
    Thanks for the link. I guess it's in the "Dynamic meshes" section?

    Source would (obviously?) be even better than asset!

    The only voxel system I've used had 3-ish parts to this (IIRC):
    1. triplanar shader does the basic job
    2. multiple materials allowed different blocks to have different materials
    3. blend values passed through the vertex colours allowed the triplanar shader to blend between.
    You probably come up with a better solution but thought to mention. Oh, and you might want to look at RTP3 and enable compatibility in your design!
    HTH!
     
  9. mangax

    mangax

    Joined:
    Jul 17, 2013
    Posts:
    336
    personally i find my self most of the time in need for a tool that helps in making simple balanced platform levels..

    there are many tools in assets store.. but they demand alot of pre-setup for tiles that should be made outside unity, also tiles don't help in any variation at all. most of these tools aims for repetitive dungeons...which are limited.

    if your voxel tool can help creating meshes and bending or create all types of simple voxel connected shapes.
    it would be very awesome tool. am sure many people will find it very helpful!

    am using currently probuilder and do good job in modeling worlds or platforms in unity.
    but still the voxel flexibility is unlimited.
     
  10. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    That's interesting. I think adding spline functionality would be interesting (and would be helpful to you). The mesh could be created along the spline which would allow quick level design. Does that sound helpful or useful? It sounds pretty cool to me so I think I'll start trying to implement it!
     
  11. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    Triplanar shader? I'll look into it. As for open source I'm almost positive I'll be posting the project from the youtube demo for people to test out. Feedback and suggestions would be much appreciated.
     
    Arkade likes this.
  12. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    Here's a basic spline controller for the Isosurface. It's really rough but I think it's a good start. The main issue I'm having is leaking meshes. I've never been able to figure out how to prevent it when making meshes in the editor. If anyone has some advice on preventing leaks, please let me know. I think this might be a helpful tool in platform level design. You can quickly draw and modify a spline to create a base level.
     
  13. mangax

    mangax

    Joined:
    Jul 17, 2013
    Posts:
    336
    This looks very interesting! i wish i can help in some coding tricks, but am not that knowledgeable in voxels or dynamic mesh creation.

    what am thinking also (and suggesting) is to have away to paint with more control of height or certain axis.

    for example i can set a fixed height for the paint brush in Y axis, and then whenever i paint, the new added voxel are only expanding in Z & X axis, while Y remains in fixed height.. this will be a good way to keep created levels more consistent in height and help avoiding messing up things.
     
  14. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    You're right, that would be nice. I'll try and implement it when I get the time. Thanks for the suggestions!
     
  15. mangax

    mangax

    Joined:
    Jul 17, 2013
    Posts:
    336
    wow sure has been a long time :) almost a year!
    has there been any new updates on this?
     
  16. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    Not really, I've kinda taken a break. The code is pretty messy so I really need to clean it up. I'll see if I can find the project files. Because I haven't really pursued this project as much as I would have liked, I'll try and find the project file for you! :) I can't make any promises on how easy it is to use, but maybe you can do something cool with it. Email me at keenan@fivestonestudios.com and I'll send you the project files, if I can find them. :)
     
  17. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    598
    Hey mangax, I did some code cleanup and made some examples. This is a very stripped down version of what you saw in my first video, although you can easily recreate it with some nice noise! Here's a Unity package.
     

    Attached Files:

    Arkade likes this.
  18. EugeneG97

    EugeneG97

    Joined:
    Apr 4, 2019
    Posts:
    1
    I'm currently working with your isosuface example and I'm wondering how do change the size of the isosurface mesh model?