///
    public void Combine()
    {
        /*if (bakeGroundLightingGrass && bakeGroundLightingFoliage) {
         *      Debug.Log ("You can not combine meshes using 2 different materials.");
         *      return;
         * }*/

        if (isStaticallyCombined)
        {
            return;
        }

        Component[] filters        = GetComponentsInChildren(typeof(MeshFilter));
        Matrix4x4   myTransform    = transform.worldToLocalMatrix;
        Hashtable   materialToMesh = new Hashtable();

        for (int i = 0; i < filters.Length; i++)
        {
            MeshFilter filter      = (MeshFilter)filters[i];
            Renderer   curRenderer = filters[i].renderer;

            ///// sample ground normal
            Vector3    objectPos = curRenderer.transform.position;
            RaycastHit hit1;

            if (Physics.Raycast(objectPos + (Vector3.up * GroundMaxDistance * 0.5f), Vector3.down, out hit1, GroundMaxDistance))
            {
                if (debugNormals)
                {
                    Debug.DrawLine(objectPos + (Vector3.up * GroundMaxDistance * 0.5f), objectPos - (GroundMaxDistance * Vector3.up * 0.5f), Color.green, 5.0f, false);
                    if (debugNormals)
                    {
                        Debug.DrawLine(objectPos, objectPos + (hit1.normal), Color.red, 5.0f, false);
                    }

                    // is it terrain? that makes a big difference!
                    if (UnderlayingTerrain)
                    {
                        Vector3 terrainPos = (hit1.point - UnderlayingTerrain.transform.position) / UnderlayingTerrain.terrainData.size.x;
                        //Debug.Log (hit1.point.y);
                        //Debug.Log ( UnderlayingTerrain.SampleHeight(terrainPos) + UnderlayingTerrain.transform.position.y );
                        //Debug.Log (hit1.transform.gameObject.name);
                        //if ( hit1.point.y - UnderlayingTerrain.SampleHeight(terrainPos) < 1.5f && hit1.point.y - UnderlayingTerrain.SampleHeight(terrainPos) > -1.5f  ) {
                        if (hit1.transform.gameObject.name == UnderlayingTerrain.name)
                        {
                            if (debugNormals)
                            {
                                Debug.DrawLine(objectPos, objectPos + (UnderlayingTerrain.terrainData.GetInterpolatedNormal(terrainPos.x, terrainPos.z)), Color.blue, 5.0f, false);
                            }
                            hit1.normal = UnderlayingTerrain.terrainData.GetInterpolatedNormal(terrainPos.x, terrainPos.z);
                        }
                    }
                }
            }
            else
            {
                hit1.normal = new Vector3(0, 1, 0);
                if (debugNormals)
                {
                    Debug.DrawLine(objectPos, objectPos + (1.0f * hit1.normal), Color.yellow, 5.0f, false);
                }
            }


            MeshCombineUtilityAFS.MeshInstance instance = new MeshCombineUtilityAFS.MeshInstance();
            instance.mesh         = filter.sharedMesh;
            instance.groundNormal = hit1.normal;
            instance.scale        = filter.transform.localScale.x;
            instance.pivot        = filter.transform.position;


            // store max height in worldspace
            // Bounds bounds = curRenderer.bounds;
            // store max height in local space
            // Bounds bounds = filter.sharedMesh.bounds;
            // instance.maxHeight = bounds.size.y;

            if (curRenderer != null && curRenderer.enabled && instance.mesh != null)
            {
                instance.transform = myTransform * filter.transform.localToWorldMatrix;
                Material[] materials = curRenderer.sharedMaterials;
                for (int m = 0; m < materials.Length; m++)
                {
                    instance.subMeshIndex = System.Math.Min(m, instance.mesh.subMeshCount - 1);

                    ArrayList objects = (ArrayList)materialToMesh[materials[m]];
                    if (objects != null)
                    {
                        objects.Add(instance);
                    }
                    else
                    {
                        objects = new ArrayList();
                        objects.Add(instance);
                        materialToMesh.Add(materials[m], objects);
                    }
                }

                // handle dynamic combine
                if (Application.isPlaying)
                {
                    if (destroyChildObjectsInPlaymode)
                    {
                        Destroy(curRenderer.gameObject);
                    }
                }
                else
                {
                    if (destroyChildObjectsInPlaymode)
                    {
                        DestroyImmediate(curRenderer.gameObject);
                        isStaticallyCombined = true;
                    }
                    else
                    {
                                                #if UNITY_3_5
                        curRenderer.gameObject.active = false;
                                                #else
                        curRenderer.gameObject.SetActive(false);
                                                #endif
                        isStaticallyCombined = true;
                    }
                }
            }
        }

        foreach (DictionaryEntry de in materialToMesh)
        {
            ArrayList elements = (ArrayList)de.Value;
            MeshCombineUtilityAFS.MeshInstance[] instances = (MeshCombineUtilityAFS.MeshInstance[])elements.ToArray(typeof(MeshCombineUtilityAFS.MeshInstance));

            // We have a maximum of one material, so just attach the mesh to our own game object
            if (materialToMesh.Count == 1)
            {
                // Make sure we have a mesh filter & renderer
                if (GetComponent(typeof(MeshFilter)) == null)
                {
                    gameObject.AddComponent(typeof(MeshFilter));
                }
                if (!GetComponent("MeshRenderer"))
                {
                    gameObject.AddComponent("MeshRenderer");
                }
                MeshFilter filter = (MeshFilter)GetComponent(typeof(MeshFilter));

//				///////
                renderer.material = (Material)de.Key;
                //renderer.enabled = true;

                // check material and set up the combine script automatically
                bakeGroundLightingGrass   = false;
                bakeGroundLightingFoliage = false;
                simplyCombine             = false;

                string result;
                if (Application.isPlaying)
                {
                    result = renderer.material.GetTag("RenderType", true, "");
                    // RenderTags are: AfsGrassModelSingleSided / AfsGrassModel / AtsFoliage
                    if (result == "AfsGrassModel" || result == "AfsGrassModelSingleSided")
                    {
                        bakeGroundLightingGrass = true;
                    }
                    else if (result == "AtsFoliage")
                    {
                        // just foliage of groundlighting?
                        if (renderer.material.HasProperty("_GroundLightingAttunation"))
                        {
                            bakeGroundLightingFoliage = true;
                        }
                        else
                        {
                            simplyCombine = true;
                        }
                    }
                    filter.mesh = MeshCombineUtilityAFS.Combine(instances, bakeGroundLightingGrass, bakeGroundLightingFoliage, randomBrightness, randomPulse, randomBending, randomFluttering, HealthyColor, DryColor, NoiseSpread, bakeScale, simplyCombine, NoiseSpreadFoliage);
                }
                else
                {
                    result = renderer.sharedMaterial.GetTag("RenderType", true, "");
                    // RenderTags are: AfsGrassModelSingleSided / AfsGrassModel / AtsFoliage
                    if (result == "AfsGrassModel" || result == "AfsGrassModelSingleSided")
                    {
                        bakeGroundLightingGrass = true;
                    }
                    else if (result == "AtsFoliage")
                    {
                        // just foliage of groundlighting?
                        if (renderer.sharedMaterial.HasProperty("_GroundLightingAttunation"))
                        {
                            bakeGroundLightingFoliage = true;
                        }
                        else
                        {
                            simplyCombine = true;
                        }
                    }
                    filter.sharedMesh = MeshCombineUtilityAFS.Combine(instances, bakeGroundLightingGrass, bakeGroundLightingFoliage, randomBrightness, randomPulse, randomBending, randomFluttering, HealthyColor, DryColor, NoiseSpread, bakeScale, simplyCombine, NoiseSpreadFoliage);
                }

                //renderer.material = (Material)de.Key;
                renderer.enabled = true;
                if (CastShadows)
                {
                    renderer.castShadows = true;
                }
                else
                {
                    renderer.castShadows = false;
                }
            }
            // We have multiple materials to take care of, build one mesh / gameobject for each material
            // and parent it to this object
            else
            {
                GameObject go = new GameObject("Combined mesh");
                go.transform.parent        = transform;
                go.transform.localScale    = Vector3.one;
                go.transform.localRotation = Quaternion.identity;
                go.transform.localPosition = Vector3.zero;
                go.AddComponent(typeof(MeshFilter));
                go.AddComponent("MeshRenderer");
                go.renderer.material = (Material)de.Key;
                go.layer             = go.transform.parent.gameObject.layer;

//				///////

                // check material and set up the combine script automatically
                bakeGroundLightingGrass   = false;
                bakeGroundLightingFoliage = false;
                simplyCombine             = false;
                string result;
                if (Application.isPlaying)
                {
                    result = go.renderer.material.GetTag("RenderType", true, "");
                }
                else
                {
                    result = go.renderer.sharedMaterial.GetTag("RenderType", true, "");
                }

                // RenderTags are: AfsGrassModelSingleSided / AfsGrassModel / AtsFoliage
                if (result == "AfsGrassModel" || result == "AfsGrassModelSingleSided")
                {
                    bakeGroundLightingGrass = true;
                }
                else if (result == "AtsFoliage")
                {
                    // just foliage of groundlighting?
                    if (Application.isPlaying)
                    {
                        if (go.renderer.material.HasProperty("_GroundLightingAttunation"))
                        {
                            bakeGroundLightingFoliage = true;
                        }
                        else
                        {
                            simplyCombine = true;
                        }
                    }
                    else
                    {
                        if (go.renderer.sharedMaterial.HasProperty("_GroundLightingAttunation"))
                        {
                            bakeGroundLightingFoliage = true;
                        }
                        else
                        {
                            simplyCombine = true;
                        }
                    }
                }
//				///////

                MeshFilter filter = (MeshFilter)go.GetComponent(typeof(MeshFilter));
                if (Application.isPlaying)
                {
                    filter.mesh = MeshCombineUtilityAFS.Combine(instances, bakeGroundLightingGrass, bakeGroundLightingFoliage, randomBrightness, randomPulse, randomBending, randomFluttering, HealthyColor, DryColor, NoiseSpread, bakeScale, simplyCombine, NoiseSpreadFoliage);
                }
                else
                {
                    filter.sharedMesh = MeshCombineUtilityAFS.Combine(instances, bakeGroundLightingGrass, bakeGroundLightingFoliage, randomBrightness, randomPulse, randomBending, randomFluttering, HealthyColor, DryColor, NoiseSpread, bakeScale, simplyCombine, NoiseSpreadFoliage);
                }
            }
        }
    }
	public void Combine () {
		if (isStaticallyCombined) {
			return;	
		}
		Component[] filters = GetComponentsInChildren(typeof(MeshFilter));
		Matrix4x4 myTransform = transform.worldToLocalMatrix;
		Hashtable materialToMesh= new Hashtable();
		
		for (int i=0;i<filters.Length;i++) {
			MeshFilter filter = (MeshFilter)filters[i];
			Renderer curRenderer  = filters[i].GetComponent<Renderer>();
			
			// Sample ground normal
			Vector3 objectPos = curRenderer.transform.position;
			RaycastHit hit1;
			if (Physics.Raycast(objectPos + (Vector3.up * GroundMaxDistance * 0.5f), Vector3.down, out hit1, GroundMaxDistance)) {
				if(debugNormals) {
					Debug.DrawLine(objectPos + (Vector3.up * GroundMaxDistance * 0.5f), objectPos - (GroundMaxDistance * Vector3.up * 0.5f), Color.green, 5.0f, false);
					if(debugNormals) {
						Debug.DrawLine(objectPos, objectPos + (hit1.normal), Color.red, 5.0f, false);
					}
					// Is it terrain? That makes a big difference!
					if (UnderlayingTerrain) {
						Vector3 terrainPos = (hit1.point - UnderlayingTerrain.transform.position) / UnderlayingTerrain.terrainData.size.x;
						if (hit1.transform.gameObject.name == UnderlayingTerrain.name ){
							if(debugNormals) {
								Debug.DrawLine(objectPos, objectPos + (UnderlayingTerrain.terrainData.GetInterpolatedNormal(terrainPos.x, terrainPos.z)), Color.blue, 5.0f, false);
							}
							hit1.normal = UnderlayingTerrain.terrainData.GetInterpolatedNormal(terrainPos.x, terrainPos.z);
						}
					}
				}
			}
			else {
				hit1.normal = new Vector3 (0,1,0);
				if(debugNormals) {
					Debug.DrawLine(objectPos, objectPos + (1.0f * hit1.normal), Color.yellow, 5.0f, false);
				}
			}
			MeshCombineUtilityAFS.MeshInstance instance = new MeshCombineUtilityAFS.MeshInstance ();
			instance.mesh = filter.sharedMesh;
			instance.groundNormal = hit1.normal;
			instance.scale = filter.transform.localScale.x;
			instance.pivot = filter.transform.position;
			
			// Store max height in worldspace
			// Bounds bounds = curRenderer.bounds;
			// store max height in local space
			// Bounds bounds = filter.sharedMesh.bounds;
			// instance.maxHeight = bounds.size.y;
			
			if (curRenderer != null && curRenderer.enabled && instance.mesh != null) {
				instance.transform = myTransform * filter.transform.localToWorldMatrix;
				Material[] materials = curRenderer.sharedMaterials;
				for (int m=0;m<materials.Length;m++) {
					instance.subMeshIndex = System.Math.Min(m, instance.mesh.subMeshCount - 1);
					ArrayList objects = (ArrayList)materialToMesh[materials[m]];
					if (objects != null) {
						objects.Add(instance);
					}
					else
					{
						objects = new ArrayList ();
						objects.Add(instance);
						materialToMesh.Add(materials[m], objects);
					}
				}
				// Handle dynamic combine
				if (Application.isPlaying) {
					if (destroyChildObjectsInPlaymode) {
						Destroy(curRenderer.gameObject);
					}
				}
				else {
					if (destroyChildObjectsInPlaymode) {
						DestroyImmediate(curRenderer.gameObject);
						isStaticallyCombined = true;
					}
					else {
						#if UNITY_3_5
						curRenderer.gameObject.active = false;
						#else
						curRenderer.gameObject.SetActive(false);
						#endif
						isStaticallyCombined = true;
					}
				}
			}
		}
	
		foreach (DictionaryEntry de in materialToMesh) {
			ArrayList elements = (ArrayList)de.Value;
			MeshCombineUtilityAFS.MeshInstance[] instances = (MeshCombineUtilityAFS.MeshInstance[])elements.ToArray(typeof(MeshCombineUtilityAFS.MeshInstance));
			// We have a maximum of one material, so just attach the mesh to our own game object
			if (materialToMesh.Count == 1)
			{
				// Make sure we have a mesh filter & renderer
				if (GetComponent(typeof(MeshFilter)) == null)
					gameObject.AddComponent(typeof(MeshFilter));
				if (!GetComponent("MeshRenderer"))
					gameObject.AddComponent<MeshRenderer>();
				MeshFilter filter = (MeshFilter)GetComponent(typeof(MeshFilter));
				GetComponent<Renderer>().material = (Material)de.Key;
				// Check material and set up the combine script automatically
				bakeGroundLightingGrass = false;
				bakeGroundLightingFoliage = false;
				simplyCombine = false;
				string result;
				if (Application.isPlaying) {
					result = GetComponent<Renderer>().material.GetTag("AfsMode", true, "");
					// RenderTags are: AfsGrassModelSingleSided / AfsGrassModel / AtsFoliage
					if (result == "Grass" || result == "AfsGrassModelSingleSided" ) {
						bakeGroundLightingGrass = true;
					}
					else if (result == "Foliage") {
						// Just foliage of groundlighting?
						if (GetComponent<Renderer>().material.HasProperty("_GroundLightingAttunation")) {
							bakeGroundLightingFoliage = true;
						}
						else {
							simplyCombine = true;
						}
						if (GetComponent<Renderer>().material.GetFloat("_BendingControls") == 1.0f) {
							useUV4 = true;
						}
					}
					filter.mesh = MeshCombineUtilityAFS.Combine(instances, bakeGroundLightingGrass, bakeGroundLightingFoliage, randomBrightness, randomPulse, randomBending, randomFluttering, HealthyColor, DryColor, NoiseSpread, bakeScale, simplyCombine, NoiseSpreadFoliage, createUniqueUV2playmode, useUV4);
				}
				else {
					result = GetComponent<Renderer>().sharedMaterial.GetTag("AfsMode", true, "");
					// RenderTags are: AfsGrassModelSingleSided / AfsGrassModel / AtsFoliage
					if (result == "Grass" || result == "AfsGrassModelSingleSided" ) {
						bakeGroundLightingGrass = true;
					}
					else if (result == "Foliage") {
						// just foliage of groundlighting?
						if (GetComponent<Renderer>().sharedMaterial.HasProperty("_GroundLightingAttunation")) {
							bakeGroundLightingFoliage = true;
						}
						else {
							simplyCombine = true;
						}
						if (GetComponent<Renderer>().material.GetFloat("_BendingControls") == 1.0f) {
							useUV4 = true;
						}
					}
					filter.sharedMesh = MeshCombineUtilityAFS.Combine(instances, bakeGroundLightingGrass, bakeGroundLightingFoliage, randomBrightness, randomPulse, randomBending, randomFluttering, HealthyColor, DryColor, NoiseSpread, bakeScale, simplyCombine, NoiseSpreadFoliage, createUniqueUV2, useUV4);	
				}
				GetComponent<Renderer>().enabled = true;
				if (CastShadows) {
					GetComponent<Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
				}
				else {
					GetComponent<Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;	
				}
				if(UseLightprobes) {
					GetComponent<Renderer>().useLightProbes = true;
				}
				else {
					GetComponent<Renderer>().useLightProbes = false;	
				}
			}
			// We have multiple materials to take care of, build one mesh / gameobject for each material
			// and parent it to this object
			else
			{
				GameObject go = new GameObject("Combined mesh");
				go.transform.parent = transform;
				go.transform.localScale = Vector3.one;
				go.transform.localRotation = Quaternion.identity;
				go.transform.localPosition = Vector3.zero;
				go.AddComponent(typeof(MeshFilter));
				go.AddComponent<MeshRenderer>();
				go.GetComponent<Renderer>().material = (Material)de.Key;
				go.layer = go.transform.parent.gameObject.layer;
				// Check material and set up the combine script automatically
				bakeGroundLightingGrass = false;
				bakeGroundLightingFoliage = false;
				simplyCombine = false;
				string result;
				if (Application.isPlaying) {
					result = go.GetComponent<Renderer>().material.GetTag("AfsMode", true, "");
				}
				else {
					result = go.GetComponent<Renderer>().sharedMaterial.GetTag("AfsMode", true, "");	
				}
				// RenderTags are: AfsGrassModelSingleSided / AfsGrassModel / AtsFoliage
				if (result == "Grass" || result == "AfsGrassModelSingleSided" ) {
					bakeGroundLightingGrass = true;
				}
				else if (result == "Foliage") {
					// Just foliage of groundlighting?
					if (Application.isPlaying) {
						if (go.GetComponent<Renderer>().material.HasProperty("_GroundLightingAttunation")) {
							bakeGroundLightingFoliage = true;
						}
						else {
							simplyCombine = true;
						}
						if (go.GetComponent<Renderer>().material.GetFloat("_BendingControls") == 1.0f) {
							useUV4 = true;
						}
					}
					else {
						if (go.GetComponent<Renderer>().sharedMaterial.HasProperty("_GroundLightingAttunation")) {
							bakeGroundLightingFoliage = true;
						}
						else {
							simplyCombine = true;
						}
						if (go.GetComponent<Renderer>().sharedMaterial.GetFloat("_BendingControls") == 1.0f) {
							useUV4 = true;
						}	
					}
				}
				
				MeshFilter filter = (MeshFilter)go.GetComponent(typeof(MeshFilter));
				if (Application.isPlaying) {
					filter.mesh = MeshCombineUtilityAFS.Combine(instances, bakeGroundLightingGrass, bakeGroundLightingFoliage, randomBrightness, randomPulse, randomBending, randomFluttering, HealthyColor, DryColor, NoiseSpread, bakeScale, simplyCombine, NoiseSpreadFoliage, createUniqueUV2playmode, useUV4);
				}
				else {
					filter.sharedMesh = MeshCombineUtilityAFS.Combine(instances, bakeGroundLightingGrass, bakeGroundLightingFoliage, randomBrightness, randomPulse, randomBending, randomFluttering, HealthyColor, DryColor, NoiseSpread, bakeScale, simplyCombine, NoiseSpreadFoliage, createUniqueUV2, useUV4);
				}
				// Copy settings
				if (CastShadows) {
					go.GetComponent<Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
				}
				else {
					go.GetComponent<Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
				}
				if(UseLightprobes) {
					go.GetComponent<Renderer>().useLightProbes = true;
				}
				else {
					go.GetComponent<Renderer>().useLightProbes = false;	
				}
			}
		}
	}