Click or drag to resize
DigitalRuneISceneQuery Interface
Represents a query that can be executed against a scene.

Namespace: DigitalRune.Graphics.SceneGraph
Assembly: DigitalRune.Graphics (in DigitalRune.Graphics.dll) Version: 1.2.0.0 (1.2.1.14562)
Syntax
public interface ISceneQuery

The ISceneQuery type exposes the following members.

Methods
  NameDescription
Public methodReset
Resets this query.
Public methodSet
Sets the query result.
Top
Properties
  NameDescription
Public propertyReferenceNode
Gets the reference node.
Top
Remarks

A scene query returns all scene nodes that touch a given reference node. Queries can be performed by calling QueryT(SceneNode, RenderContext) of a IScene. Here are a few examples of scene queries:

  • A CameraFrustumQuery gets all scene nodes within the camera frustum. The reference node in this query is (usually) a camera node.
  • A LightQuery gets all lights that shine light on the reference node.
  • A ShadowCasterQuery gets all shadow casters near a light source. The reference node in this query is the light node.

Scene nodes where IsEnabled is are ignored and do not show up in the query results.

Notes to Implementors: Classes that implement ISceneQuery must have a parameterless constructor.

Examples

The following examples demonstrates how to create a scene query that collects MeshNodes.

MeshQuery
using System.Collections.Generic;
using DigitalRune.Graphics;
using DigitalRune.Graphics.SceneGraph;

namespace Samples
{
  public class MeshQuery : ISceneQuery
  {
    public SceneNode ReferenceNode { get; private set; }
    public List<SceneNode> Meshes { get; private set; }

    public MeshQuery()
    {
      Meshes = new List<SceneNode>();
    }

    public void Reset()
    {
      ReferenceNode = null;
      Meshes.Clear();
    }

    public void Set(SceneNode referenceNode, IList<SceneNode> nodes, RenderContext context)
    {
      Reset();
      ReferenceNode = referenceNode;

      for (int i = 0; i < nodes.Count; i++)
      {
        var node = nodes[i];
        if (node is MeshNode)
          Meshes.Add(node);
      }
    }
  }
}

The query can, for example, be used to get all meshes within the camera frustum.

C#
ISceneQuery query = myScene.Query<MeshQuery>(cameraNode, renderContext);

Distance Culling:
The following example shows how to implement a scene query that performs distance culling of scene nodes.

Scene Query with Distance Culling
using System.Collections.Generic;
using DigitalRune.Graphics;
using DigitalRune.Graphics.SceneGraph;
using DigitalRune.Mathematics;

namespace Samples
{
  public class SceneQueryWithDistanceCulling : ISceneQuery
  {
    public SceneNode ReferenceNode { get; private set; }
    public List<SceneNode> Nodes { get; private set; }

    public SceneQueryWithDistanceCulling()
    {
      Nodes = new List<SceneNode>();
    }

    public void Reset()
    {
      ReferenceNode = null;
      Nodes.Clear();
    }

    public void Set(SceneNode referenceNode, IList<SceneNode> nodes, RenderContext context)
    {
      Reset();
      ReferenceNode = referenceNode;

      var cameraNode = context.LodCameraNode;
      if (cameraNode == null)
        throw new GraphicsException("LOD camera node needs to be set in render context.");

      for (int i = 0; i < nodes.Count; i++)
      {
        var node = nodes[i];

        // Calculate view-normalized distance of scene node.
        float distance = GraphicsHelper.GetViewNormalizedDistance(node, cameraNode);
        distance *= cameraNode.LodBias * context.LodBias;

        // Distance Culling: Check whether scene node is within MaxDistance.
        if (Numeric.IsPositiveFinite(node.MaxDistance) && distance >= node.MaxDistance)
          continue;   // Ignore scene node.

        Nodes.Add(node);
      }
    }
  }
}

Level of Detail:
Level of detail (see LodGroupNode) needs to be evaluated by the scene query. The following example implements distance culling and LOD selection.

Scene Query with Level Of Detail
using System.Collections.Generic;
using DigitalRune.Graphics;
using DigitalRune.Graphics.SceneGraph;
using DigitalRune.Mathematics;

namespace Samples
{
  public class SceneQueryWithLod : ISceneQuery
  {
    public SceneNode ReferenceNode { get; private set; }
    public List<SceneNode> Nodes { get; private set; }

    public SceneQueryWithLod()
    {
      Nodes = new List<SceneNode>();
    }

    public void Reset()
    {
      ReferenceNode = null;
      Nodes.Clear();
    }

    public void Set(SceneNode referenceNode, IList<SceneNode> nodes, RenderContext context)
    {
      Reset();
      ReferenceNode = referenceNode;

      if (context.LodCameraNode == null)
        throw new GraphicsException("LOD camera node needs to be set in render context.");

      for (int i = 0; i < nodes.Count; i++)
        AddNode(nodes[i], context);
    }

    private void AddNode(SceneNode node, RenderContext context)
    {
      var cameraNode = context.LodCameraNode;

      // Calculate view-normalized distance.
      float distance = GraphicsHelper.GetViewNormalizedDistance(node, cameraNode);
      distance *= cameraNode.LodBias * context.LodBias;

      // Distance Culling: Check whether scene node is within MaxDistance.
      if (Numeric.IsPositiveFinite(node.MaxDistance) && distance >= node.MaxDistance)
        return;   // Ignore scene node.

      var lodGroupNode = node as LodGroupNode;
      if (lodGroupNode != null)
      {
        // Evaluate LOD group.
        var lodSelection = lodGroupNode.SelectLod(context, distance);
        AddSubtree(lodSelection.Current, context);
      }
      else
      {
        Nodes.Add(node);
      }
    }

    private void AddSubtree(SceneNode node, RenderContext context)
    {
      if (node.IsEnabled)
      {
        AddNode(node, context);

        if (node.Children != null)
        foreach (var childNode in node.Children)
          AddSubtree(childNode, context);
      }
    }
  }
}
See Also