BufferedReader 空指针异常 Class 资源

BufferedReader Null Pointer Exception Class Resource

我有一个 OBJ 文件和 MTL 文件的解析器,但是我一直收到空指针异常,即使它在那里。我知道我的文件是正确的,因为我仔细检查了文件的位置。资源(源文件)/res/meshes/{}.obj,.mtl

这是我的 MyFile class

package com.darkerminecraft.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class MyFile {

    private static final String FILE_SEPARATOR = "/";

    private String path;
    private String name;

    public MyFile(String path) {
        this.path = FILE_SEPARATOR + path;
        String[] dirs = path.split(FILE_SEPARATOR);
        this.name = dirs[dirs.length - 1];
    }

    public MyFile(String... paths) {
        this.path = "";
        for (String part : paths) {
            this.path += (FILE_SEPARATOR + part);
        }
        String[] dirs = path.split(FILE_SEPARATOR);
        this.name = dirs[dirs.length - 1];
    }

    public MyFile(MyFile file, String subFile) {
        this.path = file.path + FILE_SEPARATOR + subFile;
        this.name = subFile;
    }

    public MyFile(MyFile file, String... subFiles) {
        this.path = file.path;
        for (String part : subFiles) {
            this.path += (FILE_SEPARATOR + part);
        }
        String[] dirs = path.split(FILE_SEPARATOR);
        this.name = dirs[dirs.length - 1];
    }

    public String getPath() {
        return path;
    }

    @Override
    public String toString() {
        return getPath();
    }

    public InputStream getInputStream() {
        return Class.class.getResourceAsStream(path);
    }

    public BufferedReader getReader() throws Exception {
        try {
            InputStreamReader isr = new InputStreamReader(getInputStream());
            BufferedReader reader = new BufferedReader(isr);
            return reader;
        } catch (Exception e) {
            System.err.println("Couldn't get reader for " + path);
            throw e;
        }
    }

    public String getName() {
        return name;
    }

}

这是我的解析器class

package com.darkerminecraft.graphics.mesh;

import java.util.ArrayList;
import java.util.List;

import org.joml.Vector3f;

import com.darkerminecraft.utils.MyFile;

public class MeshLoader {

