如何:显示和选择网格

更新:2007 年 11 月

您可以创建和显示网格数组,以便在设备上选中(点击)某个网格时,该网格会更改颜色。

说明:

托管 Direct3D 移动应用程序需要使用适用于 Pocket PC 和 Smartphone 的 Windows Mobile 5.0 版软件。有关 Windows Mobile 软件和 SDK 的信息,请参见 .NET Compact Framework 的外部资源

此代码示例的窗体包含以下对象:

  • 活动网格的 Mesh 对象。

  • 一个包含可选择的各种颜色的九个 Mesh 对象的数组。

  • 一个定义网格位置的 Vector3 结构。

  • 两个定义边界框的 Vector3 结构。

  • 一个 Device 对象。

窗体的构造函数指定设备的 PresentationParameters 属性的设置,创建 Device 对象,将 OnDeviceReset 事件处理程序添加到设备的 DeviceReset 事件,然后调用 OnDeviceReset 方法以开始创建网格。下表描述呈现网格和启用用户交互的方法。

方法

操作

OnDeviceReset

创建网格,将它们放置在边界框中的一些位置上,并定义变换矩阵。

OnPaint

开启屏幕,绘制网格,然后关闭屏幕。

OnMouseDown

通过使用以下方法演示如何选择网格:在逻辑三维空间中创建一条射线,然后运行一个框-射线交集。

该射线表示在三维空间中按下手写笔。该框表示三维对象周围的边界框。如果这两者有交集,则用户应单击包含三维对象的位置。

示例

下面的代码示例提供了一个完整的窗体。它显示可选择的各种颜色的 Mesh 对象。当选中某一网格后,该网格的颜色会发生更改。

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());
        }
    }
}

编译代码

此示例需要引用下面的命名空间:

请参见

概念

.NET Compact Framework 帮助主题

其他资源

.NET Compact Framework 中的 Mobile Direct3D 编程