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坐标的更多相关文章
- WPF中获取鼠标相对于屏幕的位置
原文:WPF中获取鼠标相对于屏幕的位置 WPF中获取鼠标相对于屏幕的位置 周银辉WPF编程时,我们经常使用Mouse.GetPosi ...
- [UE4]使用PlayerController获取鼠标点击时的坐标
1,获取鼠标在当前场景中坐标系统的中的position,加入场景地图的范围是一千平方米,那么这个position的范围也是1000米x1000米. 注册鼠标事件 FInputActionBinding ...
- unity 3d 获取鼠标当前坐标
获取当前鼠标position:Input.mousePosition;
- WPF中获取鼠标相对于桌面位置
var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice; var mouse ...
- javascript 获取鼠标在盒子中的坐标
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- NGUI中获取鼠标在控件内部坐标
在UIWidget 中添加以下函数.获得的坐标系是以右上角为原点坐标,x轴向左,一轴向下. public Vector2 GetTouchPoint() { Vector3 p0 = cachedT ...
- 发现:Click事件也能获取鼠标单击的坐标
按照MSDN的说明以及平时的习惯,我们要获取鼠标单击时的相对坐标,都会使用MouseClick等事件,今天,偶然发现,原来Click事件也可以. /* 惊天地泣鬼神的考古业绩. * 原来Cilck事件 ...
- Javascript获取当前鼠标在元素内的坐标定位
代码如下: <!doctype html> <html> <head> <meta charset="utf-8"> <tit ...
- 获取鼠标在 canvas 中的位置
一般情况 一般情况下,如果需要在 canvas 中获取鼠标指针坐标,可以通过监听鼠标的 mousemove(如果只需单击时的坐标,可以用 click)事件. 当事件被触发时,我们可以获取鼠标相对于 v ...
随机推荐
- [Node] Define MongoDB Model with Mongoose
const mongoose = require('mongoose'); mongoose.Promise = global.Promise; // url friendly const slug ...
- 无意中发现Markdown,最终解放了我
文件夹 概述 换行 删除线 链接自己主动识别 表格 代码块高亮 定义列表 脚注 自己主动生成文件夹 參考资料 正文 概述 大部分情况下,Markdown的基本的语法已够我们使用,比方随性记录点东西.非 ...
- js课程 2-7 带默认参数的函数怎么写
js课程 2-7 带默认参数的函数怎么写(注意参数顺序) 一.总结 一句话总结:默认参数一定要放在最后面,而且还有注意你调用参数的时候给参数的顺序习惯.直接加个等于号就可以是默认参数.function ...
- ListView.setSelection(position)不起作用
选择同事列表页面,在Adapter里设置复选框背景时调用了notifyDataSetChanged(),阻碍了UI线程,因此在设置ListView.setSelection(position)时不起作 ...
- [Docker] Run Short-Lived Docker Containers
Learn the benefits of running one-off, short-lived Docker containers. Short-Lived containers are use ...
- AOP概述:
AOP可以在不修改源代码的情况下,对程序进行增强. AOP面向切面进行编程,Spring将AOP引入到框架中,但是也需要遵守AOP联盟的规范. 通过预编译的方式和运行期动态代理实现程序功能的同意维护的 ...
- 账号权限问题导致 masterha_check_repl 检查失败
在使用 masterha_check_repl --global_conf=/etc/masterha/masterha_default.conf --conf=/etc/masterha/app1. ...
- Android 用LinkedList实现队列
队列 队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作.进行插入操作的端称为队尾,进行删除操作的端称为队头.队列中没有元素时,称为空队列. 在 ...
- Python科学计算(一)
一.准备教材:<python科学计算> 作者: 张若愚 出版社: 清华大学出版社 出版年: 2012-1 页数: 621 定价: 98.00元 装帧: 平装 ISBN: 97873022 ...
- wpf SnapsToDevicePixels
原文:wpf SnapsToDevicePixels 可以在您的根元素上将此属性设为 true,以在整个 UI 上启用像素对齐呈现. 对于运行在大于 96 每英寸点数 (dpi) 的设备,像素对 ...