private void ClearObjects(GStylizedTerrain t) { if (t.TerrainData == null) { return; } Vector3 terrainSize = new Vector3( t.TerrainData.Geometry.Width, t.TerrainData.Geometry.Height, t.TerrainData.Geometry.Length); Vector3 scale = new Vector3( GUtilities.InverseLerpUnclamped(0, terrainSize.x, Scale.x), GUtilities.InverseLerpUnclamped(0, terrainSize.y, Scale.y), GUtilities.InverseLerpUnclamped(0, terrainSize.z, Scale.z)); Matrix4x4 matrix = Matrix4x4.TRS( t.WorldPointToNormalized(Position), Rotation, scale); Matrix4x4 normalizeToStamp = matrix.inverse; GSpawner.DestroyIf(t, (g) => { Vector3 normalizePos = t.WorldPointToNormalized(g.transform.position); Vector3 stampSpacePos = normalizeToStamp.MultiplyPoint(normalizePos); return (stampSpacePos.x >= -0.5f && stampSpacePos.x <= 0.5f && stampSpacePos.y >= 0f && stampSpacePos.y <= 1f && stampSpacePos.z >= -0.5f && stampSpacePos.z <= 0.5f); }); }
private void RemoveObjectFromTerrain(GStylizedTerrain t, Color[] maskData) { for (int i = 0; i < PrototypeIndices.Count; ++i) { int prototypeIndex = PrototypeIndices[i]; if (prototypeIndex < 0 || prototypeIndex >= Prototypes.Count) { continue; } GameObject g = Prototypes[prototypeIndex]; if (g == null) { continue; } GSpawner.DestroyIf(t, g, (instance) => { Vector2 uv = t.WorldPointToUV(instance.transform.position); float alpha = GUtilities.GetColorBilinear(maskData, MaskResolution, MaskResolution, uv).r; return(Random.value <= alpha); }); } }
private void SpawnObjectOnTerrain(GStylizedTerrain t, Color[] maskData, int layerIndex) { GObjectStampLayer layer = Layers[layerIndex]; Vector3 centerPos = Vector3.zero; Vector3 samplePos = Vector3.zero; Vector2 uv = Vector2.zero; float maskValue = 0; Vector3 terrainSize = new Vector3( t.TerrainData.Geometry.Width, t.TerrainData.Geometry.Height, t.TerrainData.Geometry.Length); Vector3 scale = new Vector3( GUtilities.InverseLerpUnclamped(0, terrainSize.x, Scale.x), 1, GUtilities.InverseLerpUnclamped(0, terrainSize.z, Scale.z)); Matrix4x4 matrix = Matrix4x4.TRS( t.WorldPointToNormalized(Position), Rotation, scale); int index = -1; int instanceCount = 0; int attempt = 0; int maxAttempt = layer.InstanceCount * 100; RaycastHit hit; #if UNITY_EDITOR string title = "Stamping on " + t.name; string info = string.Format("Layer: {0}", !string.IsNullOrEmpty(layer.Name) ? layer.Name : layerIndex.ToString()); int currentPercent = 0; int attemptPercent = 0; int instancePercent = 0; GCommonGUI.CancelableProgressBar(title, info, 0); #endif while (instanceCount < layer.InstanceCount && attempt <= maxAttempt) { attempt += 1; #if UNITY_EDITOR attemptPercent = (int)(attempt * 100.0f / maxAttempt); instancePercent = (int)(instanceCount * 100.0f / layer.InstanceCount); if (currentPercent != Mathf.Max(attemptPercent, instancePercent)) { currentPercent = Mathf.Max(attemptPercent, instancePercent); GCommonGUI.CancelableProgressBar(title, string.Format("{0} ... {1}%", info, currentPercent), currentPercent / 100.0f); } #endif index = layer.PrototypeIndices[Random.Range(0, layer.PrototypeIndices.Count)]; if (index < 0 || index >= layer.Prototypes.Count) { continue; } GameObject g = layer.Prototypes[index]; if (g == null) { continue; } centerPos.Set(Random.value - 0.5f, 0, Random.value - 0.5f); samplePos = matrix.MultiplyPoint(centerPos); if (samplePos.x < 0 || samplePos.x > 1 || samplePos.z < 0 || samplePos.z > 1) { continue; } uv.Set(samplePos.x, samplePos.z); maskValue = GUtilities.GetColorBilinear(maskData, MaskResolution, MaskResolution, uv).r; if (Random.value > maskValue) { continue; } if (t.Raycast(samplePos, out hit)) { GameObject instance = GSpawner.Spawn(t, g, hit.point); instance.transform.rotation = Quaternion.Euler(0, Random.Range(layer.MinRotation, layer.MaxRotation), 0); instance.transform.localScale = Vector3.Lerp(layer.MinScale, layer.MaxScale, Random.value); if (layer.AlignToSurface) { instance.transform.up = hit.normal; } instanceCount += 1; } } #if UNITY_EDITOR GCommonGUI.ClearProgressBar(); #endif }
public void Paint(Pinwheel.Griffin.GStylizedTerrain terrain, GObjectPainterArgs args) { if (args.MouseEventType == GPainterMouseEventType.Up) { 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; } 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 prototypeIndex = -1; Vector2 terrainUv = Vector2.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; for (int i = 0; i < args.PrototypeIndices.Count; ++i) { prototypeIndex = args.PrototypeIndices[i]; if (prototypeIndex < 0 || prototypeIndex >= args.Prototypes.Count) { continue; } GameObject g = args.Prototypes[prototypeIndex]; if (g == null) { continue; } GameObject root = GSpawner.GetRoot(terrain, g); Transform[] instances = GUtilities.GetChildrenTransforms(root.transform); int instanceCount = instances.Length; for (int j = 0; j < instanceCount; ++j) { worldPos = instances[j].position; 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; } } if (args.EnableTerrainMask) { terrainUv = terrain.WorldPointToUV(worldPos); maskColor = terrainMask.GetPixelBilinear(terrainUv.x, terrainUv.y); if (Random.value < maskColor.r) { continue; } } scale.Set( Mathf.Max(0, instances[j].transform.localScale.x + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME), Mathf.Max(0, instances[j].transform.localScale.y + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME), Mathf.Max(0, instances[j].transform.localScale.z + multiplier * maskColor.grayscale * args.ScaleStrength * GUtilities.DELTA_TIME)); GSpawnFilterArgs filterArgs = GSpawnFilterArgs.Create(); filterArgs.Terrain = terrain; filterArgs.Position = worldPos; filterArgs.Rotation = instances[j].transform.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; } } } instances[j].transform.localScale = filterArgs.Scale; } } }
private void HandleSpawnObject(GStylizedTerrain terrain, GObjectPainterArgs args) { int prototypeIndex = -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; Color maskColor = Color.white; Texture2D clonedMask = null; if (args.Mask != null) { clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256); } for (int i = 0; i < args.Density; ++i) { prototypeIndex = args.PrototypeIndices[Random.Range(0, args.PrototypeIndices.Count)]; if (prototypeIndex < 0 || prototypeIndex >= args.Prototypes.Count) { continue; } GameObject g = args.Prototypes[prototypeIndex]; if (g == null) { 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; } } //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; } //spawn here GameObject instance = GSpawner.Spawn(terrain, g, samplePoint.point); instance.transform.position = filterArgs.Position; instance.transform.rotation = filterArgs.Rotation; instance.transform.localScale = filterArgs.Scale; } } if (clonedMask != null) { Object.DestroyImmediate(clonedMask); } }
private void HandleEraseObject(GStylizedTerrain terrain, GObjectPainterArgs args) { int prototypeIndex = -1; 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; if (args.Mask != null) { clonedMask = GCommon.CloneAndResizeTexture(args.Mask, 256, 256); } for (int i = 0; i < args.PrototypeIndices.Count; ++i) { prototypeIndex = args.PrototypeIndices[i]; if (prototypeIndex < 0 || prototypeIndex >= args.Prototypes.Count) { continue; } GameObject g = args.Prototypes[prototypeIndex]; if (g == null) { continue; } GSpawner.DestroyIf(terrain, g, (instance => { worldPos = instance.transform.position; 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); } } return(true); })); } if (clonedMask != null) { Object.DestroyImmediate(clonedMask); } }
private void SpawnObjectsOnTerrain(GStylizedTerrain t, Color[] maskData, List <Vector4> vertices) { int prototypeIndex = -1; Vector2 v0 = Vector2.zero; Vector2 v1 = Vector2.zero; Vector2 v2 = Vector2.zero; Vector2 center = Vector2.zero; float radius = 0; Vector2 pos = Vector2.zero; Vector3 bary = Vector3.zero; float maskValue = 0; RaycastHit hit; int trisCount = vertices.Count / 3; for (int i = 0; i < trisCount; ++i) { v0 = t.WorldPointToUV(vertices[i * 3 + 0]); v1 = t.WorldPointToUV(vertices[i * 3 + 1]); v2 = t.WorldPointToUV(vertices[i * 3 + 2]); center = (v0 + v1 + v2) / 3; radius = Vector2.Distance(center, v0); for (int s = 0; s < Density; ++s) { prototypeIndex = PrototypeIndices[Random.Range(0, PrototypeIndices.Count)]; if (prototypeIndex < 0 || prototypeIndex >= Prototypes.Count) { continue; } GameObject g = Prototypes[prototypeIndex]; if (g == null) { continue; } pos = center + Random.insideUnitCircle * radius; if (pos.x < 0 || pos.x > 1 || pos.y < 0 || pos.x > 1) { continue; } GUtilities.CalculateBarycentricCoord(pos, v0, v1, v2, ref bary); if (bary.x < 0 || bary.y < 0 || bary.z < 0) { continue; } maskValue = GUtilities.GetColorBilinear(maskData, MaskResolution, MaskResolution, pos).r; if (Random.value > maskValue) { continue; } if (t.Raycast(pos.ToX0Y(), out hit)) { GameObject instance = GSpawner.Spawn(t, g, hit.point); instance.transform.rotation = Quaternion.Euler(0, Random.Range(MinRotation, MaxRotation), 0); instance.transform.localScale = Vector3.Lerp(MinScale, MaxScale, Random.value); if (AlignToSurface) { instance.transform.up = hit.normal; } } } } }