三维空间中鼠标点击选择线段的方法

   在二维图中,判断鼠标是否选中线段,是根据鼠标点的位置与线段的距离,如果和线段的距离小于阈值,那么就认为鼠标已经选中的线段。

    计算过程如下:

  1. 第一步,计算鼠标点到线段所在的直线的距离。
  2. 第二步,计算鼠标点到线段两个端点的距离。
  3. 选择上面计算出的三个值,如果存在小于阈值的,那么就认为鼠标选择了线段。
   类似的,在三维中,判断鼠标是否选中线段也是类似的方法,但是计算更加复杂。首先是不存在鼠标点的在空间的位置,鼠标点是二维的。其次,二维图本身就是一个平面系统,而在三维计算中需要进行投影,才能将鼠标点的信息转换为空间信息。
      具体计算过程如下:
      第一步,将鼠标点的信息进行投影,把鼠标模拟成一个光源,起点是鼠标点在平面的位置,光源的方向是三维 视锥体的顶点到鼠标点的射线。
   
            Vector3 nearVector = new Vector3(LastMousePosition.X, LastMousePosition.Y, Camera.Viewport.MinZ);
            Vector3 farVector = new Vector3(LastMousePosition.X, LastMousePosition.Y, Camera.Viewport.MaxZ);

            nearVector.Unproject(device.Viewport, device.Transform.Projection, device.Transform.View, renderWorldMatrix);
            farVector.Unproject(device.Viewport, device.Transform.Projection, device.Transform.View, renderWorldMatrix);
            farVector.Subtract(nearVector);
        上述代码中, renderWorldMatrix是线段在场景中的Transform.World值,如果没有Transform那么就用Matrix.Identity表示。而 Camera.Viewport.MinZ和Camera.Viewport.MaxZ是三维视锥体的前后裁剪面。最后鼠标表示的射线存放在 farVector中。

      第二步,求的射线与线段之间的距离。关于空间中两条直线的空间距离,就是计算直线到一个平行平面的距离,而这个平面的法向是垂直于两条直线,平面所在的位置在一条直线上。
      第三步,求的射线与线段端点之间的距离
      第四步,将上面求得的值与阈值判断,如果存在小于阈值,那么就说明鼠标选中了线段。
 
      下面代码将第二步到第四步整合在一起了
               Vector3 v1 = transformedLineVertex[i];
                Vector3 v2 = transformedLineVertex[i + 1];
                Vector3 v = v2 - v1;
                float a11 = Vector3.Dot(v, farVector);
                
                float a21 = v.LengthSq();
                float a22 = -a11;
                float d1 = Vector3.Dot((nearVector - v1), farVector);
                float d2 = Vector3.Dot((nearVector - v1), v);

                float x = (d1 * a22 - d2 * a12) / (a11 * a22 - a21 * a12);
                float y = (d1 * a21 - d2 * a11) / (a12 * a21 - a22 * a11);

                //求得射线中与线段A最近的点
                Vector3 p1 = new Vector3(nearVector.X + y * farVector.X,
                    nearVector.Y + y * farVector.Y,
                    nearVector.Z + y * farVector.Z);
                //线段A与射线最近的点
                Vector3 p2 = new Vector3(v1.X + x * v.X,
                    v1.Y + x * v.Y,
                    v1.Z + x * v.Z);
                
                //下面是判断是否是否与端点的位置最近
                Vector3 disLine;
                if (x <= 0)
                {
                    disLine = p2 - v1;
                }
                else if (x >= 1)
                {
                    disLine = p2 - v2;
                }
                else
                {
                    disLine = p2 - p1;
                }
          <完>

猜你喜欢

转载自blog.csdn.net/htsitr2/article/details/39186073