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,但更实用。您至少可以制作纹理的头部和尾部。
这里真正的解决方案是使用一个对象(例如obj
的vt
导出值)从程序(例如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 的纹理坐标的主要内容,如果未能解决你的问题,请参考以下文章
使用 RemoteView 删除 Widget 中以编程方式生成的布局