/// <summary> /// 左键抬起 /// </summary> public override void OnLeftButtonUp() { hitInfo = Utility.SendRay(LayerMask.GetMask("Terrain")); if (hitInfo.Equals(default(RaycastHit))) { return; } Terrain terrain = hitInfo.collider.GetComponent <Terrain>(); switch (Panel.modifierType) { case TerrainModifierPanel.ModifierType.Up: case TerrainModifierPanel.ModifierType.Down: case TerrainModifierPanel.ModifierType.Smooth: TerrainUtility.Refresh(); TerrainUtility.AddOldData(); break; case TerrainModifierPanel.ModifierType.AddTree: if (isAdd) { TerrainUtility.CreatTree(terrain, hitInfo.point, (int)(Panel.opticalMix.Value), (int)Panel.rangeMix.Value, Panel.PrototypeIndex); } else { TerrainUtility.RemoveTree(terrain, hitInfo.point, (int)Panel.rangeMix.Value, Panel.PrototypeIndex); } break; default: break; } }
void Start() { UIManager.Instance.PushPanel(UIPanelType.TerrainModifier); MouseEvent.Instance.ChangeState(TerrainModule.Instance.mouseTerrainModifierState); TerrainUtility.ConfigActiveTerrains(); }
/// <summary> /// 初始化树木原型组 /// </summary> public static void InitTreePrototype(GameObject[] treeObjs) { TreePrototype[] trees = TerrainUtility.CreatTreePrototype(treeObjs); Terrain[] terrains = Terrain.activeTerrains; for (int i = 0, length = terrains.Length; i < length; i++) { terrains[i].terrainData.treePrototypes = trees; } }
/// <summary> /// 读取和地图有关的全部数据 /// </summary> /// <param name="folder"></param> public void ReadTerrainInfo(string folder) { RunAfterCreateTerrain += () => { TerrainUtility.ConfigActiveTerrains(); TerrainUtility.ConfigTerrainData(); RunAfterCreateTerrain = null; }; ReadTerrainData(folder); }
/// <summary> /// 初始化细节原型组 /// </summary> public static void InitDetailPrototype(Texture2D[] textures) { DetailPrototype[] details = TerrainUtility.CreateDetailPrototype(textures); Terrain[] terrains = Terrain.activeTerrains; for (int i = 0, length = terrains.Length; i < length; i++) { terrains[i].terrainData.detailPrototypes = details; terrains[i].detailObjectDistance = 250; // 设置草的消失距离 } }
public override void OnPlatformEnter(TerrainCastHit hit) { var hitSide = TerrainUtility.NormalToControllerSide(hit.NormalAngle * Mathf.Rad2Deg - transform.eulerAngles.z); if ((BouncySides & hitSide) == 0) { return; } if (LockControl) { hit.Controller.GetComponent <MoveManager>().Get <GroundControl>().Lock(LockDuration); } if (!KeepOnGround) { hit.Controller.Detach(); var moveManager = hit.Controller.GetComponent <MoveManager>(); if (moveManager != null) { moveManager.End <Roll>(); moveManager.Perform <AirControl>(true); } hit.Controller.IgnoreThisCollision(); } if (AccurateBounce) { hit.Controller.Velocity = new Vector2(hit.Controller.Velocity.x * Mathf.Abs(Mathf.Sin(hit.NormalAngle)), hit.Controller.Velocity.y * Mathf.Abs(Mathf.Cos(hit.NormalAngle))); hit.Controller.Velocity += DMath.AngleToVector(hit.NormalAngle) * Power; } else { hit.Controller.Velocity = DMath.AngleToVector(hit.NormalAngle) * Power; } if (hit.Controller.Animator != null) { var logWarnings = hit.Controller.Animator.logWarnings; hit.Controller.Animator.logWarnings = false; if (!string.IsNullOrEmpty(HitTrigger)) { hit.Controller.Animator.SetTrigger(HitTrigger); } hit.Controller.Animator.logWarnings = logWarnings; } TriggerObject(hit.Controller); }
public void Perlin() { float[,] heightMap = resetTerrain ? GetNewMap() : GetHeightMap(); for (int y = 0; y < terrainData.heightmapHeight; y++) { for (int x = 0; x < terrainData.heightmapWidth; x++) { heightMap[x, y] += TerrainUtility.FractalBrownianMotion((x + perlinOffsetX) * perlinXScale, (y + perlinOffsetY) * perlinYScale, perlinOctaves, perlinPersistence) * perlinHeightScale; } } terrainData.SetHeights(0, 0, heightMap); }
// Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.J)) { TDSaveMgr.Instance.ReadTerrainInfo("2019-03-25 14-33-15"); } if (Input.GetKeyDown(KeyCode.K)) { TerrainUtility.ConfigActiveTerrains(); TerrainUtility.ConfigTerrainData(); } }
/// <summary> /// 左键按住 /// </summary> public override void OnLeftButtonHold() { hitInfo = Utility.SendRay(LayerMask.GetMask("Terrain")); if (hitInfo.Equals(default(RaycastHit))) { return; } Terrain terrain = hitInfo.collider.GetComponent <Terrain>(); switch (Panel.modifierType) { case TerrainModifierPanel.ModifierType.Up: TerrainUtility.ChangeHeight(hitInfo.point, (int)Panel.rangeMix.Value, Panel.opticalMix.Value); break; case TerrainModifierPanel.ModifierType.Down: TerrainUtility.ChangeHeight(hitInfo.point, (int)Panel.rangeMix.Value, Panel.opticalMix.Value, false); break; case TerrainModifierPanel.ModifierType.Smooth: TerrainUtility.Smooth(hitInfo.point, (int)Panel.rangeMix.Value, Panel.opticalMix.Value); break; case TerrainModifierPanel.ModifierType.AddDetial: if (MouseEvent.Instance.MouseMove) { if (isAdd) { TerrainUtility.AddDetial(terrain, hitInfo.point, Panel.rangeMix.Value, (int)(Panel.opticalMix.Value), Panel.PrototypeIndex); } else { TerrainUtility.RemoveDetial(terrain, hitInfo.point, Panel.rangeMix.Value, Panel.PrototypeIndex); } } break; case TerrainModifierPanel.ModifierType.AttachTexture: if (MouseEvent.Instance.MouseMove) { TerrainUtility.SetTexture(hitInfo.point, 1, 1); } break; default: break; } }
// Use this for initialization void Start() { GetComponent <MeshFilter>().mesh = MeshUtility.CreateCube(1f, Vector3.zero); BlockManager.Init(chunkPrefab); TextureManager.Init(texMap, tileSize); for (int x = 0; x < 100; x++) { for (int y = 0; y < 100; y++) { IBlock block = new GrassBlock(Vector3.left * x + (Vector3.up * TerrainUtility.GetBlockHeight(x, y)) + Vector3.forward * y); for (int i = 0; i < block.Position.y; i++) { IBlock block1 = new DirtBlock(new Vector3(block.Position.x, i, block.Position.z)); BlockManager.AddBlock(block1); } BlockManager.AddBlock(block); } } //Block block = new Block(Vector3.one); //BlockManager.AddBlock(block); }
/// <summary> /// 初始化原型模板 /// </summary> private void InitPrototype() { details = TerrainUtility.CreateDetailPrototype(); trees = TerrainUtility.CreatTreePrototype(); splats = TerrainUtility.CreateSplatPrototype(); }
/// <summary> /// 创建单块地图 /// </summary> /// <param name="tdData"></param> private void CreateTerrain(TDData tdData) { // 设置TerrainData的基础参数 TerrainData terrainData = new TerrainData(); terrainData.heightmapResolution = head.ResolutionSize + 1; terrainData.SetDetailResolution(head.ResolutionSize, 8); terrainData.alphamapResolution = head.ResolutionSize * 2; terrainData.baseMapResolution = head.ResolutionSize; terrainData.size = head.terrainSize; terrainData.detailPrototypes = details; terrainData.treePrototypes = trees; terrainData.terrainLayers = splats; terrainData.RefreshPrototypes(); // 高度,贴图,细节设置 if (tdData.heightMap != null) { terrainData.SetHeights(0, 0, tdData.heightMap); } if (tdData.detailMap != null) { for (int i = 0; i < tdData.detailMap.Length; i++) { terrainData.SetDetailLayer(0, 0, i, tdData.detailMap[i]); } } if (tdData.alphaMap != null) { terrainData.SetAlphamaps(0, 0, tdData.alphaMap); } // 在场景中创建Terrain实体并设置实体的参数 GameObject newTerrainGameObject = Terrain.CreateTerrainGameObject(terrainData); newTerrainGameObject.name = terrainData.name; newTerrainGameObject.isStatic = false; newTerrainGameObject.transform.position = tdData.terrainPos; newTerrainGameObject.layer = LayerMask.NameToLayer("Terrain"); // 设置Terrain类的参数 Terrain terrain = newTerrainGameObject.GetComponent <Terrain>(); terrain.heightmapPixelError = head.heightmapPixelError; terrain.basemapDistance = head.basemapDistance; terrain.drawHeightmap = head.drawHeightmap; terrain.name = tdData.name; if (tdData.treePoses != null) { // 为地形添加树木实体 for (int index = 0; index < tdData.treePoses.Length; index++) { for (int i = 0; i < tdData.treePoses[index].Length; i++) { TreeInstance instance = TerrainUtility.GetTreeInstance(index); instance.position = tdData.treePoses[index][i]; terrain.AddTreeInstance(instance); } } } newTerrainGameObject.transform.SetParent(terrainParent); }
private void FillHeightmapUsingNeighbors(Terrain terrain) { TerrainUtility.AutoConnect(); Terrain[] nbrTerrains = new Terrain[4] { terrain.topNeighbor, terrain.bottomNeighbor, terrain.leftNeighbor, terrain.rightNeighbor }; // Position of the terrain must be lowest Vector3 position = terrain.transform.position; foreach (Terrain nbrTerrain in nbrTerrains) { if (nbrTerrain) { position.y = Mathf.Min(position.y, nbrTerrain.transform.position.y); } } terrain.transform.position = position; TerrainNeighborInfo top = new TerrainNeighborInfo(); TerrainNeighborInfo bottom = new TerrainNeighborInfo(); TerrainNeighborInfo left = new TerrainNeighborInfo(); TerrainNeighborInfo right = new TerrainNeighborInfo(); TerrainNeighborInfo[] nbrInfos = new TerrainNeighborInfo[4] { top, bottom, left, right }; const float kNeightNormFactor = 2.0f; for (int i = 0; i < 4; ++i) { TerrainNeighborInfo nbrInfo = nbrInfos[i]; Terrain nbrTerrain = nbrTerrains[i]; if (nbrTerrain) { nbrInfo.terrainData = nbrTerrain.terrainData; if (nbrInfo.terrainData) { nbrInfo.texture = nbrInfo.terrainData.heightmapTexture; nbrInfo.offset = (nbrTerrain.transform.position.y - terrain.transform.position.y) / (nbrInfo.terrainData.size.y * kNeightNormFactor); } } } RenderTexture heightmap = terrain.terrainData.heightmapTexture; Vector4 texCoordOffsetScale = new Vector4(-0.5f / heightmap.width, -0.5f / heightmap.height, (float)heightmap.width / (heightmap.width - 1), (float)heightmap.height / (heightmap.height - 1)); Material crossBlendMat = GetOrCreateCrossBlendMaterial(); Vector4 slopeEnableFlags = new Vector4(bottom.texture ? 0.0f : 1.0f, top.texture ? 0.0f : 1.0f, left.texture ? 0.0f : 1.0f, right.texture ? 0.0f : 1.0f); crossBlendMat.SetVector("_SlopeEnableFlags", slopeEnableFlags); crossBlendMat.SetVector("_TexCoordOffsetScale", texCoordOffsetScale); crossBlendMat.SetVector("_Offsets", new Vector4(bottom.offset, top.offset, left.offset, right.offset)); crossBlendMat.SetFloat("_AddressMode", (float)m_FillAddressMode); crossBlendMat.SetTexture("_TopTex", top.texture); crossBlendMat.SetTexture("_BottomTex", bottom.texture); crossBlendMat.SetTexture("_LeftTex", left.texture); crossBlendMat.SetTexture("_RightTex", right.texture); Graphics.Blit(null, heightmap, crossBlendMat); terrain.terrainData.DirtyHeightmapRegion(new RectInt(0, 0, heightmap.width, heightmap.height), TerrainHeightmapSyncControl.HeightAndLod); }
private void OnGUI() { GUILayout.Label("Settings", EditorStyles.boldLabel); fileName = EditorGUILayout.TextField("Texture Name", fileName); int wSize = (int)(EditorGUIUtility.currentViewWidth - 100); perlinXScale = EditorGUILayout.Slider("X Scale", perlinXScale, 0, 0.1f); perlinYScale = EditorGUILayout.Slider("Y Scale", perlinYScale, 0, 0.1f); perlinOctaves = EditorGUILayout.IntSlider("Octaves", perlinOctaves, 1, 10); perlinePersistance = EditorGUILayout.Slider("Persistance", perlinePersistance, 1, 10); perlineHeightScale = EditorGUILayout.Slider("Height Scale", perlineHeightScale, 0, 1); perlinOffsetX = EditorGUILayout.IntSlider("Offset X", perlinOffsetX, 0, 10000); perlinOffsetY = EditorGUILayout.IntSlider("Offset Y", perlinOffsetY, 0, 10000); brightness = EditorGUILayout.Slider("Brightness", brightness, 0, 2); contrast = EditorGUILayout.Slider("Contrast", contrast, 0, 2); alphaToggle = EditorGUILayout.Toggle("Alpha", alphaToggle); mapToggle = EditorGUILayout.Toggle("Map", mapToggle); seamlessToggle = EditorGUILayout.Toggle("Seamless", seamlessToggle); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); float minColor = 1; float maxColor = 0; if (GUILayout.Button("Generate", GUILayout.Width(wSize))) { int w = 513; int h = 513; float pValue; Color pixCol = Color.white; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { if (seamlessToggle) { float u = x / w; float v = y / h; float noise00 = TerrainUtility.FractalBrownianMotion((x + perlinOffsetX) * perlinXScale, (y + perlinOffsetY) * perlinYScale, perlinOctaves, perlinePersistance) * perlineHeightScale; float noise01 = TerrainUtility.FractalBrownianMotion((x + perlinOffsetX) * perlinXScale, (y + perlinOffsetY + h) * perlinYScale, perlinOctaves, perlinePersistance) * perlineHeightScale; float noise10 = TerrainUtility.FractalBrownianMotion((x + perlinOffsetX + w) * perlinXScale, (y + perlinOffsetY) * perlinYScale, perlinOctaves, perlinePersistance) * perlineHeightScale; float noise11 = TerrainUtility.FractalBrownianMotion((x + perlinOffsetX + w) * perlinXScale, (y + perlinOffsetY + h) * perlinYScale, perlinOctaves, perlinePersistance) * perlineHeightScale; float noiseTotal = u * v * noise00 + u * (1 - v) * noise01 + (1 - u) * v * noise10 + (1 - u) * (1 - v) * noise11; float value = (int)(256 * noiseTotal) + 50; float r = Mathf.Clamp((int)noise00, 0, 255); float g = Mathf.Clamp(value, 0, 255); float b = Mathf.Clamp(value + 50, 0, 255); float a = Mathf.Clamp(value + 100, 0, 255); pValue = (r + g + b) / (3 * 255.0f); } else { pValue = TerrainUtility.FractalBrownianMotion((x + perlinOffsetX) * perlinXScale, (y + perlinOffsetY) * perlinYScale, perlinOctaves, perlinePersistance) * perlineHeightScale; } float colValue = contrast * (pValue - 0.5f) + 0.5f * brightness; if (minColor > colValue) { minColor = colValue; } if (maxColor < colValue) { maxColor = colValue; } pixCol = new Color(colValue, colValue, colValue, alphaToggle ? colValue : 1); pTexture.SetPixel(x, y, pixCol); } } if (mapToggle) { for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { pixCol = pTexture.GetPixel(x, y); float colValue = pixCol.r; colValue = TerrainUtility.Map(colValue, minColor, maxColor, 0, 1); pixCol.r = colValue; pixCol.g = colValue; pixCol.b = colValue; pTexture.SetPixel(x, y, pixCol); } } } pTexture.Apply(false, false); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Label(pTexture, GUILayout.Width(wSize), GUILayout.Height(wSize)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Save", GUILayout.Width(wSize))) { CreatePNGFromTex(); MakeTexReadable(); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); }
public override void OnInspectorGUI() { serializedObject.Update(); TerrainUtility terrainUtility = (TerrainUtility)target; TerrainGenerator terrainGenerator = terrainUtility.GetComponent <TerrainGenerator>(); PlantGenerator plantGenerator = terrainUtility.GetComponent <PlantGenerator>(); //Terrain GUILayout.Label("Terrain generation"); terrainGenerator.terrainWidth = EditorGUILayout.FloatField(new GUIContent("Terrain size X"), terrainGenerator.terrainWidth); plantGenerator.xMinVal = -(terrainGenerator.terrainWidth / 2); plantGenerator.xMaxVal = terrainGenerator.terrainWidth / 2; plantGenerator.zMinVal = -(terrainGenerator.terrainLength / 2); plantGenerator.zMaxVal = terrainGenerator.terrainLength / 2; terrainGenerator.terrainLength = EditorGUILayout.FloatField(new GUIContent("Terrain size Z"), terrainGenerator.terrainLength); EditorGUILayout.PropertyField(_chunksPerFrame); GUILayout.BeginHorizontal(); if (GUILayout.Button("Create terrain")) { TerrainGenerator.instance = terrainGenerator; terrainGenerator.buildTerrain(_chunksPerFrame.intValue); } if (GUILayout.Button("Delete terrain")) { TerrainGenerator.instance = terrainGenerator; terrainGenerator.deleteTerrain(); EditorSceneManager.MarkAllScenesDirty(); System.GC.Collect(); Resources.UnloadUnusedAssets(); } GUILayout.EndHorizontal(); //Plants GUILayout.Label("Plant generation"); EditorGUILayout.PropertyField(_plantsPerUnit); plantsToSpawn = (int)Math.Round(_plantsPerUnit.floatValue * terrainGenerator.terrainLength * terrainGenerator.terrainWidth); GUILayout.Label($"This will spawn {plantsToSpawn} plants"); plantGenerator.amountOfPlantsToSpawn = plantsToSpawn; EditorGUILayout.PropertyField(_plantsPerFrame); GUILayout.BeginHorizontal(); if (GUILayout.Button("Generate plants")) { //Old logic -> //plantGenerator.StartCoroutine(plantGenerator.spawnPlantsInXZRange()); //New logic -> plantGenerator.StartCoroutine(plantGenerator.SpawnPlantsOnChunks(terrainGenerator, _plantsPerFrame.intValue)); } if (GUILayout.Button("Delete plants")) { plantGenerator.deleteAllPlants(terrainGenerator); EditorSceneManager.MarkAllScenesDirty(); System.GC.Collect(); Resources.UnloadUnusedAssets(); } GUILayout.EndHorizontal(); serializedObject.ApplyModifiedProperties(); }
public void PlantDetails() { // If both the prototype and the texture are missing details.RemoveAll(detail => detail.prototype == null && detail.prototypeTexture == null); // Create new detail prototype and set its properties from detail class DetailPrototype[] newDetailPrototypes = new DetailPrototype[details.Count]; float[,] heightMap = terrainData.GetHeights(0, 0, terrainData.heightmapWidth, terrainData.heightmapHeight); for (int i = 0; i < details.Count; i++) { Detail detail = details[i]; newDetailPrototypes[i] = new DetailPrototype { prototype = detail.prototype, prototypeTexture = detail.prototypeTexture, healthyColor = detail.healthyColor, dryColor = detail.dryColor, bendFactor = detail.bendFactor, noiseSpread = detail.noiseSpread, maxHeight = detail.heightRange.y, minHeight = detail.heightRange.x, maxWidth = detail.widthRange.y, minWidth = detail.widthRange.x }; DetailPrototype detailPrototype = newDetailPrototypes[i]; // If prototype mesh is given, the mesh is used. // If the texture is given, then the texture is used, not both. if (detailPrototype.prototype != null) { detailPrototype.usePrototypeMesh = true; detailPrototype.renderMode = DetailRenderMode.VertexLit; // Set prototype texture to null for better understanding in editor. detailPrototype.prototypeTexture = null; } else if (detailPrototype.prototypeTexture != null) { detailPrototype.usePrototypeMesh = false; detailPrototype.renderMode = DetailRenderMode.GrassBillboard; } } // Apply detail prototypes to terrain terrainData.detailPrototypes = newDetailPrototypes; for (int i = 0; i < terrainData.detailPrototypes.Length; i++) { Detail detail = details[i]; int[,] detailMap = new int[terrainData.detailWidth, terrainData.detailHeight]; EditorUtility.DisplayProgressBar("Planting Details", detail.prototype != null ? detail.prototype.name : detail.prototypeTexture.name, (float)i / terrainData.detailPrototypes.Length); // Go through all terrain and plant details for (int y = 0; y < terrainData.detailHeight; y += detailSpacing) { for (int x = 0; x < terrainData.detailWidth; x += detailSpacing) { // Less density means more details will be skipped at this (x,z) position if (Random.Range(0f, 1f) > detail.density) { continue; } // Calculate x and y of the heightmap from detail width/height int xHM = (int)(x / (float)terrainData.detailWidth * terrainData.heightmapWidth); int yHM = (int)(y / (float)terrainData.detailHeight * terrainData.heightmapHeight); float perlin = Mathf.PerlinNoise(x * detail.heightNoiseMultiplier, y * detail.heightNoiseMultiplier); float thisNoise = TerrainUtility.Map(perlin, 0, 1, 0.5f, 1); float thisHeightStart = thisNoise * detail.minHeight; float nextHeightStart = thisNoise * detail.maxHeight; // Detailmap is rotated 90 degrees, so when converting to heightmap swap x and z float thisHeight = heightMap[yHM, xHM]; float steepness = terrainData.GetSteepness( xHM / terrainData.size.x, yHM / terrainData.size.z); // If the height is in between boundaries if (thisHeight >= thisHeightStart && thisHeight <= nextHeightStart && // If steepness is between boundaries steepness >= detail.minSlope && steepness <= detail.maxSlope) { // x and y is backwards for the detail map, detail map is rotated 90 degrees // Apply detail map on this point //detailMap[y, x] = 1; detailMap[y, x] = 1; } } } // Apply this detail on terrain with detailmap terrainData.SetDetailLayer(0, 0, i, detailMap); } EditorUtility.ClearProgressBar(); }