private void FillUniqueSegments(BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, int node) { var lanePoints = placementAlgorithm.LanePoints; uniqueSegments.Clear(); uniquePoints.Clear(); if (placementAlgorithm.LaneSegments.TryGetValue(node, out var lanes)) { foreach (var lane in lanes) { var currPoint = lanePoints[lane.StartPoint]; if (currPoint.Z != 0) { uniquePoints.Add(currPoint); } for (int i = 1; i < lane.NumPoints; i++) { var prevPoint = currPoint; currPoint = lanePoints[lane.StartPoint + i]; if (currPoint.Z != 0) { uniquePoints.Add(currPoint); } if (prevPoint.Z != 0 || currPoint.Z != 0) { uniqueSegments.Add(new Pair <Vector3>(prevPoint, currPoint)); } } } } }
public BuildingStoryLayoutInstance(IInputService inputService, BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, ICollisionMesh collisionMesh, IStoryLayoutZoning zoning) { this.placementAlgorithm = placementAlgorithm; this.collisionMesh = collisionMesh; this.zoning = zoning; this.inputService = inputService; sg = placementAlgorithm.StoryGraph; }
private BuildingCorridorDiggingResult BuildElevators(BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, int node) { const float offset = BuildingConstants.ElevatorOffset; var negativeElevatorCenter = -(placementAlgorithm.HalfSizes[node].Width + offset) * Vector3.UnitX; var negPoint0 = negativeElevatorCenter + new Vector3(offset, 0, offset); var negPoint1 = negativeElevatorCenter + new Vector3(-offset, 0, offset); var negPoint2 = negativeElevatorCenter + new Vector3(-offset, 0, -offset); var negPoint3 = negativeElevatorCenter + new Vector3(offset, 0, -offset); var positiveElevatorCenter = (placementAlgorithm.HalfSizes[node].Width + offset) * Vector3.UnitX; var posPoint0 = positiveElevatorCenter + new Vector3(-offset, 0, -offset); var posPoint1 = positiveElevatorCenter + new Vector3(offset, 0, -offset); var posPoint2 = positiveElevatorCenter + new Vector3(offset, 0, offset); var posPoint3 = positiveElevatorCenter + new Vector3(-offset, 0, offset); var fullHeight = 2 * placementAlgorithm.HalfSizes[node].Height; var wallSegments = new List <BuildingWallSegment> { new BuildingWallSegment(negPoint0, negPoint1, fullHeight), new BuildingWallSegment(negPoint1, negPoint2, fullHeight), new BuildingWallSegment(negPoint2, negPoint3, fullHeight), new BuildingWallSegment(posPoint0, posPoint1, fullHeight), new BuildingWallSegment(posPoint1, posPoint2, fullHeight), new BuildingWallSegment(posPoint2, posPoint3, fullHeight), }; var children = placementAlgorithm.StoryGraph.Children[node]; var currentHeight = BuildingConstants.CeilingHeight; foreach (var child in children) { var verticalOffset = Vector3.UnitY * currentHeight; var floorHeight = 2 * placementAlgorithm.HalfSizes[child].Height + BuildingConstants.HeightMargin; var separatorHeight = floorHeight - BuildingConstants.CeilingHeight; wallSegments.Add(new BuildingWallSegment(negPoint3 + verticalOffset, negPoint0 + verticalOffset, separatorHeight)); wallSegments.Add(new BuildingWallSegment(posPoint3 + verticalOffset, posPoint0 + verticalOffset, separatorHeight)); currentHeight += floorHeight; } var floorings = new List <AaRectangle2> { new AaRectangle2(negativeElevatorCenter.Xz, offset, offset), new AaRectangle2(positiveElevatorCenter.Xz, offset, offset), }; return(new BuildingCorridorDiggingResult { WallSegments = wallSegments, RawWallSegments = wallSegments, Floorings = floorings }); }
// public IStoryLayoutInstance ArrangeAndDecorate(IStoryGraph sg) { var placementAlgorithm = new BuildingStoryLayoutPlacementAlgorithm(coroutineService, x => ArrangeAndDecorateInternal(sg.Root, x, new List <BuildingWallSegment>()), sg); placementAlgorithm.Run(); var collisionSegments = new List <BuildingWallSegment>(); ArrangeAndDecorateInternal(sg.Root, placementAlgorithm, collisionSegments); var floors = sg.Children[sg.Root] .Select(x => new AaBox(placementAlgorithm.RelativeTransforms[x].Offset, placementAlgorithm.HalfSizes[x])) .ToArray(); var zonesWithProperties = floors.Select(x => Tuples.Pair(x, new StoryLayoutZoneProperties(-15f))).ToArray(); var defaultZoneProperties = new StoryLayoutZoneProperties(0); var zoning = new AaBoxStoryLayoutZoning(zonesWithProperties, defaultZoneProperties); var buildingCollisionMesh = new CollisionMesh(collisionSegments, floors, zoning); return(new BuildingStoryLayoutInstance(inputService, placementAlgorithm, buildingCollisionMesh, zoning)); }
private List <BuildingPrimitive> CreatePrimitives(BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, int node) { var sg = placementAlgorithm.StoryGraph; var primitives = new List <BuildingPrimitive>(); var nodeScale = placementAlgorithm.HalfSizes[node].ToVector(); var mainCorridorScale = new Vector3(nodeScale.X, nodeScale.Y, BuildingConstants.CorridorHalfWidth + MathHelper.Eps5); var mainCorridor = new BuildingPrimitive(BuildingPrimitiveType.Rectangle, mainCorridorScale, Transform.Identity, true); primitives.Add(mainCorridor); foreach (var seg in uniqueSegments) { var forward = seg.Second - seg.First; var halfWidth = forward.Length() / 2; var center = (seg.First + seg.Second) / 2; var scale = new Vector3(halfWidth, 1, BuildingConstants.CorridorHalfWidth); var transform = new Transform(1, Quaternion.RotationToFrame(forward, Vector3.UnitY), center); primitives.Add(new BuildingPrimitive(BuildingPrimitiveType.Rectangle, scale, transform)); } foreach (var point in uniquePoints) { primitives.Add(new BuildingPrimitive(BuildingPrimitiveType.Circle, new Vector3(BuildingConstants.CorridorHalfWidth), Transform.Translation(point))); } foreach (var child in sg.Children[node]) { var scale = placementAlgorithm.HalfSizes[child].ToVector(); var pos = placementAlgorithm.RelativePositions[child]; if (!sg.Children[child].Any()) { scale.Z += BuildingConstants.CorridorHalfWidth / 2; pos.Z -= scale.Z - BuildingConstants.CorridorHalfWidth; } primitives.Add(new BuildingPrimitive(BuildingPrimitiveType.Rectangle, scale, Transform.Translation(pos))); } return(primitives); }
public BuildingCorridorDiggingResult Dig(BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, int node) { var ssg = placementAlgorithm.StoryGraph; if (!ssg.Children[node].Any()) { return new BuildingCorridorDiggingResult { WallSegments = new List <BuildingWallSegment>(), RawWallSegments = new List <BuildingWallSegment>(), Floorings = new List <AaRectangle2>() } } ; if (node == ssg.Root) { return(BuildElevators(placementAlgorithm, node)); } FillUniqueSegments(placementAlgorithm, node); var primitives = CreatePrimitives(placementAlgorithm, node); var wallSegments = BuildWallBasementManaged(primitives); var rawWallSegments = BuildRawWallSegments(primitives); var floorings = new List <AaRectangle2>(); if (ssg.Parents[node] == ssg.Root) { var halfSize = placementAlgorithm.HalfSizes[node]; floorings.Add(new AaRectangle2(Vector2.Zero, halfSize.Width, halfSize.Depth)); } return(new BuildingCorridorDiggingResult { WallSegments = wallSegments, RawWallSegments = rawWallSegments, Floorings = floorings }); }
public BuildingStoryPath(BuildingStoryLayoutPlacementAlgorithm pa, IStoryGraph sg, CameraProps initialCameraProps, int endNodeId, NavigationState navigationState, bool interLevel) { this.pa = pa; this.sg = sg; beziers = new List <BezierQuadratic3>(); var closestNode = sg.Leaves.Minimal(x => (BuildingConstants.LeafHalfSize.Depth * Vector3.UnitZ * GetGlobalTransform(x) - initialCameraProps.Frame.Eye).LengthSquared()); //var closestNodeGlobalTransform = GetGlobalTransform(endNodeId); //var closestNodeCenter = Vector3.Zero * closestNodeGlobalTransform; //var closestNodeConnector = BuildingConstants.LeafHalfSize.Depth * Vector3.UnitZ * closestNodeGlobalTransform; if (closestNode != endNodeId || interLevel) { if (!interLevel && sg.TryFindShortestPath(closestNode, endNodeId, out var nodePath)) { foreach (var edge in nodePath.SequentialPairs()) { IEnumerable <BezierQuadratic3> pathToAdd; if (pa.Lanes.TryGetValue(edge, out var lane)) { pathToAdd = lane.GlobalPath; } else if (pa.Lanes.TryGetValue(edge.Reverse(), out lane)) { pathToAdd = lane.GlobalPath.Reverse().Select(x => x.Reverse()); } else { throw new Exception("Path search returned an unexisting path."); } beziers.AddRange(pathToAdd.Skip(1).ExceptLast()); } } else { var endNode = sg.NodeObjects[endNodeId]; var aEndFocus = endNode.GetComponent <IFocusNodeComponent>(); var endCameraInfo = aEndFocus.DefaultViewpointMechanism.FixedCamera.GetProps(); directPath = new DirectStoryPath(initialCameraProps, endCameraInfo, 1f); } } switch (navigationState) { case NavigationState.AtNode: break; case NavigationState.AtForwardFork: { var nextEdge = new Pair <int>(endNodeId, sg.Next[endNodeId].First()); var nextLane = pa.Lanes[nextEdge]; var lastBezier = nextLane.GlobalPath.First(); var point = lastBezier.At(1); var tangent = lastBezier.TangentAt(1); beziers.Add(BezierQuadratic3.Straight(point - tangent, point)); break; } case NavigationState.AtBackwardFork: { var nextEdge = new Pair <int>(sg.Previous[endNodeId].First(), endNodeId); var nextLane = pa.Lanes[nextEdge]; var lastBezier = nextLane.GlobalPath.Last().Reverse(); var point = lastBezier.At(1); var tangent = lastBezier.TangentAt(1); beziers.Add(BezierQuadratic3.Straight(point - tangent, point)); break; } default: throw new ArgumentOutOfRangeException(nameof(navigationState), navigationState, null); } foreach (var indexPair in Enumerable.Range(0, beziers.Count).SequentialPairs()) { if (beziers[indexPair.First].P2 != beziers[indexPair.Second].P0) { var avg = (beziers[indexPair.First].P2 + beziers[indexPair.Second].P0) / 2; beziers[indexPair.First] = beziers[indexPair.First].With((ref BezierQuadratic3 b) => b.P2 = avg); beziers[indexPair.Second] = beziers[indexPair.Second].With((ref BezierQuadratic3 b) => b.P0 = avg); } } if (!beziers.Any()) { beziers.Add(BezierQuadratic3.Straight(initialCameraProps.Frame.Eye, initialCameraProps.Frame.Eye + initialCameraProps.Frame.Forward)); } path = beziers .SelectMany(x => x.ToEnumPolyline(BezierTolerance)) .SequentialPairs() .Select(x => new PathSegment(x.First, x.Second)) .Where(x => x.Length > 0) .ToArray(); currentCameraProps = initialCameraProps; }
private void ArrangeAndDecorateInternal(int subtreeRoot, BuildingStoryLayoutPlacementAlgorithm placementAlgorithm, List <BuildingWallSegment> globalWallSegments) { var sg = placementAlgorithm.StoryGraph; var node = sg.NodeObjects[subtreeRoot]; var aspect = sg.Aspects[subtreeRoot]; var index = node.Id; var children = sg.Children[index]; foreach (var child in children) { ArrangeAndDecorateInternal(child, placementAlgorithm, globalWallSegments); } var depth = sg.Depths[subtreeRoot]; var hasChildren = children.Any(); var halfSize = placementAlgorithm.HalfSizes[index]; node.Transform = hasChildren ? placementAlgorithm.RelativeTransforms[index] : placementAlgorithm.RelativeTransforms[index] * Transform.Translation(0, BuildingConstants.EyeHeight, 0); var dynamicParts = new StoryNodeDynamicParts(); var visualElems = new List <IVisualElement>(); var corridorDigger = new BuildingCorridorDigger(); var digResult = corridorDigger.Dig(placementAlgorithm, index); var globalTransform = placementAlgorithm.GetGlobalTransform(index); var rootStoryComponent = sg.Aspects[sg.Root]; if (digResult.WallSegments.Any()) { var wallModel = BuildWallModel(digResult.WallSegments); visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent) .SetModel(wallModel) .SetMaterial(wallMaterial) .SetRenderState(StandardRenderState.New() .SetCullFace(CullFace.Back) .FromGlobalCache()) .SetHide(x => x.HideMain)); foreach (var wallSegment in digResult.WallSegments) { globalWallSegments.Add(new BuildingWallSegment { Basement = new LineSegment3( wallSegment.Basement.Point1 * globalTransform, wallSegment.Basement.Point2 * globalTransform), Height = wallSegment.Height }); } var wallPrimitivesModel = BuildWallModel4(digResult.RawWallSegments); visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent) .SetModel(wallPrimitivesModel) .SetMaterial(rawWallMaterial) .SetHide(x => !x.ShowAux3)); var filteredWallPrimitivesModel = BuildWallModel4(digResult.WallSegments); visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent) .SetModel(filteredWallPrimitivesModel) .SetMaterial(rawWallMaterial) .SetHide(x => !x.ShowAux4)); } foreach (var flooring in digResult.Floorings) { visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent) .SetModel(BuildFloorOrCeiling(new Size3(flooring.HalfWidth, 0, flooring.HalfHeight), PlaneModelSourceNormalDirection.Positive)) .SetMaterial(floorMaterial) .SetRenderState(StandardRenderState.New() .SetCullFace(CullFace.Back) .FromGlobalCache()) .SetTransform(Transform.Translation(flooring.Center.X, 0, flooring.Center.Y)) .SetHide(x => x.HideMain)); } if (index == sg.Root) { foreach (var lane in placementAlgorithm.Lanes.Values) { var laneLoc = lane; var navigationService = navigationServiceLazy.Value; var model = BuildLaneModel(lane); visualElems.Add(ModelVisualElement.New() .SetModel(model) .SetMaterial(x => new UnorderedPair <int>(navigationService.Previous.Id, navigationService.Current.Id) == new UnorderedPair <int>(laneLoc.Edge.First, laneLoc.Edge.Second) ? currentLineMaterial : lineMaterial) .SetRenderState(StandardRenderState.New() // todo: remove *5 .SetZOffset(GraphicsHelper.MinZOffset * 5) .SetLineWidth(3) .FromGlobalCache())); } } dynamicParts.Hittable = hasChildren ? new RectangleHittable <ISceneNode>(node, Transform.Rotate(Quaternion.RotationToFrame(Vector3.UnitX, Vector3.UnitZ)), x => new AaRectangle2(Vector2.Zero, halfSize.Width, halfSize.Height), x => - 0.01f * depth) : new RectangleHittable <ISceneNode>(node, new Transform(1, Quaternion.RotationToFrame(Vector3.UnitX, Vector3.UnitZ), new Vector3(0, -BuildingConstants.EyeHeight, 0)), x => new AaRectangle2(Vector2.Zero, halfSize.Width, halfSize.Height), x => - 0.01f * depth); if (depth == 1) { visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent) .SetModel(BuildFloorOrCeiling(halfSize, PlaneModelSourceNormalDirection.Negative)) .SetMaterial(ceilingMaterial) .SetRenderState(StandardRenderState.New() .SetCullFace(CullFace.Back) .FromGlobalCache()) .SetTransform(Transform.Translation(0, BuildingConstants.CeilingHeight, 0)) .SetHide(x => x.HideMain)); } if (hasChildren) { var size = halfSize.ToVector().Length(); dynamicParts.DefaultViewpointMechanism = new WallDefaultViewpointMechanism(node, new TargetedControlledCameraY.Props { Target = Vector3.Zero, Distance = size, FieldOfView = MathHelper.PiOver4, Pitch = MathHelper.PiOver4, Yaw = -MathHelper.PiOver4, ZNear = 0.01f, ZFar = 1000f }); } else { dynamicParts.DefaultViewpointMechanism = new WallDefaultViewpointMechanism(node, new TargetedControlledCameraY.Props { Distance = FrustumDistance, FieldOfView = MathHelper.PiOver4, Pitch = 0, Yaw = 0, ZNear = 0.01f, ZFar = 1000f }); visualElems.Add(new ModelVisualElement <IStoryComponent>(rootStoryComponent) .SetModel(frustumModel) .SetMaterial(frustumMaterial) .SetRenderState(StandardRenderState.New() .SetZOffset(GraphicsHelper.MinZOffset * (depth + 1)) .FromGlobalCache()) .SetHide(x => !x.ShowAux1)); dynamicParts.PlacementSurface2D = new PlanarPlacementSurface(node, new Transform(2f, Quaternion.Identity, new Vector3(0, 0, -MathHelper.FrustumDistance))); dynamicParts.PlacementSurface3D = new PlanarPlacementSurface(node, Transform.Scaling(0.1f)); } dynamicParts.VisualElements = visualElems; aspect.SetDynamicParts(dynamicParts); }