Search Unity

trouble spawning grass

Discussion in 'Scripting' started by Yourking77, Aug 23, 2016.

  1. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    I am having trouble getting my script to spawn grass. the script first gets the mesh, detects every triangle, casts a ray over top of every triangle, and gets the material attached to each triangle. then it determines if the material is grass or dirt or not and does some calculations to determine if and what it should spawn on each triangle.
     
  2. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    Is the mesh uv mapped? Then you could check the textures pixels to determine if it's grass or not, think it's cheaper than rays.
    That aside what goes wrong with your system? Is it not spawning grass or does it spawn at the wrong location?
     
  3. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    No, there is no UV unwrap, I created a system with blender that I am getting quite fast at and my world is expanding more and more rapidly so it is too late to start doing that now. each cell is a mesh, then in blender I paint the grass and the dirt and the cliffs, so is there any way faster than a ray for that type of system? it is all low poly and each cell has around 1000 triangles. each material is just a solid color, so determining what pixels are in each triangle should not be too hard if you can think of a better way to detect what material is used on each triangle.

    the system is just not spawning anything, If you could check my triangle center calculation that may be part of the problem, I was not sure how to get the center of it, sorry I meant to post my code last night but was very tired and it looks like I forgot somehow, I created this project as a learning project mainly, so to me being able to do something like this without asking for too much help is a major accomplishment. However yes rays being way too slow on thousands upon thousands of triangles on start up.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class FoliageGeneration : MonoBehaviour {
    6.  
    7.     public Material grassMaterial;
    8.     public Material dirtMaterial;
    9.  
    10.     public GameObject[] grassObject;
    11.     public GameObject[] flowerObject;
    12.     public GameObject[] treeObject;
    13.  
    14.     public bool spawnOnDirt = false;
    15.  
    16.     [Range(0,100)]
    17.     public double grassChance;
    18.     [Range(0, 100)]
    19.     public double flowerChance;
    20.     [Range(0, 100)]
    21.     public double treeChance;
    22.     [Range(0, 100)]
    23.     public double blankChance;
    24.  
    25.     double totalChance;
    26.  
    27.     Mesh cell;
    28.     int[] triangleIndex;
    29.     Vector3[] verticeIndex;
    30.  
    31.     RaycastHit hit;
    32.  
    33.     void Start()
    34.     {
    35.         cell = gameObject.GetComponent<MeshFilter>().mesh;
    36.  
    37.         triangleIndex = cell.triangles;
    38.         verticeIndex = cell.vertices;
    39.  
    40.         for (int i = 0; i >= triangleIndex.Length; i++)
    41.         {
    42.             Vector3 a = verticeIndex[triangleIndex[hit.triangleIndex + 0]];
    43.             Vector3 b = verticeIndex[triangleIndex[hit.triangleIndex + 1]];
    44.             Vector3 c = verticeIndex[triangleIndex[hit.triangleIndex + 2]];
    45.  
    46.             Vector3 target = a + b + c / 3;
    47.             target.z += 1;
    48.  
    49.             Ray ray = new Ray(target, target);
    50.  
    51.             Material targetMaterial = hit.collider.GetComponent<Material>();
    52.  
    53.             if (targetMaterial == grassMaterial)
    54.             {
    55.                 CalculateChances();
    56.             }
    57.             else if (spawnOnDirt == true)
    58.             {
    59.                 if (targetMaterial == dirtMaterial)
    60.                 {
    61.                     CalculateChances();
    62.                 }
    63.             }
    64.         }
    65.     }
    66.  
    67.     public void CalculateChances()
    68.     {
    69.         totalChance = grassChance + flowerChance + treeChance;
    70.         totalChance /= 300;
    71.         totalChance /= 3;
    72.  
    73.         var spawnChance = Random.Range(0, 100);
    74.         if (spawnChance < blankChance)
    75.         {
    76.             spawnChance = Random.Range(0, 300);
    77.             if (spawnChance >= totalChance)
    78.             {
    79.                 SpawnGrass();
    80.             }
    81.             if (spawnChance < totalChance && spawnChance >= (totalChance * 2))
    82.             {
    83.                 SpawnFlowers();
    84.             }
    85.             if (spawnChance < (totalChance * 2) && spawnChance >= (totalChance * 3))
    86.             {
    87.                 SpawnTrees();
    88.             }
    89.         }
    90.     }
    91.  
    92.     public void SpawnGrass()
    93.     {
    94.         var objectToSpawn = Random.Range(0, grassObject.Length);
    95.  
    96.         GameObject grass = GameObject.Instantiate(grassObject[objectToSpawn]);
    97.         grass.transform.parent = transform;
    98.         grass.name = grassObject[objectToSpawn].name;
    99.     }
    100.  
    101.     public void SpawnFlowers()
    102.     {
    103.         var objectToSpawn = Random.Range(0, flowerObject.Length);
    104.  
    105.         GameObject flower = GameObject.Instantiate(flowerObject[objectToSpawn]);
    106.         flower.transform.parent = transform;
    107.         flower.name = flowerObject[objectToSpawn].name;
    108.     }
    109.  
    110.     public void SpawnTrees()
    111.     {
    112.         var objectToSpawn = Random.Range(0, treeObject.Length);
    113.  
    114.         GameObject tree = GameObject.Instantiate(treeObject[objectToSpawn]);
    115.         tree.transform.parent = transform;
    116.         tree.name = treeObject[objectToSpawn].name;
    117.     }
    118. }
     
  4. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    Instead of doing it at run time every time, is there a way to convert the script to run in the editor and spawn the stuff in the hierarchy? we can worry about that as soon as I get the script working but that idea just came to mind and it would fix all the speed issues if it is possible.
     
  5. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    Here's a template I use for a Custom Editor script :
    Code (csharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. [CustomEditor( typeof(SomeExample) )]
    6. public class SomeExampleEditor : Editor
    7. {
    8.    public override void OnInspectorGUI()
    9.    {
    10.      DrawDefaultInspector();
    11.    
    12.      EditorGUILayout.Space();
    13.      EditorGUILayout.BeginHorizontal();
    14.      if ( GUILayout.Button( "Call A Function" ) )
    15.      {
    16.        SomeExample targetScript = (SomeExample)target;
    17.        targetScript.CallAFunction();
    18.      }
    19.      EditorGUILayout.EndHorizontal();
    20.    
    21.      EditorGUILayout.Space();
    22.      EditorGUILayout.BeginHorizontal();
    23.      if ( GUILayout.Button( "Call Another Function" ) )
    24.      {
    25.        SomeExample targetScript = (SomeExample)target;
    26.        targetScript.CallAnotherFunction();
    27.      }
    28.      EditorGUILayout.EndHorizontal();
    29.    }
    30. }
    You can make targetScript global, and typecast the target reference to it in OnEnable, if you wish.
     
  6. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    Thanks I assume I can generate things from within the editor then, that will come in handy later but how can I get things spawning for now? I cannot get anything to spawn. since I posted the script I noticed I did not tell the Instantiated object a position, so I fixed that and that was not the issue.

    I did glance over that script and it did not look any more difficult than stuff I have practiced already so that is good that I can convert this easily to be used in the editor rather than the game.
     
  7. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    this never runs. I assume you want:
    Code (csharp):
    1. for (int i = 0; i < triangleIndex.Length; i++)
    Edit: and I see a few other things as well.
    hit is not assigned when you first use it
    even after you declare the ray, there is no raycast to populate hit
     
  8. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    oh duh, thanks for pointing that out, I have got to get better with loops, especially for loops, don't I need the eqaul sign though? I never see people use it, but it would make sense otherwise it is not running the last thing up there right?
     
  9. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    Edit: that definately did something because it spits out a null reference exception for every single cell now, I will debug and see if I can pinpoint the problem. let me know if you see any more big mistakes likethat though
     
  10. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    Well the raycast is the most important thing. It returns lots of values stored in hit, like the collider and the point. You'll need to pass information like the hit point to the instantiate function.
    How you are finding the ray variables is incorrect. you want the origin, and direction.

    Stop, and have a think about the process.

    You want sites to place details(grass, trees, etc).
    Raycast those sites to get :
    - the collider material (for instantiation of detail type)
    - the hit.point(for instantiation of detail position),
    - and also possibly the hit.normal (for instantiation of detail rotation).

    Create a list of sites to raycast:
    probably the simplest method is to make a 2D grid, then add a little random to each grid position before raycasting.
    Create a 2D array. Set the width and length for 'density' eg 20 * 20 = 400 grid positions to raycast
    loop through for each grid position:
    make the grid position relative to the model you want to hit (world-space)
    Raycast at the grid position + random xz, make y 1000
    Raycast down (-Vector3.up) for a distance of 2000. That's a total range of -1000 to +1000, your scene probably isn't that high/low. If so, then increase y and/or distance.
    get the hit collider
    check the material, do random, instantiate at the hit point, do some random rotation or use the hit normal

    That is just a brief outline, there are more considerations, but I think that would be a good place to start. When it's working, you can vary how to find sites for raycasting.
     
    Last edited: Aug 24, 2016
  11. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    My idea was I need sites, to find those sites use the triangles on the mesh,

    then calculate the center of each triangle for each triangle in a for loop,

    cast a ray at those triangles using the center of the triangle,

    then use the ray to determine what material is attached to each triangle,

    then compare if it is the one I want and from there calculate the rest.

    I am a beginner so this in and of itself was a pretty big step especially constructing it without internet for the most part. what you describes sounds almost like re-scripting the whole thing.
     
  12. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    actually while you point that out I found a problem on teh line casting the ray, I am casting it in the position of the target, but the direction is always supposed to be Vector3.down, not target again. That did not fix anything but still, however now that I read your post a second time it seems more clear what your are saying, basically the same thing but instead of triangles use an imaginary grid. my problem now is how big does the grid have to be? and how would I actually make the grid I am having trouble with that also.
     
    Last edited: Aug 25, 2016
  13. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    Here is my new and improved code

    exact same problem as before and I have no idea where to look and I have a million other things to do and only about 3 hours left to do them so if you could take a look at this i would appreciate it, I am done with it for the day.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class FoliageGeneration : MonoBehaviour {
    6.  
    7.     public Material grassMaterial;
    8.     public Material dirtMaterial;
    9.  
    10.     public GameObject[] grassObject;
    11.     public GameObject[] flowerObject;
    12.     public GameObject[] treeObject;
    13.  
    14.     public bool spawnOnDirt = false;
    15.  
    16.     [Range(0, 100)]
    17.     public double grassChance;
    18.     [Range(0, 100)]
    19.     public double flowerChance;
    20.     [Range(0, 100)]
    21.     public double treeChance;
    22.     [Range(0, 100)]
    23.     public double blankChance;
    24.  
    25.     double totalChance;
    26.  
    27.     int gridSize = 23;
    28.     int xSize, ySize;
    29.     Vector3[] grid;
    30.  
    31.     RaycastHit hit;
    32.  
    33.     public void Start()
    34.     {
    35.         xSize = gridSize;
    36.         ySize = gridSize;
    37.  
    38.         for (int i = (gridSize * -1), y = 0; y <= ySize; y++)
    39.         {
    40.             for (int x = 0; x <= xSize; x++, i++)
    41.             {
    42.                 grid[i] = new Vector3(x, y);
    43.             }
    44.         }
    45.  
    46.         for (int i = 0; i <= grid.Length; i++)
    47.         {
    48.             Vector3 rayDirection = grid[i];
    49.             rayDirection.y += 5000;
    50.             Ray Ray = new Ray(grid[i], rayDirection);
    51.             Material hitMaterial = hit.collider.GetComponent<Material>();
    52.  
    53.             if (hitMaterial == grassMaterial)
    54.             {
    55.                 CalculateChances();
    56.             }
    57.             else if (spawnOnDirt == true)
    58.             {
    59.                 if (hitMaterial == dirtMaterial)
    60.                 {
    61.                     Debug.Log("Calculating");
    62.                     CalculateChances();
    63.                 }
    64.             }
    65.         }
    66.     }
    67.  
    68.     public void CalculateChances()
    69.     {
    70.         totalChance = grassChance + flowerChance + treeChance;
    71.         totalChance /= 300;
    72.         totalChance /= 3;
    73.  
    74.         var spawnChance = Random.Range(0, 100);
    75.         if (spawnChance < blankChance)
    76.         {
    77.             spawnChance = Random.Range(0, 300);
    78.             if (spawnChance >= totalChance)
    79.             {
    80.                 SpawnGrass();
    81.             }
    82.             if (spawnChance < totalChance && spawnChance >= (totalChance * 2))
    83.             {
    84.                 SpawnFlowers();
    85.             }
    86.             if (spawnChance < (totalChance * 2) && spawnChance >= (totalChance * 3))
    87.             {
    88.                 SpawnTrees();
    89.             }
    90.         }
    91.     }
    92.  
    93.     public void SpawnGrass()
    94.     {
    95.         var objectToSpawn = Random.Range(0, grassObject.Length);
    96.  
    97.         GameObject grass = GameObject.Instantiate(grassObject[objectToSpawn]);
    98.         grass.transform.parent = transform;
    99.         grass.name = grassObject[objectToSpawn].name;
    100.     }
    101.  
    102.     public void SpawnFlowers()
    103.     {
    104.         var objectToSpawn = Random.Range(0, flowerObject.Length);
    105.  
    106.         GameObject flower = GameObject.Instantiate(flowerObject[objectToSpawn]);
    107.         flower.transform.parent = transform;
    108.         flower.name = flowerObject[objectToSpawn].name;
    109.     }
    110.  
    111.     public void SpawnTrees()
    112.     {
    113.         var objectToSpawn = Random.Range(0, treeObject.Length);
    114.  
    115.         GameObject tree = GameObject.Instantiate(treeObject[objectToSpawn]);
    116.         tree.transform.parent = transform;
    117.         tree.name = treeObject[objectToSpawn].name;
    118.     }
    119. }
     
  14. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    Not at all :) just the main logic. The randomization looks fine. The instantiation needs a minor tweak, I like how you parent and name the object.

    The first real main issue I see trending is you need to learn how to do a raycast. A Ray just defines some of the variables used in a raycast, it doesn't actually do the Raycast. (right between line 50 and 51 is where the raycast should be)

    Havn't seen it, but here's the Unity Learn video : https://unity3d.com/learn/tutorials/topics/physics/raycasting?playlist=17120

    There are 2 main things: doing the raycast, and getting the information from the raycast hit.

    You kinda got close with the grid thing. Each grid position can be used as an origin position in the raycast. It can be calculated and used in the same loop, so no need to store it.
    For the grid spacing, you just calculate a grid to world scale modifier = worldSize / numberOfDivisions

    Here's a little script that uses gizmos to visualize the 'grid' of raycasts. Create a new scene, attach script to an empty gameObject, runs in edit mode (gizmos).
    Code (csharp):
    1. // rayOrigin is calculated in code
    2. private Vector3 rayDirection = -Vector3.up;
    3. public float rayDistance = 10f;
    4.  
    5. public float gridSize = 20f;
    6. public int gridDivisions = 24;
    7.  
    8. //   -------------------------------------------------------  Gizmos Functions
    9.  
    10. void OnDrawGizmos()
    11. {
    12.    // store current position for adding to make world position
    13.    Vector3 txPos = transform.position;
    14.    // get the world scale of each division of the grid
    15.    float gridScale = gridSize / (float)gridDivisions;
    16.  
    17.    // calculate a world position for each division in the grid of raycasts
    18.    for ( int y = 0; y < gridDivisions; y++ )
    19.    {
    20.      for ( int x = 0; x < gridDivisions; x++ )
    21.      {
    22.        // create grid position
    23.        Vector3 rayOrigin = new Vector3( x, 0, y );
    24.        // modify by the world scale
    25.        rayOrigin *= gridScale;
    26.        // add to the world position this object
    27.        rayOrigin += txPos;
    28.      
    29.        // draw a line representing the raycast
    30.        Gizmos.DrawRay( rayOrigin, rayDirection * rayDistance );
    31.      }
    32.    }
    33. }
    It uses the position of the object it is attached to, so just move that around.

    It's almost the same as what you would use for the raycasts. I know it's frustrating, but post back when you learned how to do a raycast and get hit information. Then we can look at using the Hit point and normal, passing that to your instantiation functions.
     
    Last edited: Aug 25, 2016
  15. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    I don't quite get everything you are saying, however i will take a look at my script and re-read your post a few times, implement some of your suggestion and I'll post my code a little bit later. not storing each point is sort of like, duh, why didn't I think of that, the grid thing I have not fully tested but the post I seen where someone did something similar that I got the idea from the grid started positioning from the lower left hand corner i.e. (0,0), so i had to be 1/2 * -1 of the desired grid size to center the grid I think, in theory that seemed to make sense however I have a tendency to overthink things.
     
    Last edited: Aug 26, 2016
  16. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    I didn't mess with much and I am not going to get time this weekend, I have some major cell concerns with my map that I need to get sorted out, I will have to take a look in a few days I am leaving for the weekend, so unfortunately this script had to be put on hold at the moment.
     
  17. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Just a quick comment on your post a while back about needing an equal sign in the for loop. In C# there are 3 basic comparisons <= This means less than or equal to, >= means Greater than or Equal to, and == Means equal to. There is no assignment going on at all, its just comparing two things and spitting out true/false.

    Here is a quick rundown of for loops:

    for (Initialize; Comparison; Iterator)
    {
    // do stuff
    }

    for (i=0;i<=10;i++) { // do stuff }

    What happens when you write this code, One time only the script runs the Inaitlize part, in this case i=0
    Then it it does this in order over and over:
    1. Check the comparison (in this case is i "less than or equal to 10" if no loop is over.. if yes proceed to 2
    2. // do all the stuff in the loop
    3. Do the iterator. in this case i++ which means i=i+1. Loop back to 1
    This is why your original loop failed to work at all
    for (i=0;i>=triangleIndex.Length;i++)

    It set i equal to 0. Then checked is 0 greater than or equal to triangleIndex.Lenght (which is probably a big number). this is false so exit the loop without even running it once.
     
  18. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    I understand all of that already, I just had not realized that i placed the sign the wrong way. Simple mistake on that part.
     
  19. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    I have been away from it for a while and I am sorry but I rewrote the whole thing and came up with this. now my [problem seems to be that it is not getting or setting the tergetMaterial to the correct thing. I have no idea how to get it to do that and need help once more, the rewritten script takes everything I learned from the first time and combines all the concepts and is shorter and better written. So I sort of took one step back and 2 forward.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class FoliageGeneration : MonoBehaviour {
    6.  
    7.     public GameObject cell;
    8.     public Material grassMaterial;
    9.     Material targetMaterial;
    10.  
    11.     public int xSize = 46;
    12.     public int ySize = 46;
    13.     public int ySafe = 5000;
    14.  
    15.     void Start()
    16.     {
    17.         Generate();
    18.     }
    19.  
    20.     public void Generate() {
    21.         Debug.Log("Generating");
    22.         for (int x = -(xSize / 2); x <= xSize; x++)
    23.         {
    24.             for (int y = -(ySize / 2); y <= ySize; y++)
    25.             {
    26.                 float z = cell.transform.position.z + ySafe;
    27.                 Vector3 rayPosition = new Vector3(x , y , z);
    28.                 Debug.Log(rayPosition);
    29.                 Ray ray = new Ray(rayPosition, Vector3.down);
    30.                 RaycastHit hit = new RaycastHit();
    31.  
    32.                 Physics.Raycast(ray, out hit);
    33.  
    34.                 targetMaterial = hit.collider.GetComponent<Material>();
    35.                 Debug.Log(targetMaterial.name);
    36.                 if (targetMaterial == grassMaterial) Debug.Log("Spawned grass on cell at"  + rayPosition);
    37.             }
    38.         }
    39.     }
    40.  
    41.     public void SpawnGrass()
    42.     {
    43.        
    44.     }
    45. }
     
  20. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    So first off there are two kinds of Materials in Unity. There are Materials which is what I think your working with, and PhysicMaterial. A PhysicMaterial is just a set of Properties that help with bounciness, friction,etc. This is whats on a collider: https://docs.unity3d.com/Manual/class-PhysicMaterial.html

    I suspect your Grass Material is attached to a MeshRenderer or something like that. If the GameObject that this collider is attached to only has one material you could do this:
    Code (CSharp):
    1. targetMaterial = hit.collider.gameObject.GetComponent<Material>();
     
  21. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    line 36 says you want to spawn a new grass. So here is some code to help you spawn a prefab and set it's material

    line 10 you need to add a gameobject to spawn
    public GameObject grassPrefab;

    if line 36 is true. you need to instantiate a prefab and then set it's position, then set it's material. something like this.
    if(targetMaterial == grassMaterial)
    {
    Debug.Log("Spawned grass on cell at"+ rayPosition);
    GameObject newGrass = (GameObject)Instantiate(grassPrefab);
    newGrass.transform.position = hit.collider.gameObject.transform.position; or newGrass.transform.position = rayPosition;
    newGrass.GetComponent<Material>().render.material = grassMaterial; it might be newGrass.GetComponent<Renderer>().material = grassMaterial;
    }


    FYI: code was not tested, but it should give you an idea on what is needed
     
  22. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    thanks for the help but I know all of that already, my problem "I think" is the model the code is "Scanning" has more than one material attached, so I need to get the material that the ray has hit, not the one attached to the model the ray hit. the debug code on line 35 is not getting called the error happens when I try to get the material just before that,
     
  23. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    When I run your script I'm getting a null reference error on line35. is that what you're getting? It looks like my cast isn't hitting anything.
    On line 33 add a new debug to verify that you hit something
    Debug.Log(hit.transform.name);

    On line 34, have you tried
    hit.GetComponent<Renderer>().material
     
  24. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    your right, I thought I was casting the ray correctly this time but it appears not, how can I fix this issue?
     
  25. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    I also updated the code earlier it would only scan the center of the game world I think now it centers the rays over the cell. On line 25 and 26 it creates an offset based on the cell position. Have not been able to test that yet but I think it should work correctly, in theory it makes sense to me anyway.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class FoliageGeneration : MonoBehaviour {
    6.  
    7.     public GameObject cell;
    8.     public Material grassMaterial;
    9.     Material targetMaterial;
    10.  
    11.     public int xSize = 46;
    12.     public int ySize = 46;
    13.     public int ySafe = 5000;
    14.  
    15.     void Start()
    16.     {
    17.         Generate();
    18.     }
    19.  
    20.     public void Generate() {
    21.         Debug.Log("Generating");
    22.         for (float x = -(xSize / 2); x <= xSize; x++)
    23.         {
    24.             for (float y = -(ySize / 2); y <= ySize; y++)
    25.             {
    26.                 x = cell.transform.position.x + x;
    27.                 x = cell.transform.position.y + y;
    28.                 float z = cell.transform.position.z + ySafe;
    29.  
    30.                 Vector3 rayPosition = new Vector3(x , y , z);
    31.                 Debug.Log(rayPosition);
    32.                 Ray ray = new Ray(rayPosition, Vector3.down);
    33.                 RaycastHit hit = new RaycastHit();
    34.  
    35.                 Physics.Raycast(ray, out hit);
    36.                 Debug.Log(hit.transform.name);
    37.  
    38.                 targetMaterial = hit.collider.GetComponent<Renderer>().material;
    39.                 Debug.Log(targetMaterial.name);
    40.                 if (targetMaterial == grassMaterial) Debug.Log("Spawned grass on cell at"  + rayPosition);
    41.             }
    42.         }
    43.     }
    44.  
    45.     public void SpawnGrass()
    46.     {
    47.      
    48.     }
    49. }
     
  26. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    for me the ysafe was messing things up. I created an if statement around the output of the raycast.

    i spawned an object at the ray starting point and found the 5000 was moving my ray cast off the object, so it never hit anything. you can remove this spawning code

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class FoliageGeneration : MonoBehaviour {
    5.  
    6.     public GameObject cell;
    7.     public GameObject SpawnMe;
    8.     public Material grassMaterial;
    9.     Material targetMaterial;
    10.  
    11.     public int xSize = 46;
    12.     public int ySize = 46;
    13.     public int ySafe = 0;
    14.  
    15.     void Start()
    16.     {
    17.         Generate();
    18.     }
    19.  
    20.     public void Generate()
    21.     {
    22.         Debug.Log("Generating");
    23.         for (float x = -(xSize / 2); x <= xSize; x++)
    24.         {
    25.             for (float y = -(ySize / 2); y <= ySize; y++)
    26.             {
    27.                 x = cell.transform.position.x + x;
    28.                 x = cell.transform.position.y + y;
    29.                 float z = cell.transform.position.z + ySafe;
    30.  
    31.                 Vector3 rayPosition = new Vector3(x, y, z);
    32.                 Debug.Log(rayPosition);
    33.                 Ray ray = new Ray(rayPosition, Vector3.down);
    34.  
    35.                 //for my testing
    36.                 Instantiate(SpawnMe, rayPosition, Quaternion.identity);
    37.  
    38.                 RaycastHit hit = new RaycastHit();
    39.  
    40.                 if (Physics.Raycast(ray, out hit))
    41.                 {
    42.                     Debug.Log("The ray Hit something : " + hit.transform.name);
    43.  
    44.                     targetMaterial = hit.collider.GetComponent<Renderer>().material;
    45.                     Debug.Log(targetMaterial.name);
    46.                     if (targetMaterial == grassMaterial) Debug.Log("Spawned grass on cell at" + rayPosition);
    47.                 }
    48.             }
    49.         }
    50.     }
    51.  
    52.     public void SpawnGrass()
    53.     {
    54.  
    55.     }
    56.  
    57. }
    58.  
     
  27. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    It is actually suppoed to be zSafe, its a typo. but the point is to make sure the ray is not casting under the cell. how can I fix this?
     
  28. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    looking at the part where I cast the ray the direction, Vector3.down, I noticed it was short for (0, -1, 0). Which means y is the height, so I restructured my code and I have a lot of things working now, no doubt I will run into problems later but for now I think I sort of unlocked a bunch of stuff and have a lot of work ahead of me. I will post my current code if anyone is interested.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class FoliageGeneration : MonoBehaviour {
    6.  
    7.     public GameObject cell;
    8.     public Material grassMaterial;
    9.     Material targetMaterial;
    10.  
    11.     public int xSize = 46;
    12.     public int ySafe = 5000;
    13.     public int zSize = 46;
    14.  
    15.     void Start()
    16.     {
    17.         Generate();
    18.     }
    19.  
    20.     public void Generate() {
    21.         Debug.Log("Generating");
    22.         for (float x = -(xSize / 2); x <= (xSize / 2); x++)
    23.         {
    24.             for (float z = -(zSize / 2); z <= (zSize / 2); z++)
    25.             {
    26.                 x = cell.transform.position.x + x;
    27.                 float y = cell.transform.position.y + ySafe;
    28.                 z = cell.transform.position.z + z;
    29.  
    30.                 Vector3 rayPosition = new Vector3(x , y , z);
    31.                 Debug.Log(rayPosition);
    32.                 Ray ray = new Ray(rayPosition, Vector3.down);
    33.                 RaycastHit hit = new RaycastHit();
    34.  
    35.                 Physics.Raycast(ray, out hit);
    36.                 if (hit.collider != null && hit.collider.transform.name == "cell")
    37.                 {
    38.                     Debug.Log(hit.transform.name);
    39.  
    40.                     targetMaterial = hit.collider.GetComponent<Renderer>().material;
    41.                     if (targetMaterial != false)
    42.                     {
    43.                         Debug.Log(targetMaterial.name);
    44.                         if (targetMaterial.color == grassMaterial.color) Debug.Log("Spawned grass on cell at" + rayPosition);
    45.                     }
    46.                 }
    47.             }
    48.         }
    49.     }
    50.  
    51.     public void SpawnGrass()
    52.     {
    53.        
    54.     }
    55. }
     
  29. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    alright now I am where I need some help, it is working amazing for my work, and returns the material name properly with the debug, but it is spawning grass on every single spot on the cell not just the grass, and I set it up to work when I click a button in the editor, which made it so that it keeps renaming the grass material attached to the cell, I would like that fixed as well.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class FoliageGeneration : MonoBehaviour {
    6.  
    7.     GameObject cell;
    8.     public Material grassMaterial;
    9.     Material targetMaterial;
    10.  
    11.     public float xSize = 45;
    12.     public float ySafe = 5000;
    13.     public float zSize = 45;
    14.  
    15.     Vector3 spawnPoint;
    16.     GameObject environment;
    17.     GameObject environmentCell;
    18.     public GameObject[] foliage;
    19.  
    20.     public void Generate() {
    21.         Debug.Log("Generating");
    22.  
    23.         //Set up the parents to be used later.
    24.         InitialParentSetUp();
    25.  
    26.         //Scan the cell and determine where to place objects.
    27.         for (float x = -(xSize / 2); x <= (xSize / 2); x++)
    28.         {
    29.             for (float z = -(zSize / 2); z <= (zSize / 2); z++)
    30.             {
    31.                 x = cell.transform.position.x + x;
    32.                 float y = cell.transform.position.y + ySafe;
    33.                 z = cell.transform.position.z + z;
    34.  
    35.                 Vector3 rayPosition = new Vector3(x, y, z);
    36.                 Debug.Log(rayPosition);
    37.                 Ray ray = new Ray(rayPosition, Vector3.down);
    38.                 RaycastHit hit = new RaycastHit();
    39.  
    40.                 Physics.Raycast(ray, out hit);
    41.                 if (hit.collider != null)
    42.                 {
    43.                     if (hit.transform == gameObject.transform)
    44.                     {
    45.                         Debug.Log(hit.transform.name);
    46.  
    47.                         targetMaterial = hit.collider.GetComponent<Renderer>().material;
    48.                         if (targetMaterial != false)
    49.                         {
    50.                             Debug.Log(targetMaterial.name);
    51.                             if (targetMaterial.color == grassMaterial.color)
    52.                             {
    53.                                 spawnPoint = hit.point;
    54.                                 SpawnFoliage();
    55.                                 Debug.Log("Spawned grass on cell at" + rayPosition);
    56.                             }
    57.                             else Debug.Log("Target materials were not teh same");
    58.                         }
    59.                         else Debug.Log("Target material could not be loaded");
    60.                     }
    61.                     else Debug.Log("Cell scan out of bounds");
    62.                 }
    63.                 else Debug.Log("Could not find cell");
    64.             }
    65.         }
    66.     }
    67.  
    68.     public void InitialParentSetUp()
    69.     {
    70.         Debug.Log("Setting up parents");
    71.         //Set up the parents to begin spawning objects.
    72.         cell = gameObject;
    73.  
    74.         if (gameObject.transform.parent.parent.FindChild("Environment") == null)
    75.         {
    76.             Debug.Log("Parent did not already exist");
    77.             environment = new GameObject();
    78.             environment.transform.position = Vector3.zero;
    79.             environment.transform.parent = gameObject.transform.parent.parent;
    80.             environment.transform.name = "Environment";
    81.         }
    82.         else environment = gameObject.transform.parent.parent.FindChild("Environment").gameObject;
    83.  
    84.         if (environment.transform.FindChild(gameObject.name) == null)
    85.         {
    86.             Debug.Log("Parent did not already exist");
    87.             environmentCell = new GameObject();
    88.             environmentCell.transform.position = gameObject.transform.position;
    89.             environmentCell.transform.parent = environment.transform;
    90.             environmentCell.transform.name = cell.name;
    91.         }
    92.         else environmentCell = environment.transform.FindChild(gameObject.name).gameObject;
    93.  
    94.         //Clear the existing foliage.
    95.  
    96.         while (environmentCell.transform.childCount < -1)
    97.         {
    98.             int index = environmentCell.transform.childCount;
    99.             environmentCell.transform.GetChild(index);
    100.         }
    101.     }
    102.  
    103.     public void SpawnFoliage()
    104.     {
    105.         int i = Random.Range(0, foliage.Length);
    106.         GameObject spawnedFoliage = foliage[i];
    107.         Instantiate(spawnedFoliage);
    108.         spawnedFoliage.transform.position = spawnPoint;
    109.         spawnedFoliage.transform.parent = environmentCell.transform;
    110.         spawnedFoliage.transform.name = foliage[i].name;
    111.     }
    112. }
     
  30. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    I think this might help.
    I'm having issue visualizing what's going on in your scene. running your script on my system is not producing the same results. I keep getting "else Debug.Log("Could not find cell");". so that means my raycast is not hitting anything.

    public void SpawnFoliage()
    {
    int i = Random.Range(0, foliage.Length);
    GameObject spawnedFoliage = foliage;

    GameObject spawMe = Instantiate(spawnedFoliage);
    spawMe.transform.position = spawnPoint;
    spawMe.transform.parent = environmentCell.transform;
    spawMe.transform.name = foliage.name;
    }
     
  31. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    did you set the tag to cell? that may be the problem you are having testing, but the instantiating is not the problem, my problem is it is only supposed to be instantiating where there is grass, the debug displays the name as grass, but it still spawns grass on every spot instead of only where it is supposed to.
    This script requires a lot of error messages because it will be a huge tool for me when i am making this game, so I want to get it as flawless and fool proof as possible now. So there are just a ton of debugs and such to write and leave in it.

    edit: I also need help getting a progress bar that I can cancel at any time working, I think there are some major flaws with this that need to be worked out, but I would like a progress bar later on. just wondering how hard that will be and if I should do that soon.
     
    Last edited: Sep 4, 2016
  32. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    can you post a screen shot of the grass spawning issue
     
  33. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    for the cancel feature. an easy thing to do is to put an if statement in the raycast loop. if true have it break;
    create a button or key press to change the value for cancel

    bool cancel = false;

    if(cancel == true)
    {
    break;
    }
     
  34. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    I got the code to work!!! it takes for ever to complete the loop, but it worked, here is my screen shot. red and blue are the grass objects
     

    Attached Files:

  35. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    It does take forever that is why I run it in the editor, then I can make changes and it is not slowing down the actual game, However now that you have it working that far make a new plane in blender that is half painted with one material and half painted with another, then test the script on that, My problem is it is supposed to be spawning grass on a certain material, i.e. grass, and it is spawning it everywhere instead of just on the grass material.

    The only idea I have left for getting grass to spawn in the right spot is if the hit position is grass store that Vector3 into an array and when it is done scanning Instantiate all the grass on all the stored Vector's, but that would be a lot of work and if the line if (targetMaterial.color == grassMaterial.color) is not working, why would it work storing the Vector's? so I am out of ideas pretty much. however one thing to note is last night during my testing if any of teh if statements returned false, it would not spawn anything at all, so maybe it is also the opposite if they all return true it spawns them all, but how would I fix something like that? it is already in a for loop which should mean it should not be acting like that to begin with.

    I also need the rays to only hit the cell and to go through everything else. How can I accomplish this? Here is my current code. along with the editor script, just in case.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class FoliageGeneration : MonoBehaviour {
    6.  
    7.     GameObject cell;
    8.     public Material grassMaterial;
    9.     Material targetMaterial;
    10.  
    11.     public float xSize = 45;
    12.     public float ySafe = 5000;
    13.     public float zSize = 45;
    14.  
    15.     Vector3 spawnPoint;
    16.     GameObject environment;
    17.     GameObject environmentCell;
    18.     public GameObject[] foliage;
    19.  
    20.     public void Generate() {
    21.  
    22.         //Set up the parents to be used later.
    23.         InitialParentSetUp();
    24.  
    25.         Debug.Log("Generating");
    26.         //Scan the cell and determine where to place objects.
    27.         for (float x = -(xSize / 2); x <= (xSize / 2); x++)
    28.         {
    29.             for (float z = -(zSize / 2); z <= (zSize / 2); z++)
    30.             {
    31.                 float xPosition = cell.transform.localPosition.x + x;
    32.                 float yPosition = cell.transform.localPosition.y + ySafe;
    33.                 float zPosition = cell.transform.localPosition.z + z;
    34.  
    35.                 Vector3 rayPosition = new Vector3(xPosition, yPosition, zPosition);
    36.                 Debug.Log("Coordinates: " + rayPosition);
    37.                 Ray ray = new Ray(rayPosition, Vector3.down);
    38.                 RaycastHit hit = new RaycastHit();
    39.  
    40.                 Physics.Raycast(ray, out hit);
    41.                 if (hit.collider != null)
    42.                 {
    43.                     if (hit.transform == gameObject.transform)
    44.                     {
    45.                         Debug.Log("Cell Hit: " + hit.transform.name);
    46.                         targetMaterial = hit.collider.GetComponent<Renderer>().sharedMaterial;
    47.                         if (targetMaterial != false)
    48.                         {
    49.                             Debug.Log("Material Hit: " + targetMaterial.name);
    50.                             if (targetMaterial.color == grassMaterial.color)
    51.                             {
    52.                                 targetMaterial.name = grassMaterial.name;
    53.                                 spawnPoint = hit.point;
    54.                                 SpawnFoliage();
    55.                                 Debug.Log("Spawned grass on cell at" + rayPosition);
    56.                             }
    57.                             else Debug.Log("Error 0x0004: Target material does not match");
    58.                         }
    59.                         else Debug.Log("Error 0x0003: Target material could not be loaded");
    60.                     }
    61.                     else Debug.Log("Error 0x0002: Cell scan out of bounds");
    62.                 }
    63.                 else Debug.Log("Error 0x0001: Could not find cell");
    64.             }
    65.         }
    66.     }
    67.  
    68.     public void InitialParentSetUp()
    69.     {
    70.         //Set up the parents to begin spawning objects.
    71.         Debug.Log("Finding parents");
    72.  
    73.         cell = gameObject;
    74.  
    75.         if (gameObject.transform.parent.parent.FindChild("Environment") == null)
    76.         {
    77.             Debug.Log("Error 0x0005: Parent did not already exist");
    78.             environment = new GameObject();
    79.             environment.transform.position = Vector3.zero;
    80.             environment.transform.parent = gameObject.transform.parent.parent;
    81.             environment.transform.name = "Environment";
    82.         }
    83.         else environment = gameObject.transform.parent.parent.FindChild("Environment").gameObject;
    84.  
    85.         if (environment.transform.FindChild(gameObject.name) == null)
    86.         {
    87.             Debug.Log("Error 0x0005: Parent did not already exist");
    88.             environmentCell = new GameObject();
    89.             environmentCell.transform.position = gameObject.transform.position;
    90.             environmentCell.transform.parent = environment.transform;
    91.             environmentCell.transform.name = cell.name;
    92.         }
    93.         else environmentCell = environment.transform.FindChild(gameObject.name).gameObject;
    94.  
    95.         //Clear the existing foliage.
    96.         Debug.Log("Clearing existing foliage");
    97.  
    98.         while (environmentCell.transform.childCount < -1)
    99.         {
    100.             int index = environmentCell.transform.childCount;
    101.             DestroyImmediate(environmentCell.transform.GetChild(index));
    102.         }
    103.  
    104.     }
    105.  
    106.     public void ClearCell()
    107.     {
    108.         InitialParentSetUp();
    109.  
    110.         //Clear the existing foliage.
    111.         Debug.Log("Clearing cell");
    112.  
    113.         while (environmentCell.transform.childCount < -1)
    114.         {
    115.             int index = environmentCell.transform.childCount;
    116.             DestroyImmediate(environmentCell.transform.GetChild(index));
    117.         }
    118.  
    119.         DestroyImmediate(environmentCell);
    120.     }
    121.  
    122.     public void SpawnFoliage()
    123.     {
    124.         int i = Random.Range(0, foliage.Length);
    125.         GameObject spawnedFoliage = foliage[i];
    126.  
    127.         spawnedFoliage = Instantiate(spawnedFoliage);
    128.         spawnedFoliage.transform.position = spawnPoint;
    129.         spawnedFoliage.transform.parent = environmentCell.transform;
    130.         spawnedFoliage.transform.name = foliage[i].name;
    131.     }
    132. }
    133.  
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEditor;
    5.  
    6. [CanEditMultipleObjects]
    7. [CustomEditor(typeof(FoliageGeneration))]
    8. public class ObjectBuilderEditor : Editor
    9. {
    10.     public override void OnInspectorGUI()
    11.     {
    12.         DrawDefaultInspector();
    13.  
    14.         FoliageGeneration foliageGeneration = (FoliageGeneration)target;
    15.         if (GUILayout.Button("Generate"))
    16.         {
    17.             foliageGeneration.Generate();
    18.         }
    19.  
    20.         if (GUILayout.Button("Clear Cell"))
    21.         {
    22.             foliageGeneration.ClearCell();
    23.         }
    24.     }
    25. }
     
    Last edited: Sep 4, 2016
  36. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    in unity, do you have multiple materials attached to the 3d model? I'm not a Blender user, so no model creating for me.
     
  37. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    Yes, it does have multiple materials, I thought that was the whole basis of my problems a while ago, how can I get past that if it is causing issues?
     
    Last edited: Sep 4, 2016
  38. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    What are the chances of you sending me the model and textures?
     
  39. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    Last edited: Sep 4, 2016
  40. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    just drag the cells into the hierarchy and it will place them where they need to be, then place the editor script in the editor folder and the other script on the cells and you should be able to generate and see what they are doing. every single cell follows the same file structure, right down to being shift + c'd to focus on it and being under the mesh part when saving, every one lines itself up automatically if placed in the hierarchy and has been rotated so that in unity its origins rotation is (0 , 0 , 0), I spent a lot of time getting the existing cells in that order so Please, Please do not mess with those to get this to work.

    edit; forgot I screwed up the script again, here is a working version that still had the materials problem. I am renaming the material every time because it renames it on the cell as the regular name but then puts an (Instance) at the end, I need help fixing that issue properly as well, if the way I am renaming it is not good enough.
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class FoliageGeneration : MonoBehaviour {
    7.  
    8.     GameObject cell;
    9.     public Material grassMaterial;
    10.     Material targetMaterial;
    11.  
    12.     public float xSize = 45;
    13.     public float ySafe = 5000;
    14.     public float zSize = 45;
    15.  
    16.     [Range(0, 1)]
    17.     public static double progress = 0.0;
    18.     public static double progressMade = 0.0;
    19.  
    20.     List<Vector3> spawnPoints = new List<Vector3>();
    21.     GameObject environment;
    22.     GameObject environmentCell;
    23.     public GameObject[] foliage;
    24.  
    25.     public void CellScan() {
    26.         InitialParentSetUp();
    27.  
    28.         Debug.Log("Scanning");
    29.  
    30.         progress = 0;
    31.         progressMade = 1 / xSize + zSize;
    32.  
    33.         //Scan the cell and determine where to place objects.
    34.         for (float x = -(xSize / 2); x <= (xSize / 2); x++)
    35.         {
    36.             for (float z = -(zSize / 2); z <= (zSize / 2); z++)
    37.             {
    38.                 float xPosition = cell.transform.localPosition.x + x;
    39.                 float yPosition = cell.transform.localPosition.y + ySafe;
    40.                 float zPosition = cell.transform.localPosition.z + z;
    41.  
    42.                 Vector3 rayPosition = new Vector3(xPosition, yPosition, zPosition);
    43.                 Debug.Log("Coordinates: " + rayPosition);
    44.                 Ray ray = new Ray(rayPosition, Vector3.down);
    45.                 RaycastHit hit = new RaycastHit();
    46.  
    47.                 Physics.Raycast(ray, out hit);
    48.                 if (hit.collider != null)
    49.                 {
    50.                     if (hit.transform == gameObject.transform)
    51.                     {
    52.                         Debug.Log("Cell Hit: " + hit.transform.name);
    53.                         targetMaterial = hit.collider.GetComponent<Renderer>().sharedMaterial;
    54.                         if (targetMaterial != false)
    55.                         {
    56.                             Debug.Log("Material Hit: " + targetMaterial.name);
    57.                             if (targetMaterial.color == grassMaterial.color)
    58.                             {
    59.                                 spawnPoints.Add(hit.point);
    60.                                 progress += progressMade;
    61.                             }
    62.                             else Debug.Log("Error 0x0004: Target material does not match");
    63.                         }
    64.                         else Debug.Log("Error 0x0003: Target material could not be loaded");
    65.                     }
    66.                     else Debug.Log("Error 0x0002: Cell scan out of bounds");
    67.                 }
    68.                 else Debug.Log("Error 0x0001: Could not find cell");
    69.             }
    70.         }
    71.         targetMaterial.name = grassMaterial.name;
    72.         progress = 0.0;
    73.         Generate();
    74.     }
    75.  
    76.     public void InitialParentSetUp()
    77.     {
    78.         Debug.Log("Clearing existing cell data");
    79.         ClearCell();
    80.  
    81.         cell = gameObject;
    82.  
    83.         Debug.Log("Finding parents");
    84.         if (gameObject.transform.parent.parent.FindChild("Environment") == null)
    85.         {
    86.             Debug.Log("Creating environment folder");
    87.             environment = new GameObject();
    88.             environment.transform.position = Vector3.zero;
    89.             environment.transform.parent = gameObject.transform.parent.parent;
    90.             environment.transform.name = "Environment";
    91.         }
    92.         else environment = gameObject.transform.parent.parent.FindChild("Environment").gameObject;
    93.  
    94.         if (environment.transform.FindChild(gameObject.name) == null)
    95.         {
    96.             Debug.Log("Creating cell folder");
    97.             environmentCell = new GameObject();
    98.             environmentCell.transform.position = gameObject.transform.position;
    99.             environmentCell.transform.parent = environment.transform;
    100.             environmentCell.transform.name = cell.name;
    101.         }
    102.         else environmentCell = environment.transform.FindChild(gameObject.name).gameObject;
    103.     }
    104.  
    105.     public void ClearCell()
    106.     {
    107.         if (gameObject.transform.parent.parent.FindChild("Environment") != null)
    108.         {
    109.             GameObject environment = gameObject.transform.parent.parent.FindChild("Environment").gameObject;
    110.             if (environment.transform.FindChild(gameObject.name) != null)
    111.             {
    112.                 GameObject environmentCell = environment.transform.FindChild(gameObject.name).gameObject;
    113.                 DestroyImmediate(environmentCell);
    114.             }
    115.             else Debug.Log("No cell data could be found");
    116.         }
    117.         else Debug.Log("No environment data could be found");
    118.     }
    119.  
    120.     public void Generate()
    121.     {
    122.         Debug.Log("Spawning Foliage");
    123.         progressMade = 1 / spawnPoints.Count;
    124.  
    125.         foreach (Vector3 spawnPoint in spawnPoints) {
    126.             int i = Random.Range(0, foliage.Length);
    127.             GameObject spawnedFoliage = foliage[i];
    128.  
    129.             spawnedFoliage = Instantiate(spawnedFoliage);
    130.             spawnedFoliage.transform.position = spawnPoint;
    131.             spawnedFoliage.transform.parent = environmentCell.transform;
    132.             spawnedFoliage.transform.name = foliage[i].name;
    133.  
    134.             progress += progressMade;
    135.             Debug.Log("Spawned grass on cell at " + spawnPoint);
    136.         }
    137.  
    138.         progress = 0.0;
    139.     }
    140. }
     
    Last edited: Sep 4, 2016
  41. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    the problem has to be on line 52 where I am declaring targetMaterial, I need to find a better way of declaring that based on where the ray hit.
     
  42. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    i've downloaded the files if you wanted to remove them
     
  43. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    Thank you for informing me, i am generally not too protective of that stuff but I removed it just to be safe, Not too many traces of the things I need to protect should be there but just to be safe it's gone now. I think I gave you all the info you should need let me know if I left anything out, I am currently thinking I am going to have to store the triangle the ray hit and go from there, that may be the route I have to go, I am having trouble doing it so far though.
     
  44. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    i hope this is what you want.
    I cut the mesh into submeshs based on the texture that was assigned to it. when the raycast hits. it figures out witch submesh it belongs to. then you just do an if or switch statement if it's part of the grass mesh then add to the spawn list
    and again that ySafe = 5000; was messing things up. I set it to 10, see screen shot

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class FoliageGeneration : MonoBehaviour
    6. {
    7.  
    8.     GameObject cell;
    9.     public Material grassMaterial;
    10.     public Material targetMaterial;
    11.  
    12.     public float xSize = 45;
    13.     public float ySafe = 5000;
    14.     public float zSize = 45;
    15.  
    16.     [Range(0, 1)]
    17.     public static double progress = 0.0;
    18.     //public static double progressMade = 0.0;
    19.  
    20.     List<Vector3> spawnPoints = new List<Vector3>();
    21.     GameObject environment;
    22.     GameObject environmentCell;
    23.     public GameObject[] foliage;
    24.  
    25.     private int[] subMeshesFaceTotals;
    26.     private int totalSubMeshes;
    27.  
    28.  
    29.     public void CellScan()
    30.     {
    31.         MeshFilter mf = (MeshFilter)gameObject.GetComponent(typeof(MeshFilter));
    32.         Mesh mesh = mf.mesh;
    33.      
    34.         totalSubMeshes = mesh.subMeshCount;
    35.         subMeshesFaceTotals = new int[totalSubMeshes];
    36.         for (int i = 0; i < totalSubMeshes; i++)
    37.         {
    38.             subMeshesFaceTotals[i] = mesh.GetTriangles(i).Length / 3;
    39.         }
    40.  
    41.         InitialParentSetUp();
    42.  
    43.         Debug.Log("Scanning");
    44.  
    45.         progress = 0;
    46.         //progressMade = 1 / xSize + zSize;
    47.  
    48.         //Scan the cell and determine where to place objects.
    49.         for (float x = -(xSize / 2); x <= (xSize / 2); x++)
    50.         {
    51.             for (float z = -(zSize / 2); z <= (zSize / 2); z++)
    52.             {
    53.                 float xPosition = cell.transform.localPosition.x + x;
    54.                 float yPosition = cell.transform.localPosition.y + ySafe;
    55.                 float zPosition = cell.transform.localPosition.z + z;
    56.  
    57.                 Vector3 rayPosition = new Vector3(xPosition, yPosition, zPosition);
    58.                 //Debug.Log("Coordinates: " + rayPosition);
    59.                 Ray ray = new Ray(rayPosition, Vector3.down);
    60.                 RaycastHit hit = new RaycastHit();
    61.  
    62.                 Physics.Raycast(ray, out hit);
    63.                 if (hit.collider != null)
    64.                 {
    65.                     if (hit.transform == gameObject.transform)
    66.                     {
    67.                         int hitSubMeshNumber = 0;
    68.                         int maxVal = 0;
    69.  
    70.                         for (int i = 0; i < totalSubMeshes; i++)
    71.                         {
    72.                             maxVal += subMeshesFaceTotals[i];
    73.                          
    74.                             if (hit.triangleIndex <= maxVal - 1)
    75.                             {
    76.                                 hitSubMeshNumber = i + 1;
    77.                                 break;
    78.                             }
    79.                         }
    80.  
    81.                         if (targetMaterial != false)
    82.                         {
    83.                             //Debug.Log("Material Hit: " + targetMaterial.name);
    84.                             if (hitSubMeshNumber == 0)
    85.                             {
    86.                                 //not used
    87.                                 //spawnPoints.Add(hit.point);
    88.                                 //progress += progressMade;
    89.                             }
    90.                             else if (hitSubMeshNumber == 1)
    91.                             {
    92.                                 //Grass
    93.                                 spawnPoints.Add(hit.point);
    94.                             }
    95.                             else if (hitSubMeshNumber == 2)
    96.                             {
    97.                                 //Dirt
    98.                                 //spawnPoints.Add(hit.point);
    99.                             }
    100.                             else if (hitSubMeshNumber == 3)
    101.                             {
    102.                                 //Stone
    103.                                 //spawnPoints.Add(hit.point);
    104.                             }
    105.                             else if (hitSubMeshNumber == 4)
    106.                             {
    107.                                 //Cliff
    108.                                 //spawnPoints.Add(hit.point);
    109.                             }
    110.                             //else Debug.Log("Error 0x0004: Target material does not match");
    111.                         }
    112.                         //else Debug.Log("Error 0x0003: Target material could not be loaded");
    113.                     }
    114.                     //else Debug.Log("Error 0x0002: Cell scan out of bounds");
    115.                 }
    116.                 //else Debug.Log("Error 0x0001: Could not find cell");
    117.             }
    118.         }
    119.         targetMaterial.name = grassMaterial.name;
    120.         progress = 0.0;
    121.         Generate();
    122.     }
    123.  
    124.     public void InitialParentSetUp()
    125.     {
    126.         //Debug.Log("Clearing existing cell data");
    127.         ClearCell();
    128.  
    129.         cell = gameObject;
    130.  
    131.         //Debug.Log("Finding parents");
    132.         if (gameObject.transform.parent.parent.FindChild("Environment") == null)
    133.         {
    134.             //Debug.Log("Creating environment folder");
    135.             environment = new GameObject();
    136.             environment.transform.position = Vector3.zero;
    137.             environment.transform.parent = gameObject.transform.parent.parent;
    138.             environment.transform.name = "Environment";
    139.         }
    140.         else environment = gameObject.transform.parent.parent.FindChild("Environment").gameObject;
    141.  
    142.         if (environment.transform.FindChild(gameObject.name) == null)
    143.         {
    144.             //Debug.Log("Creating cell folder");
    145.             environmentCell = new GameObject();
    146.             environmentCell.transform.position = gameObject.transform.position;
    147.             environmentCell.transform.parent = environment.transform;
    148.             environmentCell.transform.name = cell.name;
    149.         }
    150.         else environmentCell = environment.transform.FindChild(gameObject.name).gameObject;
    151.     }
    152.  
    153.     public void ClearCell()
    154.     {
    155.         if (gameObject.transform.parent.parent.FindChild("Environment") != null)
    156.         {
    157.             GameObject environment = gameObject.transform.parent.parent.FindChild("Environment").gameObject;
    158.             if (environment.transform.FindChild(gameObject.name) != null)
    159.             {
    160.                 GameObject environmentCell = environment.transform.FindChild(gameObject.name).gameObject;
    161.                 DestroyImmediate(environmentCell);
    162.             }
    163.             //else Debug.Log("No cell data could be found");
    164.         }
    165.         //else Debug.Log("No environment data could be found");
    166.     }
    167.  
    168.     public void Generate()
    169.     {
    170.         //Debug.Log("Spawning Foliage");
    171.         //progressMade = 1 / spawnPoints.Count;
    172.  
    173.         foreach (Vector3 spawnPoint in spawnPoints)
    174.         {
    175.             int i = Random.Range(0, foliage.Length);
    176.             GameObject spawnedFoliage = foliage[i];
    177.  
    178.             spawnedFoliage = Instantiate(spawnedFoliage);
    179.             spawnedFoliage.transform.position = spawnPoint;
    180.             spawnedFoliage.transform.parent = environmentCell.transform;
    181.             spawnedFoliage.transform.name = foliage[i].name;
    182.  
    183.             //progress += progressMade;
    184.             //Debug.Log("Spawned grass on cell at " + spawnPoint);
    185.         }
    186.  
    187.         progress = 0.0;
    188.     }
    189. }
     

    Attached Files:

    Last edited: Sep 6, 2016
  45. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,133
    sorry man, i wasn't able to work on it.
     
  46. Yourking77

    Yourking77

    Joined:
    Jan 14, 2016
    Posts:
    303
    No p
    No problem, I did some searching and looking up and figured it out, since every cell had different material orders and if I added a material and everything I had to create a more modular way of figuring out which material was on each cell. your way was sort of fixed, only material 2 could be spawned on, I created a way that finds out if the material hit is the material it is supposed to spawn it on and if so it spawns grass there, I still need a lot of help adding a progress bar but I have been away from this project for the week because I recently ordered this http://pcpartpicker.com/list/dDfKpb, so I have been busy and not too worried about it.