JavaFX 8 3D场景交点

2023-11-27

是否有可能在 JavaFX 8 3D 场景中沿着射线(例如 PickRay)找到点,从 3D 空间中具有某个 3D 方向向量的任意点开始,其中射线与网格中的三角形(MeshView 内的 TriangleMesh)相交?

我知道这是在 Camera/MouseHandler 中完成的用于鼠标拾取,但我看不到任何对任意光线执行此操作的方法。


正如 @jdub1581 所建议的,射线只是一个几何向量,因此为了找到与该向量相交的三角形列表,我们需要解决“线与平面相交”和“线在三角形边界内与平面相交”等问题。

假设我们有一个TriangleMesh,我们有一个顶点列表和一个面列表。每个顶点有 3 个坐标,每个面有 3 个顶点(不考虑纹理、法线……)。为了简单起见,我们使用两个列表Point3D来存储它们。

In this link有多种 3D 形状可供使用。让我们抢一个CuboidMesh.

CuboidMesh cuboid = new CuboidMesh(10f,12f,4f,4);

这将为我们提供以下 3D 形状:

Cuboid

现在,如果我们查看网格,我们可以创建两个包含顶点和面的列表:

List<Point3D> vertices=Arrays.asList(new Point3D(5.0, 6.0, 2.0), 
        new Point3D(5.0, 6.0, 2.0), new Point3D(5.0, -6.0, 2.0), ..., 
        new Point3D(-1.875, -2.25, -2.0), new Point3D(-1.875, -1.5, -2.0));

List<Point3D> faces=Arrays.asList(new Point3D(0, 386, 388), 
        new Point3D(98, 387, 386.0), new Point3D(100, 388, 387), ..., 
        new Point3D(383, 1535, 1537), new Point3D(1536, 1537, 1535));

让我们在场景中添加一些 3D 点,一个原点和一个目标,两者都在全局坐标中,并定义向量的方向(标准化):

Point3D gloOrigin=new Point3D(4,-7,-4);
Point3D gloTarget=new Point3D(2,3,2);
Point3D direction=gloTarget.subtract(gloOrigin).normalize(); // -0.154,0.771,0.617

那么射线方程将是这样的:

r(t) = (4,-7,-4)+t*(-0.154,0.771,0.617)

如果我们在这两点之间添加一个细长的圆柱体,我们将得到射线的视觉表示:

cuboid and ray

边界框交点

第一步将检查光线是否与形状的边界框相交。在形状的局部坐标中,我们有 6 个面,由它们的法线给出,有 6 个中心:

Bounds locBounds = cuboid.getBoundsInLocal();
List<Point3D> normals=Arrays.asList(new Point3D(-1,0,0),new Point3D(1,0,0),
    new Point3D(0,-1,0), new Point3D(0,1,0), new Point3D(0,0,-1), new Point3D(0,0,1));
List<Point3D> positions=Arrays.asList(new Point3D(locBounds.getMinX(),0,0),
    new Point3D(locBounds.getMaxX(),0,0), new Point3D(0,locBounds.getMinY(),0), 
    new Point3D(0,locBounds.getMaxY(),0), new Point3D(0,0,locBounds.getMinZ()), 
    new Point3D(0,0,locBounds.getMaxZ()));

由于我们将在本地系统上工作,因此我们需要以下坐标中的原点:

Point3D gloOriginInLoc = cuboid.sceneToLocal(gloOrigin); // 4,-7,-4 since the box is centered in 0,0,0

现在,对于六个面中的任何一个,我们得到距离t到随后的飞机link。然后我们可以检查该点是否属于盒子。

AtomicInteger counter = new AtomicInteger();
IntStream.range(0, 6).forEach(i->{
    double d=-normals.get(i).dotProduct(positions.get(i));
    double t=-(gloOriginInLoc.dotProduct(normals.get(i))+d)/
              (gloDirection.dotProduct(normals.get(i)));

    Point3D locInter=gloOriginInLoc.add(gloDirection.multiply(t));
    if(locBounds.contains(locInter)){
        counter.getAndIncrement();
    }
});

If counter.get()>0然后我们在射线和形状之间有一些交点,我们可以继续处理三角形。在此示例中,这些将是交点:(3.5,-4.5,-2) 和 (2.5,0.5,2)。

三角形相交

