【问题标题】:Get screen space coordinates of specific verticies of a 3D model when visible获取可见时 3D 模型特定顶点的屏幕空间坐标
【发布时间】:2011-05-26 10:57:50
【问题描述】:

我想渲染一个模型,然后,如果特定顶点(我将如何标记它们?)是可见的,我想在它们所在的位置渲染一些 2D 的东西。

我该怎么做呢?

【问题讨论】:

    标签: c# xna 3d coordinate-systems


    【解决方案1】:

    首先,您需要将您的顶点位置设为Vector4(透视投影需要使用齐次坐标;设置W = 1)。我假设你知道你想要哪个顶点以及如何获得它的位置。它的位置将在模型空间中。

    现在只需将该点转换为投影空间。也就是说 - 将它乘以您的 World-View-Projection 矩阵。那就是:

    Vector4 position = new Vector4(/* your position as a Vector3 */, 1);
    IEffectMatrices e = /* a BasicEffect or whatever you are using to render with */
    Matrix worldViewProjection = e.World * e.View * e.Projection;
    Vector4 result = Vector4.Transform(position, worldViewProjection);
    result /= result.W;
    

    现在您的结果将在投影空间中,即屏幕左下角的 (-1,-1) 和右上角的 (1,1)。如果你想在客户空间中获得你的位置(这是SpriteBatch 使用的),那么只需使用与SpriteBatch 使用的隐式视图投影矩阵匹配的矩阵的逆矩阵来转换它。

    Viewport vp = GraphicsDevice.Viewport;
    Matrix invClient = Matrix.Invert(Matrix.CreateOrthographicOffCenter(0, vp.Width, vp.Height, 0, -1, 1));
    Vector2 clientResult = Vector2.Transform(new Vector2(result.X, result.Y), invClient);
    

    免责声明:我没有测试任何代码。

    (显然,要检查特定顶点是否可见,只需检查它是否在投影空间中的 (-1,-1) 到 (1,1) 范围内。)

    【讨论】:

    • 要得到[1,-1]范围内的坐标,需要除以齐次分量。代码应该是: Vector4 aux = Vector4.Transform(new Vector4(position, 1), worldViewProjection);结果.X = aux.X /aux.W;结果.Y = aux.Y /aux.W;结果.Z = 辅助.Z /辅助.W;我曾尝试编辑 Andrew 的回复,但已被拒绝... :(
    • 你说的很对。我已经修改了我的答案以考虑到这一点。
    【解决方案2】:

    看看您的引擎的遮挡剔除功能。对于 XNA,您可以在此处查阅框架指南(附示例)。

    http://roecode.wordpress.com/2008/02/18/xna-framework-gameengine-development-part-13-occlusion-culling-and-frustum-culling/

    【讨论】:

      【解决方案3】:

      可能最好的方法是使用BoundingFrustrum。它基本上就像一个向某个方向扩展的矩形,类似于玩家相机的工作方式。然后,您可以检查您想要的给定点是否包含在 BoundingFrustrum 中,如果是,则渲染您的对象。

      基本上,它的形状如下所示:

      例子:

      // A view frustum almost always is initialized with the ViewMatrix * ProjectionMatrix
      BoundingFrustum viewFrustum = new BoundingFrustum(ActivePlayer.ViewMatrix * ProjectionMatrix);
      
      // Check every entity in the game to see if it collides with the frustum.
      foreach (Entity sourceEntity in entityList)
      {
          // Create a collision sphere at the entities location. Collision spheres have a
          // relative location to their entity and this translates them to a world location.
          BoundingSphere sourceSphere = new BoundingSphere(sourceEntity.Position,
                                        sourceEntity.Model.Meshes[0].BoundingSphere.Radius);
      
          // Checks if entity is in viewing range, if not it is not drawn
          if (viewFrustum.Intersects(sourceSphere))
              sourceEntity.Draw(gameTime);
      }
      

      该示例实际上是用于剔除游戏中的所有对象,但可以很容易地对其进行修改以处理您想要做的事情。

      示例来源:http://nfostergames.com/Lessons/SimpleViewCulling.htm

      要将您的世界坐标放入屏幕空间,请查看Viewport.Project

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多