Beispiel #1
0
		public static IEnumerator Apply(CoordRect rect, Terrain terrain, object dataBox, Func<float,bool> stop= null)
		{
			#if __MEGASPLAT__
			//loading objects
			MegaSplatData tuple = (MegaSplatData)dataBox;
			if (tuple == null)
				yield break;

			//terrain.materialType = Terrain.MaterialType.Custom; //it's already done with MapMagic
			//terrain.materialTemplate = new Material(tuple.template);

			// TODO: We should pool these textures instead of creating and destroying them!

			int res = MapMagic.instance.resolution;


			//control texture
			var control = new Texture2D(res, res, MegaSplatOutput.formatARGB? TextureFormat.ARGB32 : TextureFormat.RGBA32, false, true);
			control.wrapMode = TextureWrapMode.Clamp;
			control.filterMode = FilterMode.Point;
 
			control.SetPixels(0, 0, control.width, control.height, tuple.control);
			control.Apply();
			yield return null;
			

			//param texture
			var paramTex = new Texture2D(res, res, MegaSplatOutput.formatARGB? TextureFormat.ARGB32 : TextureFormat.RGBA32, false, true);
			paramTex.wrapMode = TextureWrapMode.Clamp;
			paramTex.filterMode = FilterMode.Point;

			paramTex.SetPixels(0, 0, paramTex.width, paramTex.height, tuple.param);
			paramTex.Apply();
			yield return null;


			//welding
			if (MapMagic.instance != null && MapMagic.instance.splatsWeldMargins!=0)
			{
				Coord coord = Coord.PickCell(rect.offset, MapMagic.instance.resolution);
				//Chunk chunk = MapMagic.instance.chunks[coord.x, coord.z];
				
				Chunk neigPrevX = MapMagic.instance.chunks[coord.x-1, coord.z];
				if (neigPrevX!=null && neigPrevX.worker.ready && neigPrevX.terrain.materialTemplate.HasProperty("_SplatControl")) 
				{
					WeldTerrains.WeldTextureToPrevX(control, (Texture2D)neigPrevX.terrain.materialTemplate.GetTexture("_SplatControl"));
					control.Apply();
				}

				Chunk neigNextX = MapMagic.instance.chunks[coord.x+1, coord.z];
				if (neigNextX!=null && neigNextX.worker.ready && neigNextX.terrain.materialTemplate.HasProperty("_SplatControl")) 
				{
					WeldTerrains.WeldTextureToNextX(control, (Texture2D)neigNextX.terrain.materialTemplate.GetTexture("_SplatControl"));
					control.Apply();
				}
				
				Chunk neigPrevZ = MapMagic.instance.chunks[coord.x, coord.z-1];
				if (neigPrevZ!=null && neigPrevZ.worker.ready && neigPrevZ.terrain.materialTemplate.HasProperty("_SplatControl")) 
				{
					WeldTerrains.WeldTextureToPrevZ(control, (Texture2D)neigPrevZ.terrain.materialTemplate.GetTexture("_SplatControl"));
					control.Apply();
				}

				Chunk neigNextZ = MapMagic.instance.chunks[coord.x, coord.z+1];
				if (neigNextZ!=null && neigNextZ.worker.ready && neigNextZ.terrain.materialTemplate.HasProperty("_SplatControl")) 
				{
					WeldTerrains.WeldTextureToNextZ(control, (Texture2D)neigNextZ.terrain.materialTemplate.GetTexture("_SplatControl"));
					control.Apply();
				}
			}
			yield return null;




			//TODO: weld textures with 1-pixel margin

			//assign textures using material property (not saving for fixed terrains)
			//#if UNITY_5_5_OR_NEWER
			//MaterialPropertyBlock matProp = new MaterialPropertyBlock();
			//matProp.SetTexture("_SplatControl", control);
			//matProp.SetTexture("_SplatParams", paramTex);
			//matProp.SetFloat("_ControlSize", res);
			//terrain.SetSplatMaterialPropertyBlock(matProp);
			//#endif

			//duplicating material
			if (MapMagic.instance.customTerrainMaterial != null)
			{
				terrain.materialTemplate = new Material(MapMagic.instance.customTerrainMaterial);

				//assigning control textures
				if (terrain.materialTemplate.HasProperty("_SplatControl"))
					terrain.materialTemplate.SetTexture("_SplatControl", control);
				if (terrain.materialTemplate.HasProperty("_SplatParams"))
					terrain.materialTemplate.SetTexture("_SplatParams", paramTex);
			}

			#else
			yield return null;
			#endif
		}
