How to: Display and Select Meshes
You can create and display an array of meshes so that when a mesh is picked (tapped) on the device, it changes color.
Note
Managed Direct3D mobile applications require Windows Mobile version 5.0 software for Pocket PCs and Smartphones. See External Resources for the .NET Compact Framework for information about Windows Mobile software and SDKs.
The form for this code example has the following objects:
A Mesh object for the active mesh.
An array of nine Mesh objects of various colors that can be picked.
A Vector3 structure that defines the mesh locations.
Two Vector3 structures that define the bounding box.
A Device object.
The form's constructor specifies settings for the device's PresentationParameters property, creates the Device object, adds the OnDeviceReset event handler to the device's DeviceReset event, and then calls the OnDeviceReset method to begin creating the meshes. The following table describes the methods that render the meshes and enable user interaction.
Method |
Actions |
---|---|
OnDeviceReset |
Creates the meshes, places them at locations in the bounding box, and defines the transformation matrices. |
OnPaint |
Begins the scene, draws the meshes, and ends the scene. |
OnMouseDown |
Demonstrates picking a mesh by using a technique that creates a ray through the logical 3-D space and performs a box-ray intersection. The ray represents pressing the stylus through the 3-D space. The box represents a bounding box around the 3-D object. If the two intersect, the user has clicked on a location that contains the 3-D object. |
Example
The following code example provides a complete form. It displays Mesh objects of various colors that can be picked. When a mesh is picked, its color changes.
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports Microsoft.WindowsMobile.DirectX
Imports Microsoft.WindowsMobile.DirectX.Direct3D
Imports Microsoft.VisualBasic
Class MeshPickingHowto
Inherits Form
Private Const numberOfMeshes As Integer = 9
Private meshes() As Mesh
Private meshColors() As Color = {Color.Green, Color.Orange, Color.Purple, Color.Pink, Color.Violet, Color.Blue, Color.Yellow, Color.Brown, Color.Aquamarine}
Private meshLocations() As Vector3
Private meshBoundingBoxMinValues() As Vector3
Private meshBoundingBoxMaxValues() As Vector3
Private activeMesh As Mesh
Private device As Device
Public Sub New()
Dim present As PresentParameters
Me.Text = "Mesh Picking"
' Enable the form to be closed.
' This is required so that Hwnd of the form changes.
Me.MinimizeBox = False
present = New PresentParameters()
present.Windowed = True
present.AutoDepthStencilFormat = DepthFormat.D16
present.EnableAutoDepthStencil = True
present.SwapEffect = SwapEffect.Discard
device = New Device(0, DeviceType.Default, Me, CreateFlags.None, present)
AddHandler device.DeviceReset, AddressOf OnDeviceReset
OnDeviceReset(Nothing, EventArgs.Empty)
End Sub
Private Sub OnDeviceReset(ByVal sender As Object, ByVal e As EventArgs)
' Meshes must be recreated whenever the device
' is reset, no matter which pool they are created in.
meshes = New Mesh(numberOfMeshes) {}
meshLocations = New Vector3(numberOfMeshes) {}
meshBoundingBoxMinValues = New Vector3(numberOfMeshes) {}
meshBoundingBoxMaxValues = New Vector3(numberOfMeshes) {}
activeMesh = Nothing
' Create several meshes and associated data.
Dim i As Integer
For i = 0 To numberOfMeshes
Dim vertexData As GraphicsStream
meshes(i) = Mesh.Box(device, 1F, 1F, 1F)
' Arrange the boxes in a grid, with each
' successive box farther in the distance.
meshLocations(i) = New Vector3((i Mod 3) * 2 - 2, i / 3 * 2 - 2, i)
' Compute the bounding box for a mesh.
Dim description As VertexBufferDescription = meshes(i).VertexBuffer.Description
vertexData = meshes(i).VertexBuffer.Lock(0, 0, LockFlags.ReadOnly)
Geometry.ComputeBoundingBox(vertexData, meshes(i).NumberVertices, description.VertexFormat, meshBoundingBoxMinValues(i), meshBoundingBoxMaxValues(i))
meshes(i).VertexBuffer.Unlock()
Next i
' Set the transformation matrices.
device.Transform.Projection = Matrix.PerspectiveFovRH(System.Convert.ToSingle(Math.PI) / 4F, System.Convert.ToSingle(Me.ClientSize.Width) / System.Convert.ToSingle(Me.ClientSize.Height), 0.001F, 40)
device.Transform.View = Matrix.LookAtRH(New Vector3(0, 2, - 7), New Vector3(0, 0, 0), New Vector3(0, 1, 0))
device.RenderState.Ambient = Color.White
End Sub
Protected Overrides Sub OnPaintBackground(ByVal e As PaintEventArgs)
' Do nothing.
End Sub
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
Dim material As New Material()
' Begin the scene and clear the back buffer to black.
device.BeginScene()
device.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, Color.Black, 1F, 0)
' Draw each mesh to the screen.
' The active mesh is drawn in red.
Dim i As Integer
For i = 0 To numberOfMeshes
If activeMesh Is meshes(i) Then
material.Ambient = Color.Red
Else
material.Ambient = meshColors(i)
End If
device.Transform.World = Matrix.Translation(meshLocations(i))
device.Material = material
meshes(i).DrawSubset(0)
Next i
' Finish the scene and present it on the screen.
device.EndScene()
device.Present()
End Sub
' This method demonstrates picking.
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
' The technique used here is to create a ray through the entire
' logical 3-D space, and then perform an intersection test
' for the bounding box and ray.
Dim i As Integer
For i = 0 To numberOfMeshes
Dim nearVector As New Vector3(e.X, e.Y, 0)
Dim farVector As New Vector3(e.X, e.Y, 1)
' Create ray.
nearVector.Unproject(device.Viewport, device.Transform.Projection, device.Transform.View, Matrix.Translation(meshLocations(i)))
farVector.Unproject(device.Viewport, device.Transform.Projection, device.Transform.View, Matrix.Translation(meshLocations(i)))
farVector.Subtract(nearVector)
' Perform intersection test for the bounding box and ray.
If Geometry.BoxBoundProbe(meshBoundingBoxMinValues(i), meshBoundingBoxMaxValues(i), nearVector, farVector) Then
' Perform operation on detection of click on mesh object.
' In this case, you designate the mesh as the active
' mesh and invalidate the window so that it is redrawn.
activeMesh = meshes(i)
Me.Invalidate()
Exit For
End If
Next i
End Sub
Shared Sub Main()
Application.Run(New MeshPickingHowto())
End Sub
End Class
using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.WindowsMobile.DirectX;
using Microsoft.WindowsMobile.DirectX.Direct3D;
namespace MeshPick
{
class MeshPickingHowto : Form
{
const int numberOfMeshes = 9;
Mesh [] meshes;
Color [] meshColors = new Color [] { Color.Green, Color.Orange,
Color.Purple, Color.Pink, Color.Violet, Color.Blue, Color.Yellow,
Color.Brown, Color.Aquamarine };
Vector3 [] meshLocations;
Vector3 [] meshBoundingBoxMinValues;
Vector3 [] meshBoundingBoxMaxValues;
Mesh activeMesh;
Device device;
public MeshPickingHowto()
{
PresentParameters present;
this.Text = "Mesh Picking";
// Enable the form to be closed.
// This is required so that Hwnd of the form changes.
this.MinimizeBox = false;
present = new PresentParameters();
present.Windowed = true;
present.AutoDepthStencilFormat = DepthFormat.D16;
present.EnableAutoDepthStencil = true;
present.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Default, this,
CreateFlags.None, present);
device.DeviceReset += new EventHandler(OnDeviceReset);
OnDeviceReset(null, EventArgs.Empty);
}
private void OnDeviceReset(object sender, EventArgs e)
{
// Meshes must be recreated whenever the device
// is reset, no matter which pool they are created in.
meshes = new Mesh[numberOfMeshes];
meshLocations = new Vector3[numberOfMeshes];
meshBoundingBoxMinValues = new Vector3[numberOfMeshes];
meshBoundingBoxMaxValues = new Vector3[numberOfMeshes];
activeMesh = null;
// Create several meshes and associated data.
for (int i = 0; i < numberOfMeshes; i+)
{
GraphicsStream vertexData;
meshes[i] = Mesh.Box(device, 1.0f, 1.0f, 1.0f);
// Arrange the boxes in a grid, with each
// successive box farther in the distance.
meshLocations[i] = new Vector3(((i % 3) * 2) - 2,
((i / 3) * 2) - 2, i);
// Compute the bounding box for a mesh.
VertexBufferDescription description =
meshes[i].VertexBuffer.Description;
vertexData = meshes[i].VertexBuffer.Lock
(0, 0, LockFlags.ReadOnly);
Geometry.ComputeBoundingBox(vertexData,
meshes[i].NumberVertices,description.VertexFormat,
out meshBoundingBoxMinValues[i],
out meshBoundingBoxMaxValues[i]);
meshes[i].VertexBuffer.Unlock();
}
// Set the transformation matrices.
device.Transform.Projection = Matrix.PerspectiveFovRH(
(float)Math.PI/4.0F,
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
0.001f, 40);
device.Transform.View = Matrix.LookAtRH(new Vector3(0, 2, -7),
new Vector3(0, 0, 0), new Vector3(0, 1, 0));
device.RenderState.Ambient = Color.White;
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do nothing.
}
protected override void OnPaint(PaintEventArgs e)
{
Material material = new Material();
// Begin the scene and clear the back buffer to black.
device.BeginScene();
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer,
Color.Black, 1.0f, 0);
// Draw each mesh to the screen.
// The active mesh is drawn in red.
for (int i = 0; i < numberOfMeshes; i+)
{
if (activeMesh == meshes[i])
material.Ambient = Color.Red;
else
material.Ambient = meshColors[i];
device.Transform.World = Matrix.Translation(meshLocations[i]);
device.Material = material;
meshes[i].DrawSubset(0);
}
// Finish the scene and present it on the screen.
device.EndScene();
device.Present();
}
// This method demonstrates picking.
protected override void OnMouseDown(MouseEventArgs e)
{
// The technique used here is to create a ray through the entire
// logical 3-D space, and then perform an intersection test
// for the bounding box and ray.
for (int i = 0; i < numberOfMeshes; i+)
{
Vector3 nearVector = new Vector3(e.X, e.Y, 0);
Vector3 farVector = new Vector3(e.X, e.Y, 1);
// Create ray.
nearVector.Unproject(device.Viewport,
device.Transform.Projection,
device.Transform.View,
Matrix.Translation(meshLocations[i]));
farVector.Unproject(device.Viewport,
device.Transform.Projection,
device.Transform.View,
Matrix.Translation(meshLocations[i]));
farVector.Subtract(nearVector);
// Perform intersection test for the bounding box and ray.
if (Geometry.BoxBoundProbe(meshBoundingBoxMinValues[i],
meshBoundingBoxMaxValues[i], nearVector, farVector))
{
// Perform operation on detection of click on mesh object.
// In this case, you designate the mesh as the active
// mesh and invalidate the window so that it is redrawn.
activeMesh = meshes[i];
this.Invalidate();
break;
}
}
}
static void Main()
{
Application.Run(new MeshPickingHowto());
}
}
}
Compiling the Code
This example requires references to the following namespaces:
See Also
Concepts
.NET Compact Framework How-to Topics