Ejemplo n.º 1
0
        // Parse the sentence, load symbol implementations and find the next module to execute.
        // One module is executed at a time, and an internal pointer is adjusted to for the next iteration.
        public bool ProcessNextModule(Module previous, Sentence sentence,
                                      SerializableDictionary <char, GameObject> implementation, RuleSet rules, ParameterBundle bundle, bool baked)
        {
            if (dead)
            {
                return(false);
            }
            Profiler.BeginSample("LSystem.Module.ProcessNextModule");

            GameObject module;
            char       symbol = '\0';

            do
            {
                if (!sentence.HasNext())
                {
                    sentence = rules.NextGeneration(sentence);

                    if (!bundle.Set("Sentence", sentence))
                    {
                        Debug.LogError("Cannot set 'Sentence' parameter in GetAndExecuteModule", gameObject);
                    }

                    int generation;
                    int iterations;
                    if (bundle.Get("Generation", out generation))
                    {
                        generation++;
                        if (bundle.Get("Iterations", out iterations))
                        {
                            if (generation > iterations)
                            {
                                //Max iterations reached.
                                return(false);
                            }
                        }
                        if (!bundle.Set("Generation", generation))
                        {
                            Debug.LogError("Cannot set 'Generation' parameter in GetAndExecuteModule", gameObject);
                        }
                    }
                    else
                    {
                        Debug.LogError("Cannot get 'Generation' parameter in GetAndExecuteModule", gameObject);
                    }
                }
                symbol = sentence.Next();
                if (symbol == '\0')
                {
                    return(false);                 //Sentence is empty! Caused if rules do not generate anything from previous
                }
            } while (!implementation.TryGetValue(symbol, out module));
            KeyValuePair <GameObject, Sentence> newPair = new KeyValuePair <GameObject, Sentence>(module, sentence);

            Profiler.EndSample();

            ExecuteModule(previous, newPair, bundle, symbol, baked);

            return(true);
        }
Ejemplo n.º 2
0
        public bool GetPositionParameters(ParameterBundle bundle, out int generation, out Quaternion rotation)
        {
            bool success = true;

            if (!bundle.Get("Generation", out generation))
            {
                success = false;
                Debug.LogError("Default parameter 'Generation' missing.", gameObject);
            }
            if (!bundle.Get("Rotation", out rotation))
            {
                success = false;
                Debug.LogError("Default parameter 'Rotation' missing.", gameObject);
            }
            return(success);
        }
Ejemplo n.º 3
0
        // Retrial for parameters common to most LSystems are wrapped here for convenience.
        public bool GetCoreParameters(ParameterBundle bundle, out Sentence sentence, out CharGameObjectDict implementations, out RuleSet rules)
        {
            bool success = true;

            if (!bundle.Get("Sentence", out sentence))
            {
                success = false;
                Debug.LogError("Default parameter 'Sentence' missing.", gameObject);
            }
            if (!bundle.Get("Implementations", out implementations))
            {
                success = false;
                Debug.LogError("Default parameter 'Implementations' missing.", gameObject);
            }
            if (!bundle.Get("RuleSet", out rules))
            {
                success = false;
                Debug.LogError("Default parameter 'RuleSet' missing.", gameObject);
            }
            return(success);
        }
Ejemplo n.º 4
0
        // Encapsulates common functionality between Bake and Execute.
        protected void AnyExecute(ParameterBundle bundle)
        {
            //try get relevant prams.
            bool               fatal = false;
            Sentence           sentence;
            CharGameObjectDict implementations;
            RuleSet            rules;

            if (!GetCoreParameters(bundle, out sentence, out implementations, out rules))
            {
                fatal = true;
            }

            // Perform rotation on transform based.
            // Note that many rotations are not easily possible with this method. Needs to be improved.
            Quaternion rotation;

            if (bundle.Get("Rotation", out rotation))
            {
                //apply pitch yaw and roll to the rotation
                rotation = rotation * Quaternion.Euler(new Vector3(Random.Range(eulerAnglesMin.x, eulerAnglesMax.x),
                                                                   Random.Range(eulerAnglesMin.y, eulerAnglesMax.y),
                                                                   Random.Range(eulerAnglesMin.z, eulerAnglesMax.z)));
                bundle.Set("Rotation", rotation);
            }
            else
            {
                Debug.LogWarning("Default parameter 'Rotation' missing. Skipping Rotation", gameObject);
            }
            if (!fatal)
            {
                //Call next module
                if (baked)
                {
                    BakeNextModule(transform, sentence, implementations, rules, bundle);
                }
                else
                {
                    EnqueueProcessNextModule(transform, sentence, implementations, rules, bundle);
                }
            }
            Destroy(gameObject); //once rotation  and next module clled we can destroy the object.
        }
