Android 实现ObjLoader自定义的3D模型加载器类
时间: 2024-03-05 09:52:28 浏览: 19
下面是一个简单的 ObjLoader 类的实现,用于在 Android 应用中加载 .obj 格式的 3D 模型。
```java
public class ObjLoader {
private String objFilePath; // obj 文件路径
private List<Float> vertexList = new ArrayList<>(); // 顶点坐标列表
private List<Float> normalList = new ArrayList<>(); // 法向量列表
private List<Float> texCoordList = new ArrayList<>(); // 纹理坐标列表
private List<Integer> vertexIndexList = new ArrayList<>(); // 顶点索引列表
private List<Integer> normalIndexList = new ArrayList<>(); // 法向量索引列表
private List<Integer> texCoordIndexList = new ArrayList<>(); // 纹理坐标索引列表
public ObjLoader(String objFilePath) {
this.objFilePath = objFilePath;
loadFile();
}
/**
* 加载 .obj 文件
*/
private void loadFile() {
try {
InputStream inputStream = new FileInputStream(objFilePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("v ")) { // 顶点坐标
String[] array = line.split(" ");
for (int i = 1; i < array.length; i++) {
vertexList.add(Float.valueOf(array[i]));
}
} else if (line.startsWith("vn ")) { // 法向量
String[] array = line.split(" ");
for (int i = 1; i < array.length; i++) {
normalList.add(Float.valueOf(array[i]));
}
} else if (line.startsWith("vt ")) { // 纹理坐标
String[] array = line.split(" ");
for (int i = 1; i < array.length; i++) {
texCoordList.add(Float.valueOf(array[i]));
}
} else if (line.startsWith("f ")) { // 面
String[] array = line.split(" ");
for (int i = 1; i < array.length; i++) {
String[] indexArray = array[i].split("/");
vertexIndexList.add(Integer.valueOf(indexArray[0]) - 1);
texCoordIndexList.add(Integer.valueOf(indexArray[1]) - 1);
normalIndexList.add(Integer.valueOf(indexArray[2]) - 1);
}
}
}
reader.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 绘制模型
*/
public void draw() {
FloatBuffer vertexBuffer = BufferUtils.listToFloatBuffer(vertexList);
FloatBuffer normalBuffer = BufferUtils.listToFloatBuffer(normalList);
FloatBuffer texCoordBuffer = BufferUtils.listToFloatBuffer(texCoordList);
IntBuffer vertexIndexBuffer = BufferUtils.listToIntBuffer(vertexIndexList);
IntBuffer normalIndexBuffer = BufferUtils.listToIntBuffer(normalIndexList);
IntBuffer texCoordIndexBuffer = BufferUtils.listToIntBuffer(texCoordIndexList);
// 绘制模型
GLES20.glEnableVertexAttribArray(0);
GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
GLES20.glEnableVertexAttribArray(1);
GLES20.glVertexAttribPointer(1, 3, GLES20.GL_FLOAT, false, 0, normalBuffer);
GLES20.glEnableVertexAttribArray(2);
GLES20.glVertexAttribPointer(2, 2, GLES20.GL_FLOAT, false, 0, texCoordBuffer);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, vertexIndexList.size(),
GLES20.GL_UNSIGNED_INT, vertexIndexBuffer);
GLES20.glDisableVertexAttribArray(0);
GLES20.glDisableVertexAttribArray(1);
GLES20.glDisableVertexAttribArray(2);
}
}
```
该类的 `loadFile()` 方法用于解析 .obj 文件,将其中的顶点坐标、法向量、纹理坐标等数据提取出来。`draw()` 方法则用于将数据绑定到 OpenGL ES 中,并绘制出模型。需要注意的是,由于 .obj 文件中的索引从 1 开始,而在 OpenGL ES 中,索引从 0 开始,因此在读取索引时需要将其减 1。