获取 3D 模型可见时特定顶点的屏幕空间坐标

发布于 2024-11-09 20:14:38 字数 80 浏览 0 评论 0原文

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

我该怎么做呢?

I'd like to render a model, then, if particular verticies (how would i mark them?) are visible, i want to render something 2D where they are.

How would i go about doing this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

娜些时光,永不杰束 2024-11-16 20:14:38

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

现在只需将该点变换到投影空间即可。也就是说,将它乘以你的世界观投影矩阵。也就是说:

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) 范围内即可。)

First of all, you need your vertex position as a Vector4 (perspective projections require the use of homogeneous coordinates; set W = 1). I'll assume you know which vertex you want and how to get its position. Its position will be in model space.

Now simply transform that point to projection space. That is - multiply it by your World-View-Projection matrix. That is:

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;

Now your result will be in projection space, which is (-1,-1) in the bottom left corner of the screen, and (1,1) in the top right corner. If you want to get your position in client space (which is what SpriteBatch uses), then simply transform it using the inverse of a matrix that matches the implicit View-Projection matrix used by 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);

Disclaimer: I haven't tested any of this code.

(Obviously, to check if a particular vertex is visible or not, simply check if it is in the (-1,-1) to (1,1) range in projection space.)

潦草背影 2024-11-16 20:14:38

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

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

Take a look at the occlusion culling features of your engine. For XNA, you can consult the framework guide (with samples) here.

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

站稳脚跟 2024-11-16 20:14:38

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

基本上,它形成的形状如下所示:
Shape of a 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

Probably the best way to do this is with a BoundingFrustrum. It's basically like a rectangle that expands out in a certain direction, similar to how a player's camera works. Then, you can check to see if the given point you want is contained in the BoundingFrustrum, and if it is, then render your object.

Basically, the shape it makes looks like this:
Shape of a BoundingFrustrum

Example:

// 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);
}

The example is actually for culling all objects in the game, but it can be pretty easily modified to handle what you want to do.

Example source: http://nfostergames.com/Lessons/SimpleViewCulling.htm

To get your world coordinates into screen space, take a look at Viewport.Project.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文