有多种算法可用于查找射线是否与网格的任何三角形相交,因此我们不需要重新发明轮子。

我用过的那个是来自托马斯·穆勒和本·特朗博尔。它将提供距离t从原点到平面的坐标u,v在给定交点的三角形内部。

一旦我们有了形状的局部坐标原点,并且知道了射线的方向,该算法的实现如下:

private final float EPS = 0.000001f;

public List<Point3D> getIntersections(Point3D origin, Point3D direction, 
                                      List<Point3D> points, List<Point3D> faces){

    return faces.parallelStream().filter(f->{
        // vertices indices
        int p0=(int)f.getX(); 
        int p1=(int)f.getY(); 
        int p2=(int)f.getZ();

        // vertices 3D coordinates
        Point3D a = points.get(p0);
        Point3D b = points.get(p1);
        Point3D c = points.get(p2);

        Point3D edge1 = b.substract(a);
        Point3D edge2 = c.substract(a);
        Point3D pvec=direction.crossProduct(edge2);
        float det=edge1.dotProduct(pvec);

        if(det<=-EPS || det>=EPS){
            float inv_det=1f/det;
            Point3D tvec=origin.substract(a);
            float u = tvec.dotProduct(pvec)*inv_det;
            if(u>=0f && u<=1f){
                Point3D qvec=tvec.crossProduct(edge1);
                float v = direction.dotProduct(qvec)*inv_det;
                if(v>=0 && u+v<=1f){
                    float t = c.dotProduct(qvec)*inv_det;
                    System.out.println("t: "+t+", u: "+u+", v: "+v);
                    return true;
                }
            }
        }
        return false;
    }).collect(Collectors.toList());
}

在此示例中,我们找到由以下顶点给出的三个面:(85, 1245, 1274)、(85, 1274, 1266) 和 (351, 1476, 1479)。

如果我们绘制这些面将会看到交集:

Cuboid intersections

请注意,通过在形状的局部坐标系中执行所有操作,我们节省了将每个三角形转换到全局坐标系的操作。

这个算法确实很快。我在不到 40 毫秒的时间内测试了多达 300 万个三角形。

本次测试的所有代码均可用here.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaFX 8 3D场景交点 的相关文章