Ejemplo n.º 5
0
        // Entry point when pre-baking LSystem.
        public override void Bake(ParameterBundle bundle)
        {
            //Get parameters
            Quaternion         rotation;
            Sentence           sentence;
            CharGameObjectDict implementations;
            int     generation;
            RuleSet rules;

            // Check valid state for growing
            if (!GetCoreParameters(bundle, out sentence, out implementations, out rules) ||
                !GetPositionParameters(bundle, out generation, out rotation))
            {
                return;
            }

            // Setup Renderer
            if ((filter = gameObject.GetComponent <MeshFilter>()) == null)
            {
                filter = gameObject.AddComponent <MeshFilter>();
            }
            if ((branchRenderer = gameObject.GetComponent <MeshRenderer>()) == null)
            {
                branchRenderer = gameObject.AddComponent <MeshRenderer>();
            }
            branchRenderer.material = branchMaterial;

            //Match start position to previous position. As growth progresses position will be offset
            //While rotation stays the same
            transform.position = previous.transform.position;
            transform.rotation = rotation;

            // Try and pick up length and radius where last branch left off.
            float length, radius;

            if (bundle.Get("BranchLength", out length))
            {
                startLength = length;
            }
            if (bundle.Get("BranchRadius", out radius))
            {
                startRadius = radius;
            }
            if (bundle.Get("BranchFaceNum", out faces))
            {
                startFaceNum = faces;
            }

            int branchIndex = 0;

            bundle.Get("BakedBranchIndex", out branchIndex);

            GrowLoopCallback growLoopCallback;

            bundle.Get("GrowLoopCallback", out growLoopCallback);

            radius = startRadius;
            length = startLength;
            faces  = startFaceNum;

            // Since we don't want to continue drawing where it doesn't matter!
            // Note that future emergence is killed here.
            if (length < lengthCutoff || radius < radiusCutoff)
            {
                return;
            }

            // Update end object to final position and execute
            if (endObject != null)
            {
                endObject = (GameObject)Instantiate(endObject, transform);
                Module mod = endObject.GetComponent <Module>();
                if (mod != null)
                {
                    AssignPrevious(mod, this);
                    if (mod.GetType() != typeof(Seed))
                    {
                        Kill(mod);
                        SetPrefabIdentifier(mod);
                        mod.Bake(bundle);
                    }
                }
                endObject.transform.rotation = rotation;
            }

            //TODO: used to be the heading.. does this work?
            transform.position += transform.up * length;

            // Bake or reuse mesh.
            // Meshes are reused based on prefabIdentifier
            bool meshNeeded = false;
            List <MeshFilter> sharedFilters;

            if (bakedPrefabFilters.TryGetValue(prefabIdentifier, out sharedFilters))
            {
                if (sharedFilters.Count > branchIndex)
                {
                    filter.mesh = sharedFilters[branchIndex].sharedMesh;
                }
                else
                {
                    meshNeeded = true;
                }
            }
            else
            {
                bakedPrefabFilters.Add(prefabIdentifier, new List <MeshFilter>());
                meshNeeded = true;
            }

            if (meshNeeded)
            {
                float distance = Vector3.Distance(transform.position, previous.transform.position);
                bottomRadius = startRadius;
                UpdateBranch(Vector3.up * -distance, distance, bottomRadius * bottomRadiusMultiplier,
                             radius * radiusChangeCoefficient, Mathf.Max(2, (int)(faces)));
            }

            if (endObject != null)
            {
                endObject.transform.position = transform.position;
                endObject.transform.rotation = rotation;
            }

            // Update parameters for next branch
            bundle.SetOrPut("BranchLength", length * lengthChangeCoefficient);
            bundle.SetOrPut("BranchRadius", radius * radiusChangeCoefficient);
            bundle.SetOrPut("BranchFaceNum", faces * faceNumChangeCoefficient);

            bundle.SetOrPut("BakedBranchIndex", ++branchIndex);

            if (setStaticOnComplete)
            {
                gameObject.isStatic = true;
            }

            BakeNextModule(transform, sentence, implementations, rules, bundle);
        }
