private IVisualElement CorridorWall(Quaternion rotation, Vector3 position) { return(ModelVisualElement.New() .SetModel(corridorWallModel) .SetMaterial(wallMaterial) .SetTransform(new Transform(1, -rotation, position + Vector3.UnitZ * centerHeight))); }
private void ArrangeAndDecorateLeaf(int nodeIndex, IStoryGraph sg) { var aStory = sg.Aspects[nodeIndex]; var node = sg.NodeObjects[nodeIndex]; var wallVisuals = CorridorWall(Quaternion.Identity, Vector3.UnitY * FrustumDistance); var frustumVisuals = ModelVisualElement.New() .SetModel(frustumModel) .SetMaterial(frustumMaterial) .SetRenderState(StandardRenderState.New() .SetCullFace(CullFace.Back) .FromGlobalCache()) .SetTransform(new Transform(1, Quaternion.RotationX(-MathHelper.PiOver2), Vector3.Zero)); var visuals = new [] { frustumVisuals, wallVisuals }; var viewpointProps = new TargetedControlledCamera.Props { Target = Vector3.Zero, Distance = FrustumDistance, FieldOfView = MathHelper.PiOver4, ZNear = 0.1f * FrustumDistance, ZFar = 100.0f * FrustumDistance }; var transform2D = new Transform(2, Quaternion.RotationX(-MathHelper.PiOver2), FrustumDistance * Vector3.UnitY); aStory.SetDynamicParts(new StoryNodeDynamicParts { DefaultViewpointMechanism = new WallDefaultViewpointMechanismZ(node, viewpointProps), Hittable = GetHittableComponent(node, transform2D), VisualElements = visuals }); }
public void OnQueryServiceUpdated() { visualElements.Clear(); optionRects.Clear(); currentQuery = queryService.Queries.LastOrDefault() as OptionsUserQuery; if (currentQuery == null || !currentQuery.Options.Any()) { return; } const float OptionMargin = 0.1f; const float OptionHalfHeight = 0.09f; const float OptionHalfWidth = 0.9f; var currentY = 1f; for (var i = 0; i < currentQuery.Options.Count; i++) { currentY -= OptionMargin; currentY -= OptionHalfHeight; optionRects.Add(new AaRectangle2(new Vector2(0, currentY), OptionHalfWidth, OptionHalfHeight)); currentY -= OptionHalfHeight; currentY -= OptionMargin; } var totalHeight = 1f - currentY; var centerY = 1f - totalHeight / 2; for (int i = 0; i < currentQuery.Options.Count; i++) { var option = currentQuery.Options[i]; var rect = optionRects[i]; rect.Center.Y -= centerY; optionRects[i] = rect; var textBox = RichTextHelper.Label(option, new IntSize2((int)(2 * 512 * OptionHalfWidth), (int)(2 * 512 * OptionHalfHeight)), RtParagraphAlignment.Center, Color4.Black, RtTransparencyMode.Opaque, "Arial", 32, Color4.Orange, FontDecoration.None); var textImageRgba = textImageBuilder.BuildImageRgba(textBox); var textImage = new RawImage(ResourceVolatility.Immutable, textBox.Size, false, textImageRgba); visualElements.Add(ModelVisualElement.New() .SetModel(planeModel) .SetMaterial(StandardMaterial.New() .SetDiffuseMap(textImage) .SetIgnoreLighting(true) .FromGlobalCache()) .SetTransform(Transform.Translation(new Vector3(rect.Center, 0))) .SetNonUniformScale(new Vector3(rect.HalfWidth, rect.HalfHeight, 1))); } }
private ModelVisualElement <object> CreateLaneElem(Vector3 prevPoint, Vector3 currPoint, int disambiguator, int depth) { return(ModelVisualElement.New() .SetModel(lineModel) .SetMaterial(lineMaterial) .SetRenderState(StandardRenderState.New() .SetLineWidth(3) .SetZOffset(GraphicsHelper.MinZOffset * (depth + 1)) .FromGlobalCache()) .SetTransform(CalcCorridorSegmentTransform(prevPoint, currPoint, disambiguator))); }
protected ResizeRectangleGizmoComponent(IInputHandler inputHandler, IEmbeddedResources embeddedResources, IUndoRedoService undoRedo) { visualElement = ModelVisualElement.New() .SetModel(embeddedResources.CubeModel()) .SetMaterial(StandardMaterial.New() .SetNoSpecular(true) .FromGlobalCache()) .SetTransform(Transform.Scaling(0.025f)); interactionElement = new ResizeRectangleInteractionElement <ResizeRectangleGizmoComponent>( this, x => x.GetRectAspect(), x => x.GetChildSpace(), x => x.Place, inputHandler, undoRedo); hittable = new SphereHittable <ResizeRectangleGizmoComponent>(this, x => { var globalTransform = Node.GlobalTransform; return(new Sphere(globalTransform.Offset, 0.025f * globalTransform.Scale)); }); }
private void ArrangeAndDecorateInternal(IStoryGraph sg, int nodeIndex, int scaleLevel) { var aStory = sg.Aspects[nodeIndex]; var node = sg.NodeObjects[nodeIndex]; var abstractChildren = sg.Children[nodeIndex]; var numChildren = abstractChildren.Count; var scale = MathHelper.Pow(4, scaleLevel); var visuals = new [] { ModelVisualElement.New() .SetModel(planeModel) .SetMaterial(planeMaterials[scaleLevel % planeMaterials.Length]) .SetTransform(Transform.Scaling(10 * scale)) }; var viewpointProps = new FreeControlledCamera.Props { Eye = Vector3.UnitZ * 10f * scale, Yaw = MathHelper.PiOver4, Pitch = MathHelper.PiOver4, FieldOfView = MathHelper.PiOver4, ZNear = 0.1f * scale, ZFar = 100.0f * scale }; for (var i = 0; i < numChildren; i++) { var adaptiveChild = abstractChildren[i]; var angle = MathHelper.TwoPi * i / numChildren - MathHelper.PiOver4; var rotation = Quaternion.RotationZ(angle); var radius = scale * GetBestRadius(numChildren); var offset = new Vector3(radius * MathHelper.Sin(angle), radius * MathHelper.Cos(angle), 0.1f * scale); sg.NodeObjects[adaptiveChild].Transform = new Transform(1, rotation, offset); ArrangeAndDecorateInternal(sg, adaptiveChild, scaleLevel - 1); } aStory.SetDynamicParts(new StoryNodeDynamicParts { DefaultViewpointMechanism = new FreeLandDefaultViewpointMechanism(node, viewpointProps, keyboardInputProvider), Hittable = GetHittableComponent(node), VisualElements = visuals }); }
private void Rebuild() { if (SpherePackingResult == null) { return; } var material = StandardMaterial.New(this) .SetDiffuseColor(x => x.Color); visualElems = SpherePackingResult.Points.Select(p => ModelVisualElement.New(this) .SetModel(embeddedResources.SphereModel(64)) .SetTransform(x => new Transform(x.Radius, Quaternion.Identity, p)) .SetMaterial(material)) .Cast <IVisualElement>() .ToArray(); LocalBoundingSphere = Sphere.BoundingSphere(SpherePackingResult.Points); }
public IEnumerable <IVisualElement> GetVisualElements() { yield return(borderVisualElement); yield return(backgroundVisualElement); for (int i = 0; i < solvingProcess.Packer.NumCircles; i++) { var iLoc = i; if (circleVisualElements.Count <= i) { circleVisualElements.Add(ModelVisualElement.New(this) .SetModel(x => x.embeddedResources.CircleModel(64)) .SetMaterial(StandardMaterial.New(this) .SetIgnoreLighting(true) .SetDiffuseColor(x => x.ColorForStatus(x.solvingProcess.Packer.FrontCircleStatuses[iLoc]))) .SetTransform(x => new Transform(x.solvingProcess.Packer.CircleRadius, Quaternion.Identity, new Vector3(x.solvingProcess.Packer.FrontCircleCenters[iLoc], 0)))); } yield return(circleVisualElements[i]); } }
protected CirclePackingAutoComponent(IEmbeddedResources embeddedResources, IViewService viewService, ICoroutineService coroutineService) { this.embeddedResources = embeddedResources; this.coroutineService = coroutineService; solver = new CirclePackingSolver(); Reset(); borderModel = new ExplicitModel(ResourceVolatility.Stable) { IndexSubranges = new ExplicitModelIndexSubrange[1], Topology = ExplicitModelPrimitiveTopology.LineStrip }; backgroundVisualElement = ModelVisualElement.New(this) .SetModel(embeddedResources.SimplePlaneXyModel()) .SetMaterial(StandardMaterial.New() .SetIgnoreLighting(true) .SetDiffuseColor(Color4.Black) .FromGlobalCache()) .SetRenderState(StandardRenderState.New() .SetZOffset(-GraphicsHelper.MinZOffset)) .SetTransform(x => Transform.Translation(new Vector3(x.border.BoundingRect.Center, 0))) .SetNonUniformScale(x => new Vector3( x.border.BoundingRect.HalfWidth, x.border.BoundingRect.HalfHeight, 1)); borderVisualElement = ModelVisualElement.New(this) .SetModel(x => x.GetRelevantBorderModel()) .SetMaterial(StandardMaterial.New() .SetDiffuseColor(Color4.Yellow) .SetIgnoreLighting(true) .FromGlobalCache()); circleVisualElements = new List <IVisualElement>(); selectOnClickInterationElement = new SelectOnClickInteractionElement(this, viewService); // todo: make precise hittable = new RectangleHittable <CirclePackingAutoComponent>(this, Transform.Identity, x => x.border.BoundingRect, x => 0); }
private void Reset() { simulationRunning = false; simulationTimestamp = 0; prevQueue = new Queue <FluidSimulationFrame>(); var size = new IntSize3(Width, Height, 1); var cellSize = CellSize; fluidSimulation.Reset(CreateConfig()); model = CreateModel(size, cellSize, fluidSimulation.Particles.Length); levelSetImageData = new byte[fluidSimulation.LevelSet.Size.Width * fluidSimulation.LevelSet.Size.Height * 4]; levelSetImage = new RawImage(ResourceVolatility.Volatile, new IntSize2(fluidSimulation.LevelSet.Size.Width, fluidSimulation.LevelSet.Size.Height), true, levelSetImageData); squareModel = embeddedResources.SimplePlaneXyModel(); visualElements.Clear(); visualElements.Add(ModelVisualElement.New() .SetModel(model) .SetMaterial(StandardMaterial.New() .SetDiffuseColor(Color4.Yellow) .SetIgnoreLighting(true) .FromGlobalCache())); visualElements.Add(ModelVisualElement.New() .SetModel(model) .SetModelPartIndex(1) .SetMaterial(StandardMaterial.New() .SetDiffuseColor(Color4.White) .SetIgnoreLighting(true) .FromGlobalCache()) .SetRenderState(StandardRenderState.New() .SetPointSize(3) .FromGlobalCache())); visualElements.Add(ModelVisualElement.New() .SetModel(squareModel) .SetMaterial(StandardMaterial.New() .SetDiffuseMap(levelSetImage) .SetIgnoreLighting(true) .FromGlobalCache()) .SetTransform(new Transform(cellSize * size.Width / 2, Quaternion.Identity, new Vector3(cellSize * size.Width / 2, cellSize * size.Height / 2, -0.1f)))); }
private void ArrangeAndDecorateRoot(IStoryGraph sg) { var nodeIndex = sg.Root; var aStory = sg.Aspects[nodeIndex]; var node = sg.NodeObjects[nodeIndex]; var adaptiveChildren = sg.Children[nodeIndex]; var numChildren = adaptiveChildren.Count; var visuals = new List <IVisualElement>(); // todo: refactor to CenterLayout struct var wallRadius = 1f; var alpha = MathHelper.PiOver2; if (numChildren > 2) { alpha = MathHelper.TwoPi / (2 * numChildren); wallRadius = corridorHalfWidth / MathHelper.Tan(alpha / 2f); } for (int i = 0; i < numChildren; i++) { var centerAngle = alpha * (1 + 2 * i); var pos = new Vector3( wallRadius * MathHelper.Cos(centerAngle), wallRadius * MathHelper.Sin(centerAngle), 0); var rotation = Quaternion.RotationZ(-centerAngle + MathHelper.PiOver2); visuals.Add(CorridorWall(rotation, pos)); } for (int i = 0; i < numChildren; i++) { var child = adaptiveChildren[i]; var centerAngle = alpha * (2 * i); var doorPos = new Vector3( wallRadius * MathHelper.Cos(centerAngle), wallRadius * MathHelper.Sin(centerAngle), 0); var forward = doorPos.Normalize(); var rotation = Quaternion.RotationZ(-centerAngle + MathHelper.PiOver2); if (sg.Children[child].Any()) { sg.NodeObjects[child].Transform = new Transform(1, rotation, doorPos); ArrangeAndDecorateIntermediate(child, sg); } else { sg.NodeObjects[child].Transform = new Transform(1, rotation, doorPos - forward * FrustumDistance); ArrangeAndDecorateLeaf(child, sg); } } // floor visuals.Add(ModelVisualElement.New() .SetModel(floorModel) .SetMaterial(floorMaterial) .SetRenderState(StandardRenderState.New() .SetCullFace(CullFace.Back) .FromGlobalCache()) .SetTransform(new Transform(1, Quaternion.Identity, new Vector3(0, 0, centerHeight - ceilingHalfHeight)))); // ceiling visuals.Add(ModelVisualElement.New() .SetModel(ceilingModel) .SetMaterial(ceilingMaterial) .SetRenderState(StandardRenderState.New() .SetCullFace(CullFace.Back) .FromGlobalCache()) .SetTransform(new Transform(1, Quaternion.Identity, new Vector3(0, 0, centerHeight + ceilingHalfHeight)))); var viewpointProps = new LookAroundCamera.Props { Distance = 24, FieldOfView = MathHelper.PiOver2, ZNear = 0.1f, ZFar = 100.0f, Pitch = 0 }; aStory.SetDynamicParts(new StoryNodeDynamicParts { DefaultViewpointMechanism = new SphereDefaultViewpointMechanism(node, viewpointProps), Hittable = new DummyHittable(), VisualElements = visuals }); }
private void ArrangeAndDecorateInternal(IStoryGraph sg, int nodeId, AaRectangle2 yawPitchBounds, float radius) { var cStory = sg.Aspects[nodeId]; var node = sg.NodeObjects[nodeId]; var children = sg.Children[nodeId]; var numChildren = children.Count; var yaw = yawPitchBounds.Center.X; var pitch = yawPitchBounds.Center.Y; var pos = ToCartesian(yaw, pitch, radius); var zAxis = (-pos).Normalize(); var xAxis = Vector3.Cross(Vector3.UnitY, zAxis).Normalize(); var yAxis = Vector3.Cross(zAxis, xAxis); var rotation = Quaternion.RotationToFrame(xAxis, yAxis); node.Transform = new Transform(1, rotation, pos); var numRows = (int)Math.Ceiling(MathHelper.Sqrt(numChildren)); var numCols = (int)Math.Ceiling((float)numChildren / numRows); var totalHeightRequired = MinVerticalDistance * numRows; var totalWidthRequired = MinHorizontalDistance * numRows; var minChildrenRadius = Math.Max(totalWidthRequired / yawPitchBounds.Width, totalHeightRequired / yawPitchBounds.Height); var childRadius = Math.Max(radius + MinRadiusDistance, minChildrenRadius); for (var i = 0; i < numChildren; i++) { var child = children[i]; var row = i / numCols; var col = i % numCols; var childYawWidth = yawPitchBounds.Width / numCols; var childYawHeight = yawPitchBounds.Height / numRows; var childYaw = yawPitchBounds.MinX + childYawWidth * (row + 0.5f); var childPitch = yawPitchBounds.MinY + childYawHeight * (col * 0.5f); var childYawPitchBounds = AaRectangle2.FromCenter(new Vector2(childYaw, childPitch), HalfWidth / childRadius, HalfHeight / childRadius); ArrangeAndDecorateInternal(sg, child, childYawPitchBounds, childRadius); } var visuals = new [] { ModelVisualElement.New(sg.Aspects[sg.Root]) .SetModel(frustumModel) .SetMaterial(frustumMaterial) .SetTransform(new Transform(0.5f, Quaternion.Identity, new Vector3(0, 0, 0.5f * MathHelper.FrustumDistance))) .SetHide(x => !x.ShowAux1) }; var viewpointProps = new TargetedControlledCameraY.Props { Target = Vector3.Zero, Distance = MathHelper.FrustumDistance, FieldOfView = MathHelper.PiOver4, ZNear = 0.1f, ZFar = 100.0f }; var transform2D = new Transform(2, Quaternion.Identity, -MathHelper.FrustumDistance * Vector3.UnitZ); cStory.SetDynamicParts(new StoryNodeDynamicParts { DefaultViewpointMechanism = new WallDefaultViewpointMechanism(node, viewpointProps), Hittable = GetHittableComponent(node, transform2D), VisualElements = visuals, PlacementSurface2D = new PlanarPlacementSurface(node, Transform.Identity), PlacementSurface3D = new PlanarPlacementSurface(node, new Transform(0.05f, Quaternion.Identity, new Vector3(0, 0, 0.5f * MathHelper.FrustumDistance))) }); }
private void ArrangeAndDecorateLevel(IStoryGraph sg, int nodeIndex, int scaleLevel, bool isRoot) { var aStory = sg.Aspects[nodeIndex]; var node = sg.NodeObjects[nodeIndex]; var abstractChildren = sg.Children[nodeIndex]; var scale = MathHelper.Pow(2, scaleLevel / 4f); var halfSize = 1f; var fov = MathHelper.PiOver4; var distance = halfSize / MathHelper.Tan(fov / 2); var visuals = new List <IVisualElement>(); visuals.Add(ModelVisualElement.New() .SetModel(frustumModel) .SetMaterial(frustumMaterial)); var viewpointProps = isRoot ? new TargetedControlledCameraY.Props { Target = Vector3.Zero, Distance = distance * 10, Pitch = MathHelper.Pi * 0.1f, FieldOfView = fov, ZNear = 0.1f * distance * scale, ZFar = 100.0f * distance * scale } : new TargetedControlledCameraY.Props { Target = Vector3.Zero, Distance = distance, FieldOfView = fov, ZNear = 0.1f * distance * scale, ZFar = 100.0f * distance * scale }; if (isRoot) { // todo: change into additional local transform, or move to a 3D child space node.Transform = new Transform(1, Quaternion.RotationToFrame(Vector3.UnitX, Vector3.UnitZ), Vector3.Zero); } for (int i = 0; i < abstractChildren.Count; i++) { var adaptiveChild = abstractChildren[i]; var childBoundingRadius = 5 * scale; var angle = MathHelper.Pi * 0.33f + 3 * MathHelper.TwoPi / 5 * i; var rotation = Quaternion.RotationY(-angle + MathHelper.Pi); var childScalingCompoensation = 10f; var radius = isRoot ? (childBoundingRadius / 3) * (2 + i) * childScalingCompoensation : (childBoundingRadius / 3) * (2 + i * 0.5f) * childScalingCompoensation * 0.5f; var offset = new Vector3(radius * MathHelper.Sin(angle), 0, radius * MathHelper.Cos(angle)); sg.NodeObjects[adaptiveChild].Transform = new Transform(5, rotation, offset); ArrangeAndDecorateLevel(sg, adaptiveChild, scaleLevel - 1, false); visuals.Add(ModelVisualElement.New() .SetModel(circleModel) .SetMaterial(circleMaterial) .SetTransform(new Transform(radius / childScalingCompoensation, Quaternion.RotationToFrame(Vector3.UnitX, Vector3.UnitZ), Vector3.Zero))); } aStory.SetDynamicParts(new StoryNodeDynamicParts { DefaultViewpointMechanism = new WallDefaultViewpointMechanism(node, viewpointProps), Hittable = GetHittableComponent(node), VisualElements = visuals }); }
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); }