随机推荐

  • 无法使 GWT 应用程序作为 Chrome 打包应用程序工作,可能是由于 CSP

    不断收到 CSP 错误 拒绝执行内联脚本 因为它违反了以下内容安全策略指令 script src self 该问题可能是由于 GWT 生成的 HTML 文件包含内联 JS UPD 更改为清单版本 1 有所帮助 但这是一个临时解决方法 因为
  • Java世界里有类似WPF和MVVM的东西吗?

    Java世界里有类似WPF和MVVM的东西吗 你见过吗eFace eFace 是 Java 中的 XAML WPF 解决方案 第一个版本可用于 现在下载 http www soyatec com eface installation Jav
  • 我可以在 .ld 文件中使用预处理器指令吗

    我可以在 ld 文件中使用预处理器指令吗 我需要使用两组 ld 文件中的一组 并希望让构建引擎使用宏来决定 我可以这样做吗 是的你可以 您需要为链接器脚本手动运行预处理器 如下所示 in your linker script ld out
  • 为什么 Scala 中的柯里化需要多个参数列表?

    假设我有一个有 2 个参数的函数 需要部分应用 我需要将其定义为 def f a Int b Int some code 然后我可以将其部分应用为def fWithA f a 我的问题是 为了柯里化函数 为什么 Scala 要求使用多个参数
  • 相当于Java中C的“_getch()”函数吗?

    我使用 Google Wave 并且我想模拟在您实际按下 Enter 键之前发送消息的功能 Java中是否有相当于C函数的函数 getch 您可以使用 JLine 库的 ConsoleReader readVirtualKey 方法 看ht
  • 当页面重新加载时,JavaScript setTimeout 函数是否停止?

    如果我发起一个setTimeout函数从触发器 当页面重新加载时函数会停止吗 我发起一个setTimeout功能periodic update on the onload我的页面的事件 这是否创建了多个实例periodic update 功
  • C++0x 将不再有概念。意见?这将如何影响你?

    在 2009 年 7 月C 0x 法兰克福会议 决定删除概念来自 C 0x 就我个人而言 我很失望 但我宁愿有一个可实现的 C 0x 也不愿没有 C 0x 他们表示将在稍后添加 您对此决定 问题有何看法 它将如何影响你 就我个人而言 我对删
  • 将文本基线与 div 底部对齐

    我正在尝试调整baseline中的某些文本div到所说的最底部边缘div 这样的角色就像g and j实际上会溢出 div 我似乎只能将文本元素的底部边缘与文本元素的底部边缘对齐div 我尝试过使用vertical align有价值观bas
  • CSS 选择器 * + * 定义?

    css 选择器 到底是什么意思 当您执行检查元素时 您可以在谷歌浏览器的控制台中看到它 根据我的说法 这似乎是对 每个第二个孩子 应用一种风格 但仍然想确定一下 谁能帮我吗 Example margin top 1em 表示 任何具有前一个
  • 通用 UITableView 键盘调整大小算法

    我搜索了很多调整表视图大小以适应键盘显示和隐藏的代码 但我遇到的几乎每一篇文章都假设表视图正在获取其视图控制器的整个视图 我有一个 iPad 应用程序 其中表格视图仅占据屏幕的一部分 在这种情况下调整表视图大小的正确方法是什么 我上面提到的
  • 相机覆盖随方位角和高度变化

    Folks 我正在尝试获取如下图所示的实用程序 基本上 相机显示窗口覆盖了设备屏幕的一部分 并且由曲线或直线连接的点列表作为覆盖层呈现在相机视图上 我知道这可以使用石英来绘制 但这还不到我的问题的一半 真正的问题是 随着方位和标高的变化 叠
  • 如何在Python中读取/dev/random

    我在一本书上读到 dev random就像一个无限文件 但是当我设置以下代码来查看内容是什么样子时 它什么也不打印 with open dev random as f for i in xrange 10 print f readline
  • ValueError:输入 0 与层 conv_1 不兼容:预期 ndim=3,发现 ndim=4

    我正在尝试制作一个变分自动编码器来学习编码 DNA 序列 但遇到了意外错误 我的数据是一组单热数组 我遇到的问题是值错误 它告诉我 我有一个四维输入 而我的输入显然是三维的 100 4008 4 事实上 当我打印出seq层 它说它的形状是
  • 删除超过 2 小时的 Firebase 数据

    我想删除超过两个小时的数据 目前 在客户端 我循环遍历所有数据并对过时的数据运行删除 当我这样做时 db on value 每次删除某些内容时都会调用该函数 另外 只有当客户端连接时才会删除内容 如果两个客户端同时连接会发生什么 我在哪里可
  • 有没有办法与 Netbeans 和 Github 一起工作,同步它们

    有没有办法与 Netbeans 和 Github 一起工作 同步它们 Netbeans 或其他东西的 Github 插件 Update NetBeans 7 0 现在在某些功能级别上对 Git 提供本机支持 它可以从 插件门户 更新中心 工
  • 如何更改 NuGet 包中的目标文件名?

    JavaScript 命名约定要求文件名中包含版本号 例如jQuery 1 34 min js 我有将输出的文本模板my library js在输出文件夹中 我想创建 NuGet 包my library js以这种方式 在安装时应将其部署为
  • 需要在 Singleton 类中私有化赋值运算符

    有人可以证明在 Singleton 类实现中私有化赋值运算符的必要性吗 它解决了什么问题Singleton operator Singleton const 私人的 class Singleton public static Singlet
  • 将对象的 NSMutableArray 保存/写入磁盘?

    最初我认为这会起作用 但现在我明白它不会起作用 因为artistCollection是一个 Artist 对象的NSMutableArray interface Artist NSObject NSString firName NSStri
  • 如何保存使用rhandsontable r包所做的编辑

    我的 R 程序按预期工作 它显示了一个包含我的数据帧的表 并允许我编辑值 如何捕获这些值并将它们保存到我的数据框或数据框的副本中 require shiny library rhandsontable DF data frame val 1
  • JavaFX 8 3D场景交点

    是否有可能在 JavaFX 8 3D 场景中沿着射线 例如 PickRay 找到点 从 3D 空间中具有某个 3D 方向向量的任意点开始 其中射线与网格中的三角形 MeshView 内的 TriangleMesh 相交 我知道这是在 Cam