private bool PlaceObjects() { if (Event.current.type != EventType.KeyDown) { return(false); } Event.current.Use(); if (_lastHitTangentSpace == null) { // No location to place something. // But it's handled. return(true); } if (Event.current.keyCode != KeyCode.Space) { // Currently only space is used, ignore the reset... // But it's handled. return(true); } foreach (PlacementLocation location in RandomLocations.Where(rl => rl.HitSurface)) { // Skip when normal too much off. float angle = Vector3.Angle(_lastHitTangentSpace.Up, location.Normal); float thresholdAngle = 45; if (angle > thresholdAngle) { // TOO Steep continue; } GameObject prefab = GetPrefab(); Undo.RegisterCreatedObjectUndo(prefab, "Spawn Objects"); prefab.name += $" ∠{angle}"; prefab.transform.position = location.WorldPosition; prefab.transform.rotation = location.Rotation; if (Container) { prefab.transform.SetParent(Container.transform, true); } } GenerateRandomLocations(SpawnCount, true); return(true); }
private void UpdateSceneUI() { if (Event.current.type != EventType.Repaint || _lastHitTangentSpace == null) { return; } Handles.zTest = CompareFunction.LessEqual; // Draw the current situation. _lastHitTangentSpace.DrawHandles(); // The tangent plane. // Handles.color = new Color(0, 0, 0, .5f); // Handles.DrawSolidDisc(hit.point + hit.normal * .01f, hit.normal, Radius); // The ray plane. // Handles.color = new Color(0, 0, 0, .5f); // Handles.DrawSolidDisc(hit.point + _rayElevationHeight * hit.normal, hit.normal, Radius); DrawBrush(Color.blue, 6f, 256); foreach (PlacementLocation location in RandomLocations.Where(rl => rl.HitSurface)) { // Skip when normal too much off. float angle = Vector3.Angle(_lastHitTangentSpace.Up, location.Normal); float thresholdAngle = 30; GameObject activePrefab = GetActivePrefab(location.PrefabIndex); if (activePrefab == null) { Color handleColor = GetAngleColor(angle, thresholdAngle); // Draw a dot where a placement will occur. Handles.color = handleColor; Handles.SphereHandleCap(-1, location.WorldPosition, Quaternion.identity, .1f, EventType.Repaint); // Draw the local normal Handles.color = Color.black; Handles.DrawAAPolyLine(5f, location.WorldPosition, location.WorldPosition + location.Normal); } else { if (angle > thresholdAngle) { continue; } RenderModelAtLocation(activePrefab, location); } } }
private void UpdatePlacementLocations() { foreach (PlacementLocation location in RandomLocations.ToArray()) { // Scale the point in the unit-circle to a circle of specified radius. Vector2 localPoint = location.UnitLocation * Radius; Ray placementRay = _lastHitTangentSpace.GetTangentRay(localPoint, _rayElevationHeight); bool validSurface = false; bool hitSurface = Physics.Raycast(placementRay, out RaycastHit placementHit); if (hitSurface) { GameObject surfaceObject = placementHit.transform.gameObject; int surfaceLayer = surfaceObject.layer; int surfaceMask = 1 << surfaceLayer; validSurface = (SurfaceLayers.value & surfaceMask) == surfaceMask; } if (validSurface) { // Align the object with the Normal vector of the local plane. Quaternion rotation = Quaternion.FromToRotation(Vector3.up, location.Normal); // Give it a random rotation around the Normal vector. rotation *= location.Orientation; // Quaternion.Euler(0, Random.value * 360, 0); location.HitSurface = true; location.WorldPosition = placementHit.point; location.Normal = placementHit.normal; location.Rotation = rotation; } else { location.HitSurface = false; #if DEBUG location.WorldPosition = Vector3.zero; location.Normal = Vector3.zero; #endif } } }