private void Editor_CreateHistory(GFoliagePainterArgs args) { if (!Editor_EnableHistory) { return; } if (EditedTerrains.Count == 0) { return; } List <GTerrainResourceFlag> flags = new List <GTerrainResourceFlag>(); flags.AddRange(ActivePainter.GetResourceFlagForHistory(args)); List <GStylizedTerrain> terrainList = new List <GStylizedTerrain>(EditedTerrains); string backupName = GBackup.TryCreateBackup(ActivePainter.HistoryPrefix, terrainList[0], flags, false); if (!string.IsNullOrEmpty(backupName)) { for (int i = 1; i < terrainList.Count; ++i) { GBackup.BackupTerrain(terrainList[i], backupName, flags); } } }
private void Editor_CreateHistory(GFoliagePainterArgs args) { if (!Editor_EnableHistory) { return; } List <GTerrainResourceFlag> flags = new List <GTerrainResourceFlag>(); flags.AddRange(ActivePainter.GetResourceFlagForHistory(args)); GBackup.TryCreateBackup(ActivePainter.HistoryPrefix, GroupId, ActivePainter.GetResourceFlagForHistory(args), false); }
public void Paint(GFoliagePainterArgs args) { IGFoliagePainter p = ActivePainter; if (p == null) { return; } args.Radius = BrushRadius; args.Rotation = BrushRotation; args.Density = BrushDensity; args.EraseRatio = EraseRatio; args.ScaleStrength = ScaleStrength; args.TreeIndices = SelectedTreeIndices; args.GrassIndices = SelectedGrassIndices; args.CustomArgs = CustomPainterArgs; if (SelectedBrushMaskIndex >= 0 && SelectedBrushMaskIndex < BrushMasks.Count) { args.Mask = BrushMasks[SelectedBrushMaskIndex]; } args.Filters = GetComponents <GSpawnFilter>(); ProcessBrushDynamic(ref args); Vector3[] corners = GCommon.GetBrushQuadCorners(args.HitPoint, args.Radius, args.Rotation); args.WorldPointCorners = corners; #if UNITY_EDITOR if (args.MouseEventType == GPainterMouseEventType.Down && args.ShouldCommitNow == false) { Editor_CreateInitialHistoryEntry(args); } #endif IEnumerator <GStylizedTerrain> terrains = GStylizedTerrain.ActiveTerrains.GetEnumerator(); while (terrains.MoveNext()) { if (terrains.Current.GroupId != GroupId && GroupId >= 0) { continue; } GStylizedTerrain t = terrains.Current; p.Paint(t, args); } #if UNITY_EDITOR if (args.MouseEventType == GPainterMouseEventType.Up) { Editor_CreateHistory(args); } #endif }
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GFoliagePainterArgs args) { if (args.TreeIndices.Count == 0) { return; } if (terrain.TerrainData == null) { return; } if (terrain.TerrainData.Foliage.Trees == null) { return; } if (args.MouseEventType == GPainterMouseEventType.Up || args.ShouldCommitNow) { GCommon.SetDirty(terrain.TerrainData.Foliage); terrain.UpdateTreesPosition(); terrain.TerrainData.Foliage.ClearTreeDirtyRegions(); GRuntimeSettings.Instance.isEditingFoliage = false; return; } Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length]; for (int i = 0; i < uvCorners.Length; ++i) { uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]); } Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners); if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1))) { return; } GRuntimeSettings.Instance.isEditingFoliage = true; if (args.ActionType == GPainterActionType.Normal) { HandleSpawnTree(terrain, args); } else { HandleEraseTree(terrain, args); } terrain.TerrainData.Foliage.SetTreeRegionDirty(dirtyRect); terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage); GUtilities.MarkCurrentSceneDirty(); }
private void ProcessBrushDynamic(ref GFoliagePainterArgs args) { Rand rand = GetRandomGenerator(); args.Radius -= BrushRadius * BrushRadiusJitter * (float)rand.NextDouble(); args.Rotation += Mathf.Sign((float)rand.NextDouble() - 0.5f) * BrushRotation * BrushRotationJitter * (float)rand.NextDouble(); args.Density -= Mathf.RoundToInt(BrushDensity * BrushDensityJitter * (float)rand.NextDouble()); Vector3 scatterDir = new Vector3((float)(rand.NextDouble() * 2 - 1), 0, (float)(rand.NextDouble() * 2 - 1)).normalized; float scatterLengthMultiplier = BrushScatter - (float)rand.NextDouble() * BrushScatterJitter; float scatterLength = args.Radius * scatterLengthMultiplier; args.HitPoint += scatterDir * scatterLength; }
private void OnSceneGUI() { HandleTerrainEditingInSceneView(); HandleBrushSettingsShortcuts(); HandleFunctionKeys(); if (Event.current != null && Event.current.type == EventType.MouseMove) { SceneView.RepaintAll(); } if (Event.current != null && Event.current.type == EventType.MouseLeaveWindow) { GFoliagePainterArgs args = new GFoliagePainterArgs(); args.ShouldCommitNow = true; painter.Paint(args); } }
private void Editor_CreateInitialHistoryEntry(GFoliagePainterArgs args, List <GStylizedTerrain> overlappedTerrains) { if (!Editor_EnableHistory) { return; } if (overlappedTerrains.Count == 0) { return; } List <GTerrainResourceFlag> flags = new List <GTerrainResourceFlag>(); flags.AddRange(ActivePainter.GetResourceFlagForHistory(args)); if (InitialRecordedTerrains.Count == 0) { currentInitialBackupName = GBackup.TryCreateInitialBackup(ActivePainter.HistoryPrefix, overlappedTerrains[0], flags, false); if (!string.IsNullOrEmpty(currentInitialBackupName)) { InitialRecordedTerrains.Add(overlappedTerrains[0]); } } else { if (!string.IsNullOrEmpty(currentInitialBackupName)) { for (int i = 0; i < overlappedTerrains.Count; ++i) { if (InitialRecordedTerrains.Contains(overlappedTerrains[i])) { continue; } GBackup.BackupTerrain(overlappedTerrains[i], currentInitialBackupName, flags); InitialRecordedTerrains.Add(overlappedTerrains[i]); } } } }
private void Paint(RaycastHit hit) { GFoliagePainterArgs args = new GFoliagePainterArgs(); args.HitPoint = hit.point; args.Collider = hit.collider; args.Transform = hit.transform; args.UV = hit.textureCoord; args.TriangleIndex = hit.triangleIndex; args.BarycentricCoord = hit.barycentricCoordinate; args.Distance = hit.distance; args.Normal = hit.normal; args.LightMapCoord = hit.lightmapCoord; args.MouseEventType = Event.current.type == EventType.MouseDown ? GPainterMouseEventType.Down : Event.current.type == EventType.MouseDrag ? GPainterMouseEventType.Drag : GPainterMouseEventType.Up; args.ActionType = Event.current.shift ? GPainterActionType.Alternative : Event.current.control ? GPainterActionType.Negative : GPainterActionType.Normal; painter.Paint(args); }
private void HandleSpawnGrass(GStylizedTerrain terrain, GFoliagePainterArgs args) { int grassIndex = -1; Vector3 randomPos = Vector3.zero; Vector3 rayOrigin = Vector3.zero; Vector3 rayDirection = Vector3.down; float sqrtTwo = Mathf.Sqrt(2); Ray ray = new Ray(); RaycastHit samplePoint; Vector3 bary0 = Vector3.zero; Vector3 bary1 = Vector3.zero; Vector2 maskUv = Vector2.zero; Vector2 samplePointTexcoord = Vector2.zero; Color maskColor = Color.white; Texture2D clonedMask = null; Texture2D terrainMask = null; if (args.Mask != null) { clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256); } if (args.EnableTerrainMask) { terrainMask = terrain.TerrainData.Mask.MaskMap; } int prototypeCount = terrain.TerrainData.Foliage.Grasses.Prototypes.Count; int sampleCount = args.Density; List <GGrassInstance> newInstances = new List <GGrassInstance>(); for (int i = 0; i < sampleCount; ++i) { grassIndex = args.GrassIndices[Random.Range(0, args.GrassIndices.Count)]; if (grassIndex < 0 || grassIndex >= prototypeCount) { continue; } randomPos = args.HitPoint + Random.insideUnitSphere * args.Radius * sqrtTwo; rayOrigin.Set( randomPos.x, 10000, randomPos.z); ray.origin = rayOrigin; ray.direction = rayDirection; if (terrain.Raycast(ray, out samplePoint, float.MaxValue)) { GUtilities.CalculateBarycentricCoord( new Vector2(samplePoint.point.x, samplePoint.point.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), ref bary0); GUtilities.CalculateBarycentricCoord( new Vector2(samplePoint.point.x, samplePoint.point.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z), ref bary1); if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0) { maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one; } else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0) { maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right; } else { continue; } //sample mask if (clonedMask != null) { maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y); if (Random.value > maskColor.grayscale) { continue; } } //sample terrain mask if (args.EnableTerrainMask) { samplePointTexcoord = samplePoint.textureCoord; maskColor = terrainMask.GetPixelBilinear(samplePointTexcoord.x, samplePointTexcoord.y); if (Random.value < maskColor.r) { continue; } } //apply filter GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create(); filterArgs.Terrain = terrain; filterArgs.Position = samplePoint.point; filterArgs.SurfaceNormal = samplePoint.normal; filterArgs.SurfaceTexcoord = samplePoint.textureCoord; List <Type> suitableFilter = SuitableFilterTypes; if (args.Filters != null) { for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex) { if (args.Filters[fIndex] != null && args.Filters[fIndex].Ignore != true) { if (suitableFilter.Contains(args.Filters[fIndex].GetType())) { args.Filters[fIndex].Apply(ref filterArgs); } } if (filterArgs.ShouldExclude) { break; } } } //spawn if (filterArgs.ShouldExclude) { continue; } GGrassInstance grass = GGrassInstance.Create(grassIndex); grass.Position = terrain.WorldPointToNormalized(filterArgs.Position); grass.Rotation = filterArgs.Rotation; grass.Scale = filterArgs.Scale; newInstances.Add(grass); } } terrain.TerrainData.Foliage.AddGrassInstances(newInstances); if (clonedMask != null) { Object.DestroyImmediate(clonedMask); } }
public List <GTerrainResourceFlag> GetResourceFlagForHistory(GFoliagePainterArgs args) { return(GCommon.GrassInstancesResourceFlags); }
private void HandleEraseGrass(GStylizedTerrain terrain, GFoliagePainterArgs args) { Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length]; for (int i = 0; i < uvCorners.Length; ++i) { uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]); } Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners); int grassIndex = -1; Vector3 terrainSize = new Vector3( terrain.TerrainData.Geometry.Width, terrain.TerrainData.Geometry.Height, terrain.TerrainData.Geometry.Length); Vector3 localPos = Vector3.zero; Vector3 worldPos = Vector3.zero; Vector3 bary0 = Vector3.zero; Vector3 bary1 = Vector3.zero; Vector2 maskUv = Vector2.zero; Color maskColor = Color.white; Texture2D clonedMask = null; Texture2D terrainMask = null; if (args.Mask != null) { clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256); } if (args.EnableTerrainMask) { terrainMask = terrain.TerrainData.Mask.MaskMap; } GGrassPatch[] patches = terrain.TerrainData.Foliage.GrassPatches; for (int i = 0; i < patches.Length; ++i) { if (!patches[i].GetUvRange().Overlaps(dirtyRect)) { continue; } if (args.ActionType == GPainterActionType.Alternative) { patches[i].RequireFullUpdate = true; } patches[i].RemoveInstances(grass => { grassIndex = args.GrassIndices[Random.Range(0, args.GrassIndices.Count)]; localPos.Set( grass.position.x * terrainSize.x, grass.position.y * terrainSize.y, grass.position.z * terrainSize.z); worldPos = terrain.transform.TransformPoint(localPos); GUtilities.CalculateBarycentricCoord( new Vector2(worldPos.x, worldPos.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), ref bary0); GUtilities.CalculateBarycentricCoord( new Vector2(worldPos.x, worldPos.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z), ref bary1); if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0) { maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one; } else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0) { maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right; } else { return(false); } //sample mask if (clonedMask != null) { maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y); if (Random.value > maskColor.grayscale * args.EraseRatio) { return(false); } } //sample terrain mask if (args.EnableTerrainMask) { maskColor = terrainMask.GetPixelBilinear(grass.position.x, grass.position.z); if (Random.value < maskColor.r) { return(false); } } if (args.ActionType == GPainterActionType.Negative && grass.PrototypeIndex == grassIndex) { return(true); } else if (args.ActionType == GPainterActionType.Alternative) { return(true); } return(false); }); } if (clonedMask != null) { Object.DestroyImmediate(clonedMask); } }
private void HandleEraseTree(GStylizedTerrain terrain, GFoliagePainterArgs args) { int treeIndex = -1; Vector3 terrainSize = new Vector3( terrain.TerrainData.Geometry.Width, terrain.TerrainData.Geometry.Height, terrain.TerrainData.Geometry.Length); Vector3 localPos = Vector3.zero; Vector3 worldPos = Vector3.zero; Vector3 bary0 = Vector3.zero; Vector3 bary1 = Vector3.zero; Vector2 maskUv = Vector2.zero; Color maskColor = Color.white; Texture2D clonedMask = null; Texture2D terrainMask = null; if (args.Mask != null) { clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256); } if (args.EnableTerrainMask) { terrainMask = terrain.TerrainData.Mask.MaskMap; } terrain.TerrainData.Foliage.RemoveTreeInstances(tree => { treeIndex = args.TreeIndices[Random.Range(0, args.TreeIndices.Count)]; localPos.Set( tree.position.x * terrainSize.x, tree.position.y * terrainSize.y, tree.position.z * terrainSize.z); worldPos = terrain.transform.TransformPoint(localPos); GUtilities.CalculateBarycentricCoord( new Vector2(worldPos.x, worldPos.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), ref bary0); GUtilities.CalculateBarycentricCoord( new Vector2(worldPos.x, worldPos.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z), ref bary1); if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0) { maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one; } else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0) { maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right; } else { return(false); } //sample mask if (clonedMask != null) { maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y); if (Random.value > maskColor.grayscale * args.EraseRatio) { return(false); } } //sample terrain mask if (args.EnableTerrainMask) { maskColor = terrainMask.GetPixelBilinear(tree.position.x, tree.position.z); if (Random.value < maskColor.r) { return(false); } } if (args.ActionType == GPainterActionType.Negative && tree.PrototypeIndex == treeIndex) { return(true); } else if (args.ActionType == GPainterActionType.Alternative) { return(true); } return(false); }); if (clonedMask != null) { Object.DestroyImmediate(clonedMask); } }
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GFoliagePainterArgs args) { if (args.GrassIndices.Count == 0) { return; } if (terrain.TerrainData == null) { return; } if (terrain.TerrainData.Foliage.Grasses == null) { return; } if (args.MouseEventType == GPainterMouseEventType.Up || args.ShouldCommitNow) { terrain.TerrainData.SetDirty(GTerrainData.DirtyFlags.Foliage); GRuntimeSettings.Instance.isEditingFoliage = false; return; } Vector2[] uvCorners = new Vector2[args.WorldPointCorners.Length]; for (int i = 0; i < uvCorners.Length; ++i) { uvCorners[i] = terrain.WorldPointToUV(args.WorldPointCorners[i]); } Rect dirtyRect = GUtilities.GetRectContainsPoints(uvCorners); if (!dirtyRect.Overlaps(new Rect(0, 0, 1, 1))) { return; } GRuntimeSettings.Instance.isEditingFoliage = true; Texture2D clonedMask = null; Texture2D terrainMask = null; if (args.Mask != null) { clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256); } if (args.EnableTerrainMask) { terrainMask = terrain.TerrainData.Mask.MaskMap; } int multiplier = args.ActionType == GPainterActionType.Normal ? 1 : -1; int grassIndex = -1; Vector3 terrainSize = new Vector3( terrain.TerrainData.Geometry.Width, terrain.TerrainData.Geometry.Height, terrain.TerrainData.Geometry.Length); Vector3 localPos = Vector3.zero; Vector3 worldPos = Vector3.zero; Vector3 bary0 = Vector3.zero; Vector3 bary1 = Vector3.zero; Vector2 maskUv = Vector2.zero; Color maskColor = Color.white; Vector3 scale = Vector3.zero; GGrassPatch[] patches = terrain.TerrainData.Foliage.GrassPatches; for (int p = 0; p < patches.Length; ++p) { if (!patches[p].GetUvRange().Overlaps(dirtyRect)) { continue; } List <GGrassInstance> instances = patches[p].Instances; int instanceCount = instances.Count; for (int i = 0; i < instanceCount; ++i) { grassIndex = args.GrassIndices[Random.Range(0, args.GrassIndices.Count)]; GGrassInstance grass = instances[i]; if (grass.PrototypeIndex != grassIndex) { continue; } localPos.Set( grass.position.x * terrainSize.x, grass.position.y * terrainSize.y, grass.position.z * terrainSize.z); worldPos = terrain.transform.TransformPoint(localPos); GUtilities.CalculateBarycentricCoord( new Vector2(worldPos.x, worldPos.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[1].x, args.WorldPointCorners[1].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), ref bary0); GUtilities.CalculateBarycentricCoord( new Vector2(worldPos.x, worldPos.z), new Vector2(args.WorldPointCorners[0].x, args.WorldPointCorners[0].z), new Vector2(args.WorldPointCorners[2].x, args.WorldPointCorners[2].z), new Vector2(args.WorldPointCorners[3].x, args.WorldPointCorners[3].z), ref bary1); if (bary0.x >= 0 && bary0.y >= 0 && bary0.z >= 0) { maskUv = bary0.x * Vector2.zero + bary0.y * Vector2.up + bary0.z * Vector2.one; } else if (bary1.x >= 0 && bary1.y >= 0 && bary1.z >= 0) { maskUv = bary1.x * Vector2.zero + bary1.y * Vector2.one + bary1.z * Vector2.right; } else { continue; } if (clonedMask != null) { maskColor = clonedMask.GetPixelBilinear(maskUv.x, maskUv.y); if (Random.value > maskColor.grayscale) { continue; } } //sample terrain mask if (args.EnableTerrainMask) { maskColor = terrainMask.GetPixelBilinear(grass.position.x, grass.position.z); if (Random.value < maskColor.r) { continue; } } scale.Set( Mathf.Max(0, grass.scale.x + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME), Mathf.Max(0, grass.scale.y + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME), Mathf.Max(0, grass.scale.z + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME)); GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create(); filterArgs.Terrain = terrain; filterArgs.Position = worldPos; filterArgs.Rotation = grass.Rotation; filterArgs.Scale = scale; List <Type> suitableFilter = SuitableFilterTypes; if (args.Filters != null) { for (int fIndex = 0; fIndex < args.Filters.Length; ++fIndex) { if (args.Filters[fIndex] != null && args.Filters[fIndex].Ignore != true) { if (suitableFilter.Contains(args.Filters[fIndex].GetType())) { args.Filters[fIndex].Apply(ref filterArgs); } } if (filterArgs.ShouldExclude) { break; } } } grass.scale = filterArgs.Scale; instances[i] = grass; } patches[p].Changed(); } terrain.TerrainData.Foliage.SetGrassRegionDirty(dirtyRect); GUtilities.MarkCurrentSceneDirty(); }