Ejemplo n.º 6
0
        IEnumerator Grow(ParameterBundle bundle)
        {
            //Get parameters
            Quaternion         rotation;
            Sentence           sentence;
            CharGameObjectDict implementations;
            int     generation;
            RuleSet rules;

            // Check valid state for growing
            if (!GetCoreParameters(bundle, out sentence, out implementations, out rules) ||
                !GetPositionParameters(bundle, out generation, out rotation))
            {
                yield break;
            }

            // Setup Renderer
            if ((filter = gameObject.GetComponent <MeshFilter>()) == null)
            {
                filter = gameObject.AddComponent <MeshFilter>();
            }
            if ((branchRenderer = gameObject.GetComponent <MeshRenderer>()) == null)
            {
                branchRenderer = gameObject.AddComponent <MeshRenderer>();
            }
            branchRenderer.material = branchMaterial;

            // Match start position to previous position. As growth progresses position will be offset
            // While rotation stays the same
            transform.position = previous.transform.position;
            transform.rotation = rotation;

            // Try and pick up length and radius where last branch left off.
            float length, radius, growSpeed;

            if (bundle.Get("BranchLength", out length))
            {
                startLength = length;
            }
            if (bundle.Get("BranchRadius", out radius))
            {
                startRadius = radius;
            }
            if (bundle.Get("BranchGrowSpeed", out growSpeed))
            {
                startGrowSpeed = growSpeed;
            }
            if (bundle.Get("BranchFaceNum", out faces))
            {
                startFaceNum = faces;
            }

            GrowLoopCallback growLoopCallback;

            bundle.Get("GrowLoopCallback", out growLoopCallback);

            radius    = startRadius;
            length    = startLength;
            growSpeed = startGrowSpeed;
            faces     = startFaceNum;

            // Since we don't want to continue drawing where it doesn't matter!
            // Note that future emergence is killed here.
            if (length < lengthCutoff || radius < radiusCutoff)
            {
                yield break;
            }

            if (endObject != null)
            {
                endObject = (GameObject)Instantiate(endObject, transform);
                Module mod = endObject.GetComponent <Module>();
                if (mod != null)
                {
                    AssignPrevious(mod, this);
                    if (mod.GetType() != typeof(Seed))
                    {
                        Kill(mod);
                        mod.Execute(bundle);
                    }
                }
                endObject.transform.rotation = rotation;
            }

            // Update mesh and extend transform towards final position
            float distance = Vector3.Distance(transform.position, previous.transform.position);

            while (distance < length)
            {
                float completionRatio = distance / length;
                transform.position += transform.up * Mathf.Min(/*heading.magnitude * */ Time.deltaTime * Mathf.Lerp(startGrowSpeed,
                                                                                                                    growSpeed * growSpeedChangeCoefficient, completionRatio), length);
                distance = Vector3.Distance(transform.position, previous.transform.position);

                bottomRadius = Mathf.Lerp(0, startRadius, completionRatio);
                UpdateBranch(Vector3.up * -distance, distance, bottomRadius * bottomRadiusMultiplier,
                             topRadius * topRadiusMultiplier, Mathf.Max(2, (int)(faces)));
                if (growLoopCallback != null)
                {
                    growLoopCallback(bottomRadius);
                }

                if (endObject != null)
                {
                    endObject.transform.position = transform.position;
                    endObject.transform.rotation = rotation;
                }

                yield return(null);
            }
            bottomRadius = startRadius;

            // Update parameters for next branch
            bundle.SetOrPut("BranchLength", length * lengthChangeCoefficient);
            bundle.SetOrPut("BranchRadius", radius * radiusChangeCoefficient);
            bundle.SetOrPut("BranchGrowSpeed", growSpeed * growSpeedChangeCoefficient);
            bundle.SetOrPut("BranchFaceNum", faces * faceNumChangeCoefficient);

            // For coordination between branches
            growLoopCallback = NextBranchGrowLoopCallback;
            bundle.SetOrPut("GrowLoopCallback", growLoopCallback);

            if (setStaticOnComplete)
            {
                gameObject.isStatic = true;
            }

            EnqueueProcessNextModule(transform, sentence, implementations, rules, bundle);
        }
