private static OutlineItem CreateOutlineItem(SceneNode sceneNode) { var item = new OutlineItem { Text = $"{sceneNode.GetType().Name} \"{sceneNode.Name}\"", Icon = MultiColorGlyphs.SceneNode, Children = new OutlineItemCollection(), ToolTip = ToolTipSceneNode, UserData = sceneNode, }; if (sceneNode is MeshNode) item.Icon = MultiColorGlyphs.Mesh; if (sceneNode.Children != null) foreach (var child in sceneNode.Children) if (child != null) item.Children.Add(CreateOutlineItem(child)); var mesh = (sceneNode as MeshNode)?.Mesh; if (mesh != null) item.Children.Add(CreateOutlineItem(mesh)); return item; }
protected virtual void CloneCore(SceneNode source) { _flags = source._flags; Name = source.Name; ScaleLocal = source.ScaleLocal; PoseLocal = source.PoseLocal; LastScaleWorld = source.LastScaleWorld; LastPoseWorld = source.LastPoseWorld; Shape = source.Shape; // Shallow copy. MaxDistance = source.MaxDistance; SortTag = source.SortTag; UserData = source.UserData; // Do not clone: RenderData, SceneData if (source.Children != null) { if (Children == null) Children = new SceneNodeCollection(); else Children.Clear(); foreach (var child in source.Children) Children.Add(child.Clone()); } }
/// <inheritdoc/> protected override void CloneCore(SceneNode source) { base.CloneCore(source); var sourceTyped = (ProxyNode)source; SetNode((sourceTyped.Node != null) ? sourceTyped.Node.Clone() : null); Shape = sourceTyped.Shape.Clone(); }
// CloneCore() is called to initialize the clone. protected override void CloneCore(SceneNode source) { // Clone the SceneNode properties (base class). base.CloneCore(source); // Clone the TextNode properties. var sourceTextNode = (TextNode)source; Color = sourceTextNode.Color; Text = sourceTextNode.Text; }
/// <summary> /// Creates an instance of the <see cref="SceneChangedEventArgs"/> class. (This method reuses a /// previously recycled instance or allocates a new instance if necessary.) /// </summary> /// <param name="sceneNode">The scene node.</param> /// <param name="changes">The changes.</param> /// <returns> /// A new or reusable instance of the <see cref="SceneChangedEventArgs"/> class. /// </returns> /// <remarks> /// <para> /// This method tries to obtain a previously recycled instance from a resource pool if resource /// pooling is enabled (see <see cref="ResourcePool.Enabled">ResourcePool.Enabled</see>). If no /// object is available, a new instance is automatically allocated on the heap. /// </para> /// <para> /// The owner of the object should call <see cref="Recycle"/> when the instance is no longer /// needed. /// </para> /// </remarks> /// <exception cref="ArgumentNullException"> /// <paramref name="sceneNode"/> is <see langword="null"/>. /// </exception> public static SceneChangedEventArgs Create(SceneNode sceneNode, SceneChanges changes) { if (sceneNode == null) throw new ArgumentNullException("sceneNode"); var args = Pool.Obtain(); args.SceneNode = sceneNode; args.Changes = changes; return args; }
private void AddSubtree(SceneNode node) { if (node.IsEnabled) { AddNode(node); if (node.Children != null) foreach (var childNode in node.Children) AddSubtree(childNode); } }
private void AddNode(SceneNode node) { var proxyNode = node as ProxyNode; if (proxyNode != null) { if (proxyNode.Node != null) AddSubtree(proxyNode.Node); } else { SceneNodes.Add(node); } }
public void Set(SceneNode referenceNode, IList<SceneNode> nodes, RenderContext context) { Reset(); ReferenceNode = referenceNode; int numberOfNodes = nodes.Count; for (int i = 0; i < numberOfNodes; i++) { var node = nodes[i]; Debug.Assert(node.ActualIsEnabled, "Scene query contains disabled nodes."); SceneNodes.Add(node); } }
public void Set(SceneNode referenceNode, IList<SceneNode> nodes) { Reset(); ReferenceNode = referenceNode; for (int i = 0; i < nodes.Count; i++) { var node = nodes[i]; if (node.IsRenderable) { RenderableNodes.Add(node); } } }
public void Set(SceneNode referenceNode, IList<SceneNode> nodes, RenderContext context) { Reset(); ReferenceNode = referenceNode; int numberOfNodes = nodes.Count; for (int i = 0; i < numberOfNodes; i++) { var node = nodes[i]; if ((WboitFlags)node.UserFlags == WboitFlags.Transparent) TransparentNodes.Add(node); else SceneNodes.Add(node); } }
public void Set(SceneNode referenceNode, IList<SceneNode> nodes, RenderContext context) { Reset(); ReferenceNode = referenceNode; int numberOfNodes = nodes.Count; for (int i = 0; i < numberOfNodes; i++) { var fogNode = nodes[i] as FogNode; if (fogNode != null) { Debug.Assert(fogNode.ActualIsEnabled, "Scene query contains disabled nodes."); FogNodes.Add(fogNode); } } // Sort fog nodes. FogNodes.Sort(DescendingFogNodeComparer.Instance); }
public void Set(SceneNode referenceNode, IList<SceneNode> nodes, RenderContext context) { Reset(); ReferenceNode = referenceNode; for (int i = 0; i < nodes.Count; i++) { #if !XBOX360 if (nodes[i] is TerrainNode) TerrainNodes.Add(nodes[i]); #endif if (nodes[i] is CloudLayerNode) CloudLayerNodes.Add(nodes[i]); else if (nodes[i] is WaterNode) WaterNodes.Add(nodes[i]); else if (nodes[i] is SceneCaptureNode) SceneCaptureNodes.Add(nodes[i]); else if (nodes[i] is PlanarReflectionNode) PlanarReflectionNodes.Add(nodes[i]); } }
//-------------------------------------------------------------- /// <inheritdoc/> public override bool CanRender(SceneNode node, RenderContext context) { return node is PlanarReflectionNode; }
// OnLoad() is called when the GameObject is added to the IGameObjectService. protected override void OnLoad() { var particleSystemService = _services.GetInstance<IParticleSystemService>(); // The campfire consists of two particle systems (fire + smoke) and a light source. // // _campfire (SceneNode) // | // +-- _fireParticles (ParticleSystemNode) // | // +-- _smokeParticles (ParticleSystemNode) // | // +-- _light (LightNode) // Use a basic scene node as the root node for the campfire. _campfire = new SceneNode { Name = "Campfire", PoseLocal = new Pose(new Vector3F(0, 0, -1)), Children = new SceneNodeCollection() }; // Add fire particles. var contentManager = _services.GetInstance<ContentManager>(); var particleSystem = CreateFire(contentManager); particleSystemService.ParticleSystems.Add(particleSystem); _fireParticles = new ParticleSystemNode(particleSystem) { // The fire effect lies in the xy plane and shoots into the forward direction (= -z axis). // Therefore we rotate the particle system to shoot upwards. PoseLocal = new Pose(new Vector3F(0, 0.2f, 0), Matrix33F.CreateRotationX(ConstantsF.PiOver2)) }; _campfire.Children.Add(_fireParticles); // Add smoke particles. particleSystem = CreateSmoke(contentManager); particleSystemService.ParticleSystems.Add(particleSystem); _smokeParticles = new ParticleSystemNode(particleSystem) { PoseLocal = new Pose(new Vector3F(0, 0.2f, 0), Matrix33F.CreateRotationX(ConstantsF.PiOver2)) }; _campfire.Children.Add(_smokeParticles); // Add a point light that illuminates the environment. var light = new PointLight { Attenuation = 0.1f, Color = new Vector3F(1, 0.2f, 0), HdrScale = 20, Range = 4 }; _light = new LightNode(light) { // Optional: We can make this light cast shadows - but this will cost performance! //Shadow = new CubeMapShadow { PreferredSize = 64, FilterRadius = 2, JitterResolution = 2048 }, PoseLocal = new Pose(new Vector3F(0, 1f, 0)) }; _campfire.Children.Add(_light); // Add campfire to scene. var scene = _services.GetInstance<IScene>(); scene.Children.Add(_campfire); // Particle effects can be added multiple times to the scene (= "instancing"). // Uncomment the following lines to add a few more instance to the scene. //for (int i = 0; i < 10; i++) //{ // var clone = _campfire.Clone(); // // Set random scale, position, orientation. // clone.ScaleLocal = _random.NextVector3F(0.5f, 1.5f); // var pose = _campfire.PoseWorld; // pose.Position.X += _random.NextFloat(-10, 10); // pose.Position.Z += _random.NextFloat(-10, 10); // pose.Orientation = Matrix33F.CreateRotationY(_random.NextFloat(-ConstantsF.PiOver2, ConstantsF.PiOver2)); // clone.PoseLocal = pose; // scene.Children.Add(clone); //} // Add GUI controls to the Options window. var sampleFramework = _services.GetInstance<SampleFramework>(); var optionsPanel = sampleFramework.AddOptions("Game Objects"); var panel = SampleHelper.AddGroupBox(optionsPanel, "CampfireObject"); SampleHelper.AddCheckBox( panel, "Enable campfire", IsEnabled, isChecked => IsEnabled = isChecked); }
// OnUnload() is called when the GameObject is removed from the IGameObjectService. protected override void OnUnload() { // Clean up. _campfire.Parent.Children.Remove(_campfire); _campfire.Dispose(false); _campfire = null; _fireParticles = null; _smokeParticles = null; _light = null; _random = null; }
/// <inheritdoc/> protected override void CloneCore(SceneNode source) { // Clone the SceneNode properties (base class). base.CloneCore(source); // Clone the TerrainNode properties. var sourceTyped = (TerrainNode)source; HoleThreshold = sourceTyped.HoleThreshold; }
public void Set(SceneNode referenceNode, IList<SceneNode> nodes, RenderContext context) { ReferenceNode = referenceNode; ShadowCasters.Clear(); // Check if the light is the directional light. If yes, we will check the // IsShadowCasterCulled flag. var lightNode = referenceNode as LightNode; if (lightNode == null) lightNode = context.ReferenceNode as LightNode; _checkShadowCusterCulling = (lightNode != null) && (lightNode.Light is DirectionalLight); int numberOfNodes = nodes.Count; #if DEBUG for (int i = 0; i < numberOfNodes; i++) Debug.Assert(nodes[i].ActualIsEnabled, "Scene query contains disabled nodes."); #endif if (context.LodCameraNode == null) { // ----- No LOD for (int i = 0; i < numberOfNodes; i++) { var node = nodes[i]; if (IsShadowCaster(node)) ShadowCasters.Add(node); } } else { // ----- LOD // Get values for LOD computations. var cameraNode = context.LodCameraNode; _cameraPosition = cameraNode.PoseLocal.Position; _lodBiasOverYScale = 1 / Math.Abs(cameraNode.Camera.Projection.ToMatrix44F().M11) * cameraNode.LodBias * context.LodBias; // Add nodes and evaluate LOD groups. for (int i = 0; i < numberOfNodes; i++) AddNodeWithLod(nodes[i], context); } }
// CanRender() checks whether a given scene node can be rendered with this // scene node renderer. public override bool CanRender(SceneNode node, RenderContext context) { return node is TextNode; }
private void AddSubtree(SceneNode node, RenderContext context) { if (node.IsEnabled) { AddNodeWithLod(node, context); if (node.Children != null) foreach (var childNode in node.Children) AddSubtree(childNode, context); } }
// Sets the node without updating the bounding shape. private void SetNode(SceneNode node) { // Detach proxy. if (_node != null) { SetProxy(_node, null); _node.SceneChanged -= OnNodeSceneChanged; _node.PoseLocal = Pose.Identity; _node.ScaleLocal = Vector3F.One; } _node = node; // Attach proxy. if (_node != null) { SetProxy(_node, this); _node.PoseLocal = PoseWorld; _node.ScaleLocal = ScaleWorld; _node.SceneChanged += OnNodeSceneChanged; } }
/// <summary> /// Sets the <see cref="SceneNode.Proxy"/> in all referenced nodes. /// </summary> /// <param name="referencedNode">The referenced node.</param> /// <param name="proxyNode">The proxy node.</param> private static void SetProxy(SceneNode referencedNode, SceneNode proxyNode) { Debug.Assert(referencedNode != null, "node must not be null."); referencedNode.Proxy = proxyNode; if (referencedNode.Children != null) foreach (var childNode in referencedNode.Children) SetProxy(childNode, proxyNode); }
//-------------------------------------------------------------- #region Creation & Cleanup //-------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="ProxyNode"/> class. /// </summary> /// <param name="node">The scene node.</param> public ProxyNode(SceneNode node) { IsRenderable = true; CastsShadows = true; Node = node; }
/// <summary> /// Called when <see cref="Parent"/> was changed. /// </summary> /// <param name="oldParent">The old parent.</param> /// <param name="newParent">The new parent.</param> protected virtual void OnParentChanged(SceneNode oldParent, SceneNode newParent) { }
/// <inheritdoc /> protected override void CloneCore(SceneNode source) { // Clone SceneNode properties. base.CloneCore(source); // Clone FogSphereNode properties. var sourceTyped = (FogSphereNode)source; Color = sourceTyped.Color; Density = sourceTyped.Density; BlendMode = sourceTyped.BlendMode; Falloff = sourceTyped.Falloff; IntersectionSoftness = sourceTyped.IntersectionSoftness; }
//-------------------------------------------------------------- /// <inheritdoc/> public void Reset() { ReferenceNode = null; FogNodes.Clear(); }
/// <inheritdoc/> protected override void CloneCore(SceneNode source) { // Clone SceneNode properties. base.CloneCore(source); // Clone FigureNode properties. var sourceTyped = (FigureNode)source; StrokeColor = sourceTyped.StrokeColor; StrokeAlpha = sourceTyped.StrokeAlpha; StrokeThickness = sourceTyped.StrokeThickness; StrokeDashPattern = sourceTyped.StrokeDashPattern; DashInWorldSpace = sourceTyped.DashInWorldSpace; FillColor = sourceTyped.FillColor; FillAlpha = sourceTyped.FillAlpha; DrawOrder = sourceTyped.DrawOrder; }
private void AddNodeWithLod(SceneNode node, RenderContext context) { if (!IsShadowCaster(node)) return; bool hasMaxDistance = Numeric.IsPositiveFinite(node.MaxDistance); var lodGroupNode = node as LodGroupNode; bool isLodGroupNode = (lodGroupNode != null); float distance = 0; if (hasMaxDistance || isLodGroupNode) { Debug.Assert( node.ScaleWorld.X > 0 && node.ScaleWorld.Y > 0 && node.ScaleWorld.Z > 0, "Assuming that all scale factors are positive."); // Determine view-normalized distance between scene node and camera node. distance = (node.PoseWorld.Position - _cameraPosition).Length; distance *= _lodBiasOverYScale; distance /= node.ScaleWorld.LargestComponent; } // Distance Culling: Only handle nodes that are within MaxDistance. if (hasMaxDistance && distance >= node.MaxDistance) return; // Ignore scene node. if (isLodGroupNode) { // Evaluate LOD group. var lodSelection = lodGroupNode.SelectLod(context, distance); AddSubtree(lodSelection.Current, context); } else { ShadowCasters.Add(node); } }
// TODO(matt) - grid creation needs to be able to be customized and should also be to a specific scale // TODO(matt) - should also have an intuitive control panel with presets and real time feedback // Add a grid with thick major grid lines and thin stroked minor grid lines. private void CreateGrid() { var majorGridLines = new PathFigure2F(); for (int i = 0; i <= 100; i++) { majorGridLines.Segments.Add(new LineSegment2F { Point1 = new Vector2F(-50, -50 + i), Point2 = new Vector2F(50, -50 + i), }); majorGridLines.Segments.Add(new LineSegment2F { Point1 = new Vector2F(-50 + i, -50), Point2 = new Vector2F(-50 + i, 50), }); } var minorGridLines = new PathFigure2F(); for (int i = 0; i < 100; i++) { minorGridLines.Segments.Add(new LineSegment2F { Point1 = new Vector2F(-50, -40.5f + i), Point2 = new Vector2F(50, -40.5f + i), }); minorGridLines.Segments.Add(new LineSegment2F { Point1 = new Vector2F(-40.5f + i, -50), Point2 = new Vector2F(-40.5f + i, 50), }); } var majorLinesNode = new FigureNode(majorGridLines) { Name = "Major grid lines", PoseLocal = Pose.Identity, StrokeThickness = 1, StrokeColor = new Vector3F(0.1f), StrokeAlpha = 1f, }; var minorLinesNode = new FigureNode(minorGridLines) { Name = "Minor grid lines", PoseLocal = Pose.Identity, StrokeThickness = 0.5f, StrokeColor = new Vector3F(0.1f), StrokeAlpha = 1f, //DashInWorldSpace = true, //StrokeDashPattern = new Vector4F(10, 4, 0, 0) / 200, }; var gridNode = new SceneNode { Name = "Grid", Children = new SceneNodeCollection(), PoseLocal = new Pose(new Vector3F(0, -0.5f, 0)), }; gridNode.Children.Add(majorLinesNode); gridNode.Children.Add(minorLinesNode); Scene.Children.Add(gridNode); }
private bool IsShadowCaster(SceneNode node) { if (_checkShadowCusterCulling) { // Flag CastsShadow must be set. // Flag IsShadowCasterCulled must NOT be set. return node.GetFlags(SceneNodeFlags.CastsShadows | SceneNodeFlags.IsShadowCasterCulled) == SceneNodeFlags.CastsShadows; } else { #if !WINDOWS_PHONE && !XBOX360 return node.GetFlag(SceneNodeFlags.CastsShadows) && !(node is TerrainNode); // Terrain node is only rendered into directional light shadow. #else return node.GetFlag(SceneNodeFlags.CastsShadows); #endif } }
//-------------------------------------------------------------- /// <inheritdoc/> public override bool CanRender(SceneNode node, RenderContext context) { var lightNode = node as LightNode; return lightNode != null && lightNode.Shadow is CubeMapShadow; }
//-------------------------------------------------------------- /// <inheritdoc/> public override bool CanRender(SceneNode node, RenderContext context) { return (node is SkyNode) && base.CanRender(node, context); }