原文:WPF 3D 获取鼠标在场景的3d坐标

上一篇中我们谈到了WPF 3d做图的一些简单原理,这里我们简单介绍一下怎样获得鼠标在场景中的3d坐标,知道了3d坐标就可以进行很多操作了:

首先介绍一下3d图形的构成以及它的一些成员属性:

在 3D 图形编程中,没有线条、Bezier 样条曲线、矩形或椭圆。每个 3D 物体都是三维坐标空间中的三角形的集合。三角形是 3D 编程的基本单位,这是因为每个单独的三角形总是能定义一个平面,而三角形集合可以模仿立体物体,甚至可以模拟曲面。3D 视图由 Viewport3D 元素组成。3D 场景需要一个或多个 GeometryModel3D 类型的物体、一个或多个光源、以及一个用于控制 3D 物体如何投射到 2D 表面从而控制观看者如何看到图像的摄像机。

GeometryModel3D 元素有三个重要属性:Geometry、Material 和 BackMaterial。

Geometry 属性被设置为 MeshGeometry3D 元素,用于根据坐标点和三角形描述可视物体。

Material 和 BackMaterial 属性说明物体的前面和背面如何着色。

MeshGeometry3D 类,该类用于定义 3D 物体的实际几何表示形式。该类有四个重要属性:Positions、TriangleIndices、TextureCoordinates 和 Normals。

Positions 属性表示物体的所有顶点。这些顶点在定义物体时肯定是有作用的,但它们不能描述所有信息。任何一组三个顶点都可以组合成一个三角形,这就是 TriangleIndices 集合所说明的内容

TriangleIndices 集合实际上驱动物体的呈现。TriangleIndices 未引用的任何 Positions 元素都会忽略(如果没有 TriangleIndices,则 Positions 集合中的每个 Point3D 三联数都将解释为一个三角形)。每个三角形都应有正面和背面。查看三角形的正面时,三联数以反时针方向表示顶点。如果将第一个三联数更改为 0 1 3,将看到左上三角形以红色着色,这是因为查看的是三角形的背面,而不是它的正面。

Normals 属性是按与 Positions 集合的一对一对应关系得到的向量的集合。每个顶点均被视为面向特定方向,该方向以该顶点的 Normals 向量表示。每个三角形内的每个点基于在其三个顶点上的向量的内插值,以不同方式反射光线。如果不提供 Normals 集合,则会基于在网格规范中共享的每个顶点上会合的三角形的 Normals 的平均值计算一个该集合。

如果对其还是不明白,可以参考这一篇文章,这里有比较详细的介绍:http://msdn.microsoft.com/zh-cn/magazine/cc163449.aspx

有了上面的基础,下面我们就来介绍一下怎样获得鼠标在三维场景中的坐标:

主要是通过viewport3d中的三维视觉效果进行命中测试:

C#源码如下:

public void HitTest(object sender, System.Windows.Input.MouseButtonEventArgs args)