Beispiel #2
0
		public static void Process(CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func<float,bool> stop = null)
		{
			#if __MEGASPLAT__
			if (stop!=null && stop(0)) return;

			//using the first texture list for all
			MegaSplatTextureList textureList = null;
			bool smoothFallof = false;
         float clusterScale = 0.05f;
			foreach (MegaSplatOutput gen in gens.GeneratorsOfType<MegaSplatOutput>(onlyEnabled: true, checkBiomes: true))
			{
				if (gen.textureList != null) textureList = gen.textureList;
				smoothFallof = gen.smoothFallof;
            clusterScale = gen.clusterNoiseScale;
			}

			//creating color arrays
			MegaSplatData result = new MegaSplatData();

			result.control = new Color[MapMagic.instance.resolution * MapMagic.instance.resolution];
			result.param = new Color[MapMagic.instance.resolution * MapMagic.instance.resolution];
			
			//creating all and special layers/biomes lists
			List<Layer> allLayers = new List<Layer>(); //all layers count = gen num * layers num in each gen (excluding empty biomes, matrices, etc)
			List<Matrix> allMatrices = new List<Matrix>();
			List<Matrix> allBiomeMasks = new List<Matrix>();

			List<Matrix> specialWetnessMatrices = new List<Matrix>(); //special count = number of generators (excluding empty biomes only)
			List<Matrix> specialPuddlesMatrices = new List<Matrix>();
			List<Matrix> specialDampeningMatrices = new List<Matrix>();
			List<Matrix> specialBiomeMasks = new List<Matrix>();

			//filling all layers/biomes
			foreach (MegaSplatOutput gen in gens.GeneratorsOfType<MegaSplatOutput>(onlyEnabled: true, checkBiomes: true))
			{
				gen.textureList = textureList;

				//loading biome matrix
				Matrix biomeMask = null;
				if (gen.biome != null)
				{
					object biomeMaskObj = gen.biome.mask.GetObject(results);
					if (biomeMaskObj == null) continue; //adding nothing if biome has no mask
					biomeMask = (Matrix)biomeMaskObj;
					if (biomeMask == null) continue;
					if (biomeMask.IsEmpty()) continue; //optimizing empty biomes
				}

				for (int i = 0; i < gen.baseLayers.Length; i++)
				{
					//reading output directly
					Output output = gen.baseLayers[i].output;
					if (stop!=null && stop(0)) return; //checking stop before reading output
					if (!results.results.ContainsKey(output)) continue;
					Matrix matrix = (Matrix)results.results[output];
					if (matrix.IsEmpty()) continue;

					if (i >= textureList.clusters.Length)
					{
						Debug.LogError("Cluster out of range");
						continue;
					}

					//adding to lists
					allLayers.Add(gen.baseLayers[i]);
					allMatrices.Add(matrix);
					allBiomeMasks.Add(gen.biome == null ? null : biomeMask);
				}

				//adding special
				object wetnessObj = gen.wetnessIn.GetObject(results);
				specialWetnessMatrices.Add( wetnessObj!=null? (Matrix)wetnessObj : null );

				object puddlesObj = gen.puddlesIn.GetObject(results);
				specialPuddlesMatrices.Add( puddlesObj!=null? (Matrix)puddlesObj : null );

				object dampeingObj = gen.displaceDampenIn.GetObject(results);
				specialDampeningMatrices.Add( dampeingObj!=null? (Matrix)dampeingObj : null );

				specialBiomeMasks.Add(gen.biome == null ? null : biomeMask);
			}

			//if no texture list found in any of generators - returning
			if (textureList == null || allLayers.Count==0) return;

			//processing
			int allLayersCount = allLayers.Count;
			int specialCount = specialWetnessMatrices.Count;
			for (int x = 0; x<rect.size.x; x++)
				for (int z = 0; z<rect.size.z; z++)
				{
					int pos = rect.GetPos(x + rect.offset.x, z + rect.offset.z);

					// doesn't use height, normal, but I'm not sure how to get that here..
					Vector3 worldPos = new Vector3(
						1f * (x+rect.offset.x) / MapMagic.instance.resolution * rect.size.x,
						0,
						1f * (z+rect.offset.z) / MapMagic.instance.resolution * rect.size.z);
					float heightRatio = results.heights!=null? results.heights.array[pos] : 0.5f; //0 is the bottom point, 1 is the maximum top
					Vector3 normal = new Vector3(0,1,0);

					// find highest two layers
					int botIdx = 0;
					int topIdx = 0;
					float botWeight = 0;
					float topWeight = 0;

					for (int i = 0; i<allLayersCount; i++)
					{
						float val = allMatrices[i].array[pos];
						if (allBiomeMasks[i] != null) val *= allBiomeMasks[i].array[pos];

						// really want world position, Normal, and height ratio for brushes, but for now, just use x/z..

						if (val > botWeight)
						{
							topWeight = botWeight;
							topIdx = botIdx;

							botWeight = val;
							botIdx = i;
						}
						else if (val > topWeight)
						{
							topIdx = i;
							topWeight = val;
						}
					}

					//converting layer index to texture index
               topIdx = textureList.clusters[ allLayers[topIdx].index ].GetIndex(worldPos *  clusterScale, normal, heightRatio);
               botIdx = textureList.clusters[ allLayers[botIdx].index ].GetIndex(worldPos * clusterScale, normal, heightRatio);

					//swapping indexes to make topIdx always on top
					if (botIdx > topIdx) 
					{
						int tempIdx = topIdx;
						topIdx = botIdx;
						botIdx = tempIdx;

						float tempWeight = topWeight;
						topWeight = botWeight;
						botWeight = tempWeight;
					}

					//finding blend
					float totalWeight = topWeight + botWeight;	if (totalWeight<0.01f) totalWeight = 0.01f; //Mathf.Max and Clamp are slow
					float blend = botWeight / totalWeight;		if (blend>1) blend = 1;

					//adjusting blend curve
					if (smoothFallof) blend = (Mathf.Sqrt(blend) * (1-blend)) + blend*blend*blend;  //Magic secret formula! Inverse to 3*x^2 - 2*x^3

					//setting color
					result.control[pos] = new Color(botIdx / 255.0f, topIdx / 255.0f, 1.0f - blend, 1.0f);

					//params
					for (int i = 0; i<specialCount; i++)
					{
						float biomeVal = specialBiomeMasks[i]!=null? specialBiomeMasks[i].array[pos] : 1;

						if (specialWetnessMatrices[i]!=null) result.param[pos].b = specialWetnessMatrices[i].array[pos] * biomeVal;
						if (specialPuddlesMatrices[i]!=null) 
						{
							result.param[pos].a = specialPuddlesMatrices[i].array[pos] * biomeVal;
							result.param[pos].r = 0.5f;
							result.param[pos].g = 0.5f;
						}
						if (specialDampeningMatrices[i]!=null) result.control[pos].a = specialDampeningMatrices[i].array[pos] * biomeVal;
					}
						
				}
			
			//pushing to apply
			if (stop!=null && stop(0))
				return;
			results.apply.CheckAdd(typeof(MegaSplatOutput), result, replace: true);
			#endif
		}