原文: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. testng并发测试与测试并发

    一.testng并发测试 通过xml文件中suit结点的parallel属性指定,如 <suite name="bundle-module-testabc" parallel ...

  2. linux下U盘状态检测

    Linux的文件系统是异步的,也就是说写一个文件不是立刻保存到介质(硬盘,U盘等)中,而是存到缓冲区内,等积累到一定程度再一起保存到介质中.如果没有umount就非法拔出U盘,程序是不知道的,fope ...

  3. Voronoi Diagram——维诺图

    Voronoi图定义   任意两点p 和q 之间的欧氏距离,记作 dist(p, q) .就平面情况而言,我们有           dist(p, q) =  (px-qx)2+ (py-qy)2 ...

  4. JS中给函数参数添加默认值(多看课程)

    JS中给函数参数添加默认值(多看课程) 一.总结 一句话总结:咋函数里面是可以很方便的获取调用函数的参数的,做个判断就好,应该有简便方法,看课程. 二.JS中给函数参数添加默认值 最近在Codewar ...

  5. pppoe-环境下的mtu和mss

    路由器上在宽带拨号高级设置页面会有设置数据包MTU的页面 数据包MTU(字节):1480 (默认是1480,如非必要,请勿修改) PPPoE/ADSL:1492 ,可以尝试修改为1492 MTU: M ...

  6. [CSS] Showing horizontal scrollbar always for the table

    table { display: block; overflow: scroll; width: 200px; height:95vh; }

  7. JNI:no implementation found in native...

    一  javah引发的问题 BUG:D/dalvikvm( 1704): Trying to load lib /data/data/com.ulang/lib/libulangaudio.so 0x ...

  8. [Vue] Use Vue.js Component Computed Properties

    You can add computed properties to a component to calculate a property on the fly. The benefit of th ...

  9. Haproxy解析

    简单介绍 HAProxy是一款提供高可用性.负载均衡以及基于TCP和HTTP应用的代理软件,HAProxy是全然免费的.借助HAProxy能够高速而且可靠的提供基于TCP和HTTP应用的代理解决方式. ...

  10. javaScript DOM编程经常使用的方法与属性

    DOM是Document Object Model文档对象模型的缩写.依据W3C DOM规范,DOM是一种与浏览器,平台,语言无关的接口,使得你能够訪问页面其它的标准组件. Node接口的特性和方法 ...