Ejemplo n.º 7
0
        public override void Bake(ParameterBundle bundle)
        {
            if (dead)
            {
                return;
            }

            Quaternion rotation;

            if (!bundle.Get("Rotation", out rotation))
            {
                //TODO: used to be Vector3.up. Equivelent?
                rotation = Quaternion.identity;
            }

            Vector3   position = transform.position;
            Transform parent   = null;

            if (previous != null)
            {
                position = previous.transform.position;
                parent   = previous.transform;
            }

            Quaternion bakedRot = Quaternion.Euler(UnityEngine.Random.Range(bakedRotationMin.x, bakedRotationMax.x),
                                                   UnityEngine.Random.Range(bakedRotationMin.y, bakedRotationMax.y),
                                                   UnityEngine.Random.Range(bakedRotationMin.z, bakedRotationMax.z));

            float   s     = UnityEngine.Random.Range(bakedScaleMin, bakedScaleMax);
            Vector3 scale = new Vector3(s, s, s);

            // try get existing instance
            GameObject prototypeInstance;
            GameObject instance;

            if (bakedProtoypes.TryGetValue(prefabIdentifier, out prototypeInstance))
            {
                if (parent == null)
                {
                    parent = transform;
                }
                instance = (GameObject)Instantiate(prototypeInstance, position, bakedRot, parent);
                instance.transform.localScale = scale;
                instance.name = "Instance_" + prefabIdentifier;

                instance.transform.rotation = rotation;
                instance.SetActive(true);

                if (bakedScaleOnSpawn)
                {
                    StartCoroutine(BakedScale(instance));
                }
            }
            else
            {
                //TODO: This could be done off-line.
                AnyExecute(bundle); //bake

                transform.position = Vector3.zero;
                transform.rotation = Quaternion.identity;
                transform.parent   = null;

                // The current object contains the original mesh data so it needs to become the prototypical instance. we create a copy of it to continue.
                instance = (GameObject)Instantiate(gameObject, position, rotation, parent);
                instance.transform.localScale = scale;
                instance.name = "InitialInstance_" + prefabIdentifier;

                if (bakedScaleOnSpawn)
                {
                    StartCoroutine(BakedScale(instance));
                }

                //Kill initial instance module since its already generated.
                Module initialInstanceModule = instance.GetComponent <Module>();
                if (initialInstanceModule != null)
                {
                    Kill(initialInstanceModule);
                }

                gameObject.name = "Prototype_" + prefabIdentifier;
                Kill(this); //the prototype must not be able to create new instances(they will do the same... etc)
                gameObject.hideFlags = HideFlags.HideInHierarchy;

                bakedProtoypes.Add(prefabIdentifier, gameObject);
                gameObject.SetActive(false);
            }
        }
Ejemplo n.º 8
0
        // Run the update loop to grow the mesh when not baked
        IEnumerator Grow(ParameterBundle bundle)
        {
            //Get parameters
            Quaternion         rotation;
            Sentence           sentence;
            CharGameObjectDict implementations;
            int     generation;
            RuleSet rules;

            // Check valid state for growing
            if (!GetCoreParameters(bundle, out sentence, out implementations, out rules) ||
                !GetPositionParameters(bundle, out generation, out rotation))
            {
                yield break;
            }

            float medialSize, lateralSize, growTime;

            if (bundle.Get("LeafMedialSize", out medialSize))
            {
                startMedialSize = medialSize;
            }
            if (bundle.Get("LeafLateralSize", out lateralSize))
            {
                startLateralSize = lateralSize;
            }
            if (bundle.Get("LeafGrowTime", out growTime))
            {
                startGrowTime = growTime;
            }

            transform.position = previous.transform.position;
            transform.rotation = rotation;

            float time = 1f;

            if (animate)
            {
                time = 0f;
            }
            while (time < startGrowTime)
            {
                time += Time.deltaTime;
                UpdateMesh(time / startGrowTime, offset);
                yield return(null);
            }

            bundle.SetOrPut("LeafMedialSize", startMedialSize * medialSizeChangeCoefficient);
            bundle.SetOrPut("LeafLateralSize", startLateralSize * lateralSizeChangeCoefficient);
            bundle.SetOrPut("LeafGrowTime", startGrowTime * growTimeChangeCoefficient);

            if (setStaticOnComplete)
            {
                gameObject.isStatic = true;
            }

            EnqueueProcessNextModule(transform, sentence, implementations, rules, bundle);

            if (continuousUpdate)
            {
                while (true)
                {
                    UpdateMesh(1f, offset);
                    yield return(null);
                }
            }
        }