使用TriangleMesh加载OBJ模型报错:faces.size()需被getFaceElementSize()整除
解决JavaFX TriangleMesh加载OBJ模型不显示及faces尺寸警告问题
问题根源
- 索引格式不匹配:OBJ文件的顶点、纹理、法线索引是1-based,但JavaFX
TriangleMesh要求0-based索引,直接转换会导致索引无效或格式错误。 - 面格式不符合要求:
TriangleMesh仅支持三角形面,OBJ文件中可能存在四边形等多边形,未拆分的话会导致面数组长度不满足getFaceElementSize()的校验(同时使用顶点、纹理、法线时,每个顶点需3个索引,每个三角形需3个顶点,因此面数组总长度必须是9的倍数)。 - 相机位置未适配:即使模型加载正确,相机位置过近或未对准也会导致看不到模型。
解决方案
1. 修改OBJ解析逻辑(核心修复)
修正索引转换,添加多边形三角化处理,修改后的objParser方法如下:
private void objParser(ArrayList<Float> v, ArrayList<Float> vt, ArrayList<Float> vn, ArrayList<Integer> f) { try { File file = new File("C:\\model\\source\\MesaF\\edgy.obj"); FileReader fr = new FileReader(file); BufferedReader reader = new BufferedReader(fr); String line = reader.readLine(); while (line != null) { line = line.trim(); if (line.isEmpty()) { line = reader.readLine(); continue; } String[] strArr = line.split("\\s+"); if (strArr[0].equals("v")) { for (int i = 1; i < strArr.length; i++) { v.add(Float.parseFloat(strArr[i])); } } else if (strArr[0].equals("vt")) { for (int i = 1; i < strArr.length; i++) { vt.add(Float.parseFloat(strArr[i])); } } else if (strArr[0].equals("vn")) { for (int i = 1; i < strArr.length; i++) { vn.add(Float.parseFloat(strArr[i])); } } else if (strArr[0].equals("f")) { // 收集每个顶点的三个索引(转换为0-based) List<int[]> vertexIndices = new ArrayList<>(); for (int i = 1; i < strArr.length; i++) { String[] parts = strArr[i].split("/"); int vIdx = Integer.parseInt(parts[0]) - 1; int vtIdx = parts.length > 1 && !parts[1].isEmpty() ? Integer.parseInt(parts[1]) - 1 : 0; int vnIdx = parts.length > 2 && !parts[2].isEmpty() ? Integer.parseInt(parts[2]) - 1 : 0; vertexIndices.add(new int[]{vIdx, vtIdx, vnIdx}); } // 将多边形拆分为三角形 if (vertexIndices.size() >= 3) { for (int i = 1; i < vertexIndices.size() - 1; i++) { // 第一个顶点 int[] v0 = vertexIndices.get(0); f.add(v0[0]); f.add(v0[1]); f.add(v0[2]); // 第i个顶点 int[] v1 = vertexIndices.get(i); f.add(v1[0]); f.add(v1[1]); f.add(v1[2]); // 第i+1个顶点 int[] v2 = vertexIndices.get(i+1); f.add(v2[0]); f.add(v2[1]); f.add(v2[2]); } } } line = reader.readLine(); } reader.close(); fr.close(); } catch (IOException e) { e.printStackTrace(); } }
2. 调整相机位置
在创建相机后添加位置和视角设置,确保能看到模型:
Camera camera = new PerspectiveCamera(true); camera.setTranslateZ(-10); // 拉远相机距离 camera.setFieldOfView(60); // 设置合适的视角 scene.setCamera(camera);
修复说明
- 索引转换:将OBJ的1-based索引减1,匹配
TriangleMesh的0-based要求,避免索引越界。 - 三角化处理:将OBJ中的多边形拆分为
TriangleMesh支持的三角形,保证面数组长度符合getFaceElementSize()的校验规则。 - 相机适配:通过调整相机位置和视角,确保模型处于相机可视范围内。
内容的提问来源于stack exchange,提问作者dadaya
相关产品推荐
相关产品推荐

