How do I replace Line Renderers with meshes or prefabs/Instantiate meshes or prefabs on top of Line Renderers?

34 Views Asked by At

I am working on an L system to generate trees, and my algorithm works fine. I made it so that that the L-System I'm working on displays itself as Line Renderers. The full code is as follows:

public class TransformInfo{
    public Vector3 position;
    public Quaternion rotation;
}


public class LSystemScript : MonoBehaviour{
    [SerializeField] private float iterations;
    [SerializeField] private GameObject branch;
    [SerializeField] private GameObject leaf;
    [SerializeField] private float length;
    [SerializeField] private float angle ;
    [SerializeField] private float rotationAngle;
    [SerializeField] private GameObject treeMesh;
    private const string axiom = "X";

    private Stack<TransformInfo> transformStack;
    private Dictionary<char, string> rules;
    private string currentString = string.Empty;
    void Start(){
        transformStack = new Stack<TransformInfo>();
        angle = UnityEngine.Random.Range(10, 60);
        iterations = UnityEngine.Random.Range(3, 5);
        rotationAngle = UnityEngine.Random.Range(0, 90);
        length = UnityEngine.Random.Range(0.01f, 0.1f);
        rules = new Dictionary<char, string> {
            { 'X',"[F-[[X]+X]+F[+FX]-X]" },
             //{ 'X', "[FX[+F[-FX]FX][-F-FXFX]]" }, //This generates interesting shrubs
            { 'F',"FF"}
        };

        Generate();
        //ReplaceWithMesh();
        
    }
    private void ReplaceWithMesh(){
        GameObject[] gos = GameObject.FindGameObjectsWithTag("Tree");
        foreach (GameObject g in gos) {
            Quaternion gq = g.transform.rotation;
            Instantiate(treeMesh, new Vector3(g.transform.position.x, g.transform.position.y, g.transform.position.z), gq);
        }
    }
    private void Generate() {
        currentString = axiom;
        StringBuilder sb = new StringBuilder();

        for(int i=0; i < iterations; i++) {
            //loop through current string and create a new string based on the rules
            foreach (char c in currentString){
                sb.Append(rules.ContainsKey(c) ? rules[c] : c.ToString());
            }

            //Set currentString to the new string we just generated.
            currentString = sb.ToString();
            sb = new StringBuilder();
        }

        


        //foreach (char c in currentString)
        for (int c = 0; c < currentString.Length; c++){ 
            switch(currentString[c])
            {
                case 'F':
                    //Draw a straight line
                    Vector3 initialPosition = transform.position;
                    transform.Translate(Vector3.up * length);
                    GameObject treeSegment;
                    if (currentString[(c + 1) % currentString.Length] == 'X' || 
                        currentString[(c + 3) % currentString.Length] == 'F' && currentString[(c + 4) % currentString.Length] == 'X')
                    {
                         treeSegment = Instantiate(leaf);
                    }
                    else{
                         treeSegment = Instantiate(branch);
                        transform.Rotate(0, rotationAngle, 0);
                    }
                    treeSegment.GetComponent<LineRenderer>().SetPosition(0, initialPosition);
                    treeSegment.GetComponent<LineRenderer>().SetPosition(1, transform.position);
                    break;

                case 'X':
                    //does nothing, generate more Fs
                    break;

                case '+':
                    //Rotates clockwise
                    transform.Rotate(Vector3.back * angle);
                    break;

                case '-':
                    //Rotates counter-clockwise
                    transform.Rotate(Vector3.forward * angle);
                    break;

                case '[':
                    //Save current transform info
                    transformStack.Push(new TransformInfo(){
                        position = transform.position,
                        rotation = transform.rotation
                    });
                    break;

                case ']':
                    //Return to our previously saved transform info
                    TransformInfo ti = transformStack.Pop();
                    transform.position = ti.position;
                    transform.rotation = ti.rotation;
                    break;

                default:
                    throw new InvalidOperationException("Invalid L-tree operation");
            }
        }
    }
}

The next step is to replace the Line Renderer with meshes/prefabs. But nothing I tried seems to be working.

I tried simply replacing the line renderers with meshes, as well as tagging the line prefabs, and using the their tags to get their location and rotation and instantiate prefabs in their place. But that didn't seem to work either.

1

There are 1 best solutions below

0
On

The first thing I notice is that iterations is a float. This is not a bug, but you should probably set it to an integer unless you are using it somewhere else.

So if you want to create a mesh from a bunch of lines, that is probably more difficult than you think. The most straightforward solution would be to convert every point to lattice points and then do some marching cubes shenanigans, but I don't recommend that.

If you would like to simply instantiate a new gameobject, like your function currently does, using Instantiate is the right way to go about it. I don't understand why you are using new Vector3(g.transform.position.x, g.transform.position.y, g.transform.position.z) instead of g.transform.position, but that shouldn't cause any issues.

If you would like to create a copy of a gameobject like I said, your issue is probably with the TreeMesh prefab, or something similar.

Hope I could help, sorry if I couldn't, I'm new to this as well.