{

Point mouseposition = args.GetPosition(myViewport);

Point3D testpoint3D = new Point3D(mouseposition.X, mouseposition.Y, 0);

Vector3D testdirection = new Vector3D(mouseposition.X, mouseposition.Y, 10);

PointHitTestParameters pointparams = new PointHitTestParameters(mouseposition);

RayHitTestParameters rayparams = new RayHitTestParameters(testpoint3D, testdirection);

//test for a result in the Viewport3D

VisualTreeHelper.HitTest(myViewport, null, HTResult, pointparams);

以下代码中的 HitTestResultBehavior 确定如何处理命中测试结果。 UpdateResultInfo 和 UpdateMaterial 是本地定义的方法。

public HitTestResultBehavior HTResult(System.Windows.Media.HitTestResult rawresult)

{

//MessageBox.Show(rawresult.ToString());

RayHitTestResult rayResult = rawresult as RayHitTestResult;

if (rayResult != null)

{

RayMeshGeometry3DHitTestResult rayMeshResult = rayResult as RayMeshGeometry3DHitTestResult;

if (rayMeshResult != null)

{

GeometryModel3D hitgeo = rayMeshResult.ModelHit as GeometryModel3D;

GeometryModel3D hitgeo = rayMeshResult.ModelHit as GeometryModel3D;

MeshGeometry3D hitmesh = hitgeo.Geometry as MeshGeometry3D;

Point3D p1=hitmesh.Positions.ElementAt(rayMeshResult.VertexIndex1);

double weight1 = rayMeshResult.VertexWeight1;

Point3D p2 = hitmesh.Positions.ElementAt(rayMeshResult.VertexIndex2);

double weight2 = rayMeshResult.VertexWeight2;

Point3D p3 = hitmesh.Positions.ElementAt(rayMeshResult.VertexIndex3);

double weight3 = rayMeshResult.VertexWeight3;

Point3D prePoint = new Point3D(p1.X * weight1 + p2.X * weight2 + p3.X * weight3,              p1.Y * weight1 + p2.Y * weight2 + p3.Y * weight3, p1.Z * weight1 + p2.Z * weight2 + p3.Z * weight3);

UpdateResultInfo(rayMeshResult);

UpdateMaterial(hitgeo, (side1GeometryModel3D.Material as MaterialGroup));

}

}

return HitTestResultBehavior.Continue;

}

代码可以参见:http://msdn.microsoft.com/zh-cn/library/ms745195.aspx

红色代码就是获得鼠标3d坐标的关键,具体解释一下:

Hitgeo 是命中测试hittest的返回结果,具体属性可以参见

http://msdn.microsoft.com/zh  cn/library/ms606198.aspx

通过上面GeometryModel3D的介绍可以知道,hitgeo的geometry属性就是MeshGeometry3D类型的,也就是三角形网络图形类,

命中测试的返回结果非常丰富,VertexIndex1,VertexIndex2 VertexIndex3 代表的是命中小三角形的顶点坐标在整个3d图中的点集合的索引,而VertexWeight1 VertexWeight2 VertexWeight3 分别代表了命中点在各个点所占的权重,这样通过权重和顶点坐标我们就可以计算出鼠标点击的点在三维场景中的坐标了。

WPF 3D 获取鼠标在场景的3d坐标的更多相关文章

  1. WPF中获取鼠标相对于屏幕的位置

    原文:WPF中获取鼠标相对于屏幕的位置 WPF中获取鼠标相对于屏幕的位置                                   周银辉WPF编程时,我们经常使用Mouse.GetPosi ...

  2. [UE4]使用PlayerController获取鼠标点击时的坐标

    1,获取鼠标在当前场景中坐标系统的中的position,加入场景地图的范围是一千平方米,那么这个position的范围也是1000米x1000米. 注册鼠标事件 FInputActionBinding ...

  3. unity 3d 获取鼠标当前坐标

    获取当前鼠标position:Input.mousePosition;

  4. WPF中获取鼠标相对于桌面位置

    var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice; var mouse ...

  5. javascript 获取鼠标在盒子中的坐标

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. NGUI中获取鼠标在控件内部坐标

    在UIWidget 中添加以下函数.获得的坐标系是以右上角为原点坐标,x轴向左,一轴向下. public Vector2 GetTouchPoint() { Vector3 p0 =  cachedT ...

  7. 发现:Click事件也能获取鼠标单击的坐标

    按照MSDN的说明以及平时的习惯,我们要获取鼠标单击时的相对坐标,都会使用MouseClick等事件,今天,偶然发现,原来Click事件也可以. /* 惊天地泣鬼神的考古业绩. * 原来Cilck事件 ...

  8. Javascript获取当前鼠标在元素内的坐标定位

    代码如下: <!doctype html> <html> <head> <meta charset="utf-8"> <tit ...

  9. 获取鼠标在 canvas 中的位置

    一般情况 一般情况下,如果需要在 canvas 中获取鼠标指针坐标,可以通过监听鼠标的 mousemove(如果只需单击时的坐标,可以用 click)事件. 当事件被触发时,我们可以获取鼠标相对于 v ...

随机推荐

  1. Spring Boot应用启动原理分析(转)

    在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启动的,不需要另外配置一个Web Server. 如果之前没有使用过sprin ...

  2. 34、JZ2440上WIFI网卡使用

    :http://wireless.kernel.org在这个网站上的document中有下面说有内容的介绍 1. 准备工作(虚拟机,开发板)及配置内核选择WIFI驱动1.1 选型:确定网卡的VID,P ...

  3. 【7001】n阶法雷序列

    Time Limit: 10 second Memory Limit: 2 MB 问题描述      对任意给定的一个自然数n(n<=100),将分母小于等于n的不可约的真分数按上升的次序排序, ...

  4. hdu 4406 费用流

    这题问题就是当前时刻究竟选择哪门课程,易知选择是和分数有关的,而且是一个变化的权值,所以能够用拆点的方式,把从基础分到100分都拆成点.但若这样拆点的话,跑费用流时就必须保证顺序.这样就麻烦了..观察 ...

  5. hdu3360National Treasures (最大匹配,拆点法)

    National Treasures Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...

  6. node-sass的安装问题

    1.认识node-sass 我觉得要解决node-sass的问题,你首先至少要简单的了解node-sass是个什么东西?为什么要安装它? 对于在项目中使用sass的语法的时候,需要通过sass-loa ...

  7. 【Heritrix基础教程之1】在Eclipse中配置Heritrix 分类: H3_NUTCH 2014-06-01 00:00 1262人阅读 评论(0) 收藏

    一.新建项目并将Heritrix源码导入 1.下载heritrix-1.14.4-src.zip和heritrix-1.14.4.zip两个压缩包,并解压,以后分别简称SRC包和ZIP包: 2.在Ec ...

  8. php javascript的ajax

    先说基础一点的get类型的ajax function loadXMLDoc() { var xmlhttp;//首先判断浏览器是否支持xmlhttprequest,因为ie56不是这个对象,是acti ...

  9. Windows Phone 8.1 数据处理

    Windows Phone 8.1 应用的数据存储位置包括: Installation Folder ApplicationData Credential Locker Known Folders S ...

  10. 详解springmvc控制登录用户session失效后跳转登录页面

    springmvc控制登录用户session失效后跳转登录页面,废话不多少了,具体如下: 第一步,配置 web.xml <session-config> <session-timeo ...