    public static Mesh load3DModel(String fileName) {
        MyFile objFile = new MyFile("res/meshes/" + fileName + ".obj");

        String line = "";
        String mtlFileName = "";
        String currentFaceMat = "";

        Mesh mesh = new Mesh();

        try {
            while ((line = objFile.getReader().readLine()) != null) {
                String[] lineParts = line.split(" ");
                switch (line.substring(0, 2)) {
                case "v ":
                    Vertex v = new Vertex(createVector(lineParts));
                    mesh.addVertex(v);
                    break;
                case "vn":
                    Normal n = new Normal(createVector(lineParts));
                    mesh.addNormal(n);
                    break;
                case "mt":
                    mtlFileName = lineParts[1];
                    break;
                case "us":
                    currentFaceMat = lineParts[1];
                    break;
                case "f ":
                    Face face = createFace(currentFaceMat, lineParts);
                    mesh.addFace(face);
                    break;
                }
                objFile.getReader().close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        MyFile mtlFile = new MyFile("res/meshes/" + mtlFileName + ".mtl");
        Material mat = null;
        try {
            while ((line = mtlFile.getReader().readLine()) != null) {
                String[] lineParts = line.split(" ");
                switch (line.substring(0, 2)) {
                case "ne":
                    mat = new Material(lineParts[1]);
                    mesh.addMaterial(lineParts[1], mat);
                    break;
                case "Ka":
                    mat.setKa(createVector(lineParts));
                    break;
                case "Kd":
                    mat.setKd(createVector(lineParts));
                    break;
                case "Ks":
                    mat.setKs(createVector(lineParts));
                    break;
                case "Ns":
                    mat.setNs(Float.parseFloat(lineParts[1]));
                    break;
                case "d ":
                    mat.setD(Float.parseFloat(lineParts[1]));
                    break;
                case "il":
                    mat.setIllum(Float.parseFloat(lineParts[1]));
                    break;
                }
                mtlFile.getReader().close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        mesh.normalArray = new float[mesh.vertices.size() * 3];
        
        for(Face face : mesh.faces) {
            decodeNormals(face.indices1, mesh);
            decodeNormals(face.indices2, mesh);
            decodeNormals(face.indices3, mesh);
        }
        
        List<Vertex> materialVertices = new ArrayList<>();
        for(Face face : mesh.faces) {
            Vertex v1 = new Vertex(face.material, face.indices1);
            Vertex v2 = new Vertex(face.material, face.indices2);
            Vertex v3 = new Vertex(face.material, face.indices3);
            materialVertices.add(v1);
            materialVertices.add(v2);
            materialVertices.add(v3);
        }
        
        mesh.vertexArray = new float[mesh.vertices.size() * 3];
        mesh.indexArray = new int[mesh.indices.size() * 3];
        mesh.colorArray = new float[mesh.vertices.size() * 3];
        
        int vertexPointer = 0;
        int colorPointer = 0;
        for(Vertex vertex : mesh.vertices) {
            mesh.vertexArray[vertexPointer++] = vertex.getPosition().x;
            mesh.vertexArray[vertexPointer++] = vertex.getPosition().y;
            mesh.vertexArray[vertexPointer++] = vertex.getPosition().z;
            mesh.colorArray[colorPointer++] = mesh.materials.get(vertex.getMaterialName()).getKd().x;
            mesh.colorArray[colorPointer++] = mesh.materials.get(vertex.getMaterialName()).getKd().y;
            mesh.colorArray[colorPointer++] = mesh.materials.get(vertex.getMaterialName()).getKd().z;
        }
        
        return mesh;
    }

    private static Vector3f createVector(String[] lineData) {
        float x = Float.parseFloat(lineData[1]);
        float y = Float.parseFloat(lineData[2]);
        float z = Float.parseFloat(lineData[3]);

        return new Vector3f(x, y, z);
    }

    private static Face createFace(String materialName, String[] lineData) {
        String[] indices1 = lineData[1].split("/");
        String[] indices2 = lineData[2].split("/");
        String[] indices3 = lineData[3].split("/");

        return new Face(materialName, indices1, indices2, indices3);
    }
    
    private static void decodeNormals(Vector3f vertex, Mesh mesh) {
        int vertexPointer = (int) vertex.x - 1;
        mesh.indices.add(vertexPointer);
        Normal normal = mesh.normals.get((int) vertex.z - 1);
        mesh.normalArray[vertexPointer * 3] = normal.getNormal().x;
        mesh.normalArray[vertexPointer * 3 + 1] = normal.getNormal().y;
        mesh.normalArray[vertexPointer * 3 + 2] = normal.getNormal().z;
    }

}

我收到这个 NullPointerException

Couldn't get reader for /res/meshes/Crate1.obj
java.lang.NullPointerException
    at java.base/java.io.Reader.<init>(Reader.java:167)
    at java.base/java.io.InputStreamReader.<init>(InputStreamReader.java:72)
    at com.darkerminecraft.utils.MyFile.getReader(MyFile.java:59)
    at com.darkerminecraft.graphics.mesh.MeshLoader.load3DModel(MeshLoader.java:22)
    at com.darkerminecraft.Game.main(Game.java:10)
Couldn't get reader for /res/meshes/.mtl
java.lang.NullPointerException
    at java.base/java.io.Reader.<init>(Reader.java:167)
    at java.base/java.io.InputStreamReader.<init>(InputStreamReader.java:72)
    at com.darkerminecraft.utils.MyFile.getReader(MyFile.java:59)
    at com.darkerminecraft.graphics.mesh.MeshLoader.load3DModel(MeshLoader.java:53)
    at com.darkerminecraft.Game.main(Game.java:10)

Class,或者更准确地说java.lang.Class是一个系统class,也就是说Class.class.getResourceAsStream(...)只在系统ClassLoader中寻找资源,即它不使用负责应用程序代码和资源的ClassLoader

将代码更改为 MyFile.class.getResourceAsStream(...)getClass().getResourceAsStream(...)