JavaFX 中以编程方式生成的 TriangleMesh 的纹理坐标

Posted

技术标签:

【中文标题】JavaFX 中以编程方式生成的 TriangleMesh 的纹理坐标【英文标题】:Texture coordinates for a programmatically generated TriangleMesh in JavaFX 【发布时间】:2014-02-24 19:54:06 【问题描述】:

我的程序读入一个 ASCII 编码的 .stl 文件并将其解析为 TriangleMesh,以便将其显示在屏幕上。只要我只想要整个几何图形的单一颜色,它就可以正常工作。但现在我希望能够为网格上的不同多边形分配不同的颜色。稍后我们将知道必须为哪张脸赋予什么颜色,但现在概念证明就足够了。不幸的是,我无法让它工作。 到目前为止,这是我所拥有的:

public static MeshView parseSTLwithColor(String stlString)
    TriangleMesh mesh = new TriangleMesh();

    PhongMaterial textureMaterial = new PhongMaterial();
    Image texture = new Image("http://nikijacob.com/wp-content/uploads/2011/01/Mosaic.jpg");
    textureMaterial.setDiffuseMap(texture);

只需设置一个包含不同颜色的快速测试纹理。

    String withoutHeader = stlString.substring(12);
    String[] facetsArray = withoutHeader.split("endfacet");
    for(int h=0;h<facetsArray.length;h++)
        if(facetsArray[h].contains("endloop"))
        facetsArray[h] = facetsArray[h].substring(0,facetsArray[h].indexOf("endloop"));
        
    
    for(int i= 0 ; i<facetsArray.length;i++)
        int facetOffset = i*3; 
        String[] verticesArray = facetsArray[i].split("vertex");
        if(verticesArray.length != 4) break;
        for(int j=1;j<4;j++)
            String[] vectorArray = verticesArray[j].split(" ");
            for(int k=1;k<4;k++) mesh.getPoints().addAll(Float.parseFloat(vectorArray[k]));    

是的,这不是一个很好的方法,但这只是第一次尝试。基本上,ASCII 编码的网格数据字符串被分割成网格的面,然后每个面被分割成 3 个点,然后每个点被分割成 3 个向量,就像我们在 3d 中一样。每一个都被解析成一个浮点数并添加到 TriangleMesh 的点数组中。

            mesh.getTexCoords().addAll(1/(100+j),1/(100+j));
        

接下来我为每个点分配一个纹理坐标。我尝试给每个点稍微不同的坐标,因为我认为这可能会有所帮助。 (但它没有。)

        mesh.getFaces().addAll((facetOffset), (facetOffset),(1+facetOffset), (1+facetOffset),(2+facetOffset), (2+facetOffset));  
    

    MeshView meshView = new MeshView(mesh);
    meshView.setMaterial(textureMaterial);
    return meshView;

还有一点点家务。从点和纹理坐标构建面,实例化一个 MeshView 并赋予它纹理,这样就可以返回一个带纹理的 Meshview。

现在,问题的表现方式是,不是为面分配不同的颜色,而是 3d 对象的整个表面似乎被赋予了整个纹理的混合。当我用一半的红色和一半的蓝色纹理进行测试时,整个几何图形都呈现为紫色。

【问题讨论】:

【参考方案1】:

嗯...事实证明,当我使用位于我计算机上的 .png 而不是来自互联网的 .gif 时,它可以工作。

【讨论】:

【参考方案2】:

在这里回答一个非常古老的问题,但我自己却掉进了这个兔子洞。

总而言之:使用外部程序在 STL 文件周围包裹纹理是不可行的。

原因是因为 STL 文件没有提供正确的纹理坐标映射(例如 .getTexCoords())。

也就是说,法线贴图非常独特,所以我确实做了一些修改,从刻面剥离法线向量(例如 [1]),计算刻面的数量并对该数字求平方根(假设我们将填充一个方形图像):

int facets = (int)Math.sqrt((lines.size() - 2) / 7);

其中:lines 是文件长度的String[],STL 的页眉和页脚为 2 行,每个方面有 7 行描述。

然后取法线向量并滥用它:

mesh.getTexCoords().addAll(((Float.parseFloat(n) + 1) / -2));

其中:n 是法线向量中的一个值,+ 1// -2 是将法线向量从 -1 -> 0 归一化为 0 -> 1(.getTexCoords() 的可接受范围)。

它很hacky,但更实用。您至少可以制作纹理的头部和尾部。


这里真正的解决方案是使用一个对象(例如objvt 导出值)从程序(例如Blender)实际输出UV 映射:https://blender.stackexchange.com/a/18428

[1]:

facet normal -0 0 1
  outer loop
    vertex -10 12 9
    vertex 10 0 9
    vertex 10 12 9
  endloop
endfacet

【讨论】:

以上是关于JavaFX 中以编程方式生成的 TriangleMesh 的纹理坐标的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 中以编程方式生成视图

使用 RemoteView 删除 Widget 中以编程方式生成的布局

在 CloudFormation 模板中以编程方式生成子网 CIDR 块(或将整数相加)

在 Beam 管道中以编程方式生成 BigQuery 架构

寻找在 xml3d 中以编程方式生成几何图形的示例

如何以编程方式在 JavaFX ComboBox 中设置字符串值