【问题标题】:Ray intersection with 3D quads in XNA?射线与 XNA 中的 3D 四边形相交?
【发布时间】:2012-10-24 02:49:38
【问题描述】:

所以我已经成功制作了一条代表未投影到世界中的鼠标的射线,现在我需要检查该射线是否可以与四边形对象相交,这是我用来获取射线的代码:

public Ray GetMouseRay()
    {
        Vector2 mousePosition = new Vector2(cursor.getX(), cursor.getY());

        Vector3 nearPoint = new Vector3(mousePosition, 0);
        Vector3 farPoint = new Vector3(mousePosition, 1);

        nearPoint = viewport.Unproject(nearPoint, projectionMatrix, viewMatrix, Matrix.Identity);
        farPoint = viewport.Unproject(farPoint, projectionMatrix, viewMatrix, Matrix.Identity);

        Vector3 direction = farPoint - nearPoint;
        direction.Normalize();

        return new Ray(nearPoint, direction);
    }

同样,这是我的四边形结构,我用它在 3d 空间中绘制一个“立方体世界”。 公共结构四边形 { 公共 Vector3 起源; 公共 Vector3 左上角; 公共 Vector3 左下; 公共 Vector3 UpperRight; 公共 Vector3 右下角; 公共 Vector3 正常; 公共 Vector3 向上; 公共 Vector3 左;

    public VertexPositionNormalTexture[] Vertices;
      public int[] Indexes;
    public short[] Indexes;


    public Quad( Vector3 origin, Vector3 normal, Vector3 up, 
        float width, float height )
    {
        Vertices = new VertexPositionNormalTexture[4];
        Indexes = new short[6];
        Origin = origin;
        Normal = normal;
        Up = up;

        // Calculate the quad corners
        Left = Vector3.Cross( normal, Up );
        Vector3 uppercenter = (Up * height / 2) + origin;
        UpperLeft = uppercenter + (Left * width / 2);
        UpperRight = uppercenter - (Left * width / 2);
        LowerLeft = UpperLeft - (Up * height);
        LowerRight = UpperRight - (Up * height);

        FillVertices();
    }

    private void FillVertices()
    {
        // Fill in texture coordinates to display full texture
        // on quad
        Vector2 textureUpperLeft = new Vector2( 0.0f, 0.0f );
        Vector2 textureUpperRight = new Vector2( 1.0f, 0.0f );
        Vector2 textureLowerLeft = new Vector2( 0.0f, 1.0f );
        Vector2 textureLowerRight = new Vector2( 1.0f, 1.0f );

        // Provide a normal for each vertex
        for (int i = 0; i < Vertices.Length; i++)
        {
            Vertices[i].Normal = Normal;
        }

        // Set the position and texture coordinate for each
        // vertex
        Vertices[0].Position = LowerLeft;
        Vertices[0].TextureCoordinate = textureLowerLeft;
        Vertices[1].Position = UpperLeft;
        Vertices[1].TextureCoordinate = textureUpperLeft;
        Vertices[2].Position = LowerRight;
        Vertices[2].TextureCoordinate = textureLowerRight;
        Vertices[3].Position = UpperRight;
        Vertices[3].TextureCoordinate = textureUpperRight;

        // Set the index buffer for each vertex, using
        // clockwise winding
        Indexes[0] = 0;
        Indexes[1] = 1;
        Indexes[2] = 2;
        Indexes[3] = 2;
        Indexes[4] = 1;
        Indexes[5] = 3;
    }
}

我发现射线类有一个方法 intersects() 以 plane 结构体作为参数,而平面结构体在构造函数中采用法线和距原点的距离,但我的飞机有一个位置和法线,而不是距离原点的距离,所以我无法转换它们。如何检测我的光线是否与我的四边形结构相交?

编辑: 我意识到我不能使用平面结构,因为它不是有限大小并且不包括角,就像我的四边形一样。我现在需要找到一种方法来检测这条射线是否与我创建的四边形相交...

感谢阅读,我意识到这个问题有点冗长,在此先感谢。

【问题讨论】:

    标签: c# xna intersect reverseprojection


    【解决方案1】:

    我不确定“沿法线到原点的距离”到底是什么意思,但我认为它只是指到原点的距离。你可以从 Vector3 的长度属性中得到它。

    如果这不起作用,还有一个 plane 的构造函数,它在平面上取三个点:

    public Plane (
         Vector3 point1,
         Vector3 point2,
         Vector3 point3
    )
    

    您可以将它与平面上的任意 3 个点(例如四边形的角)一起使用来创建平面。

    【讨论】:

    • 沿平面法线向量的距离意味着,如果平面处于相同的方向,但平移使得它也包含点 (0,0,0),它需要多远移动以到达其实际位置。或者它可能是那个值的负数,我总是把最后一点混在一起:)
    • 好的,但这不是从原点到飞机的最近距离吗?对我来说,这似乎措辞不佳。
    • 是的,但它依赖于这样一个想法,即可以仅根据该法线单位向量和距离来定义平面。
    【解决方案2】:

    由于您使用的是多维数据集,因此您可以使用Ray.Intersects(Plane) 方法。你只需要多几架飞机。

    一旦确定了第一个交点,就可以为立方体的每个垂直面构建更多平面。然后你可以使用Plane.Distance(Vector3)(我很确定这个或类似的东西存在)来确保你的点在每对垂直平面之间。如果不在它们之间,则可以忽略交叉点。

    【讨论】:

      【解决方案3】:

      不完全是您问题的直接答案,但也许您觉得这很相关。

      您是否考虑过构造一个 BoundingBox 对象并使用 Intersects(Ray)? http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.boundingbox.intersects.aspx

      编辑 1:这是我通常的做法。根据您的数据结构,优化也可能更容易(例如,如果您构建更大的边界框来钻入)。

      编辑 2: 根据 Niko 的建议:我不想从示例中发布相关代码(因为总共需要几页才能使上下文有意义),但我可以指出您会感兴趣的部分在。

      1. http://xbox.create.msdn.com/en-US/education/catalog/sample/picking_triangle下载样本
      2. Cursor.cs 文件的底部包含您已经知道的计算射线的内容
      3. 转到 Game.cs 文件。在那里你会发现 UpdatePicking() 调用 RayIntersectsModel(...) 调用 RayIntersectsTriangle(...)

      Ray的变换就是这部分:

      Matrix inverseTransform = Matrix.Invert( modelTransform );
      
      ray.Position = Vector3.Transform( ray.Position, inverseTransform );
      ray.Direction = Vector3.TransformNormal( ray.Direction, inverseTransform );
      

      你想去多深(你的选择有多准确)当然取决于你的需要,但你有它。

      【讨论】:

      猜你喜欢
      • 2015-09-21
      • 2015-08-27
      • 1970-01-01
      • 1970-01-01
      • 2015-05-07
      • 1970-01-01
      • 2011-05-25
      • 1970-01-01
      • 2014-07-28
      相关资源
      最近更新 更多