原文: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. 使用github pages创建博客

      参考:http://wenku.baidu.com/link?url=hi0nlkIp17HnQQpCkUr3KacZOOVGMOYKYbWzjX_HKJZNZpiRxfGPLuwvUydOVxe ...

  2. 1、第一课 register_chrdev和register_chrdev_region 创建知识

    1. register_chrdev注册字符设备后,有0-256个子设备可用,若major==0,则内核动态申请主设备号.static inline int register_chrdev(unsig ...

  3. 如何调试Javascript代码

    转自原文如何调试Javascript代码 目前,常用的浏览器IE.Chrome.Firefox都有相应的脚本调试功能.作为我们.NET 阵营,学会如何在IE中调试JS就足够了,在掌握了IE中的调试方法 ...

  4. js进阶ajax函数封装(匿名函数作为参数传递)(封装函数引入文件的方式非常好用)

    js进阶ajax函数封装(匿名函数作为参数传递)(封装函数引入文件的方式非常好用) 一.总结 2.匿名函数作为参数传递 二.js进阶ajax函数封装 ajax1.js function ajax(ur ...

  5. Java多线程系列-线程创建

    1.怎样创建多线程? Java从语言级别实现多线程,因此实现一个多线程程序很easy.有两种方法能够实现多线程,即继承Thread类和实现Runnable接口.由于Java不支持多继承的原因,建议尽可 ...

  6. Spring之i18n配置与使用

    Spring的i18n配置: <!-- conf:i18n --> <bean id="messageSource" class="org.spring ...

  7. js实现md5加密sha1加密等

    1.base64加密 在页面中引入base64.js文件,调用方法为: <!DOCTYPE HTML> <html> <head> <meta charset ...

  8. 避免if语句的深层次嵌套

    公司做了个抢红包的限制,然后ajax请求的返回字段,要进行多层逻辑的判断,想想是真恶心,虽然都是简单逻辑,而且看别人以前写的代码,发现,哎,注释能不能写上吶,像我写代码都是细致到,哪怕初学者也能看懂这 ...

  9. CSS学习小结

    接触了B/S的东西之后才发现自己须要学习的东西太多了.html.xml.JavaScript.jquery.HTMLdom.VBScript.ajax.jquery.json等等技术都是须要我们一一研 ...

  10. URL传递中文参数,大坑一枚,Windows与Linux效果竟然不一致(两种解决方法)

    下午,计划2个小时搞定,个人官网第6次升级,就可以干点轻松的事了,结果,下午多搞了2个小时,晚上又搞了2个小时,才搞定. 最后一个世界难题是,URL传递中文参数. 问题大致是这么出现的:我为" ...