OpenGL VAO 多个 VBO 绑定问题

OpenGL VAO multiple VBO binding issue

我正在编写现代 openGL 模型加载器,并且 运行 使用 0 以外的着色器属性位置来解决一些问题。我可以将位置属性获取到着色器中,但不是 Blinn 所需的值- Phong 着色(在程序中绑定到以下位置:Ks-3、Ka-4、Kd-5)。这是我用来加载和渲染 OBJ 模型的代码:

public class Model{
private List<Vector3f> vertices=new ArrayList<>();
private List<Vector3f> normals=new ArrayList<>();

private ArrayList<Integer> vaos=new ArrayList<>();
private float[] faces=new float[fvaoSize];
private float[] ks=new float[kvaoSize];
private float[] ka=new float[kvaoSize];
private float[] kd=new float[kvaoSize];
private int currentPlace=0,kcurrentPlace=0;
private static final int fvaoSize=glGetInteger(GL12.GL_MAX_ELEMENTS_VERTICES)-(glGetInteger(GL12.GL_MAX_ELEMENTS_VERTICES)%12);
private static final int kvaoSize=(fvaoSize/4)*3;
private int facesd=0;
private HashMap<String,Material> materials=new HashMap<>();

@SuppressWarnings("unused")
private int plainFaceVAO=0,texFaceVAO=0,normalsFaceVAO=0,normalsTexVAO=0;
@SuppressWarnings("unused")
private int faceOffset=0,
        texOffset=0,texTexture=0,texCoords=0,
        normalOffset=0,normalCoords=0,
        normalTexOffset=0,normalTexNormalCoords,normalTexTexCoords,normalTexTexture=0;
@SuppressWarnings("unused")
private Shader faceShader=null,texShader=null,normalsShader=null,normalTexShader=null;
private Material currMtl=null;

public Model(File f,Shader faceShader,Shader texShader,Shader normalsShader,Shader normalTexShader){
    loadModelData(f);
    this.faceShader=faceShader;
    this.texShader=texShader;
    this.normalsShader=normalsShader;
    this.normalTexShader=normalTexShader;
    faceOffset=glGetUniformLocation(faceShader.getID(),"trans");
    texOffset=glGetUniformLocation(texShader.getID(),"trans");
    texTexture=glGetAttribLocation(texShader.getID(),"tex");
    texCoords=glGetAttribLocation(texShader.getID(),"texCoords");
    normalOffset=glGetUniformLocation(normalsShader.getID(),"trans");
    normalCoords=glGetAttribLocation(normalsShader.getID(),"normalsCoords");
}
@SuppressWarnings("null")
private void loadModelData(File f){
    try(BufferedReader br=new BufferedReader(new FileReader(f))){
        String line="";
        while((line=br.readLine())!=null){
            String[] words=line.split(" ");
            //System.out.println(line);
            if(line.startsWith("#"))
                continue;
            switch(words[0]){
                case OBJ_VERTEX:
                    vertices.add(new Vector3f(parseFloat(words[1]),parseFloat(words[2]),-parseFloat(words[3])));
                    break;
                case OBJ_VERTEX_NORMAL:
                    normals.add(new Vector3f(parseFloat(words[1]),parseFloat(words[2]),-parseFloat(words[3])));
                    break;
                case OBJ_FACE:
                    facesd++;
                    FaceType cft=null;
                    int slashCount=0;
                    for(char c:words[1].toCharArray()){
                        if(c=='/')
                            slashCount++;
                    }

                    if(slashCount==0){
                        cft=FaceType.COORDSONLY;
                    }else if(slashCount==1){
                        cft=FaceType.TEXTURE;
                    }else if(slashCount==2){
                        if(words[0].contains("//")){
                            cft=FaceType.NORMALS;
                        }else{
                            cft=FaceType.NORMALS_AND_TEXTURE;
                        }
                    }
                    switch(cft){
                        case COORDSONLY:
                            Vector3f pos1=vertices.get(Integer.parseInt(words[1])-1);
                            Vector3f pos2=vertices.get(Integer.parseInt(words[2])-1);
                            Vector3f pos3=vertices.get(Integer.parseInt(words[3])-1);
                            Vec3 Ks=(currMtl.getKs()!=null?currMtl.getKs():new Vec3(1));
                            Vec3 Ka=(currMtl.getKa()!=null?currMtl.getKa():new Vec3(1));
                            Vec3 Kd=(currMtl.getKd()!=null?currMtl.getKd():new Vec3(1));
                            float[] temp=new float[]
                                {
                                    pos1.x,pos1.y,pos1.z,1.0f,
                                    pos2.x,pos2.y,pos2.z,1.0f,
                                    pos3.x,pos3.y,pos3.z,1.0f
                                };
                            for(int i=0;i<12;i++){
                                faces[currentPlace+i]=temp[i];
                            }
                            float[] ktemp=new float[]
                                {
                                    Ks.x,Ks.y,Ks.z,
                                    Ks.x,Ks.y,Ks.z,
                                    Ks.x,Ks.y,Ks.z
                                };
                            for(int i=0;i<9;i++){
                                ks[kcurrentPlace+i]=ktemp[i];
                            }
                            ktemp=new float[]
                                {
                                    Ka.x,Ka.y,Ka.z,
                                    Ka.x,Ka.y,Ka.z,
                                    Ka.x,Ka.y,Ka.z
                                };
                            for(int i=0;i<9;i++){
                                ka[kcurrentPlace+i]=ktemp[i];
                            }
                            ktemp=new float[]
                                {
                                    Kd.x,Kd.y,Kd.z,
                                    Kd.x,Kd.y,Kd.z,
                                    Kd.x,Kd.y,Kd.z
                                };
                            for(int i=0;i<9;i++){
                                kd[kcurrentPlace+i]=ktemp[i];
                            }
                            kcurrentPlace+=9;
                            currentPlace+=12;
                            if(currentPlace==fvaoSize){


                                int fvbo=glGenBuffers();
                                FloatBuffer vertexPositionsBuffer=BufferUtils.createFloatBuffer(fvaoSize);
                                vertexPositionsBuffer.put(faces);
                                vertexPositionsBuffer.flip();
                                glBindBuffer(GL_ARRAY_BUFFER, fvbo);
                                glBufferData(GL_ARRAY_BUFFER, vertexPositionsBuffer, GL_STATIC_DRAW);

                                int ksvbo=glGenBuffers();
                                FloatBuffer ksBuffer=BufferUtils.createFloatBuffer(kvaoSize);
                                ksBuffer.put(ks);
                                ksBuffer.flip();
                                glBindBuffer(GL_ARRAY_BUFFER, ksvbo);
                                glBufferData(GL_ARRAY_BUFFER, ksBuffer, GL_STATIC_DRAW);

                                int kavbo=glGenBuffers();
                                FloatBuffer kaBuffer=BufferUtils.createFloatBuffer(kvaoSize);
                                kaBuffer.put(ka);
                                kaBuffer.flip();
                                glBindBuffer(GL_ARRAY_BUFFER, kavbo);
                                glBufferData(GL_ARRAY_BUFFER, kaBuffer, GL_STATIC_DRAW);

                                int kdvbo=glGenBuffers();
                                FloatBuffer kdBuffer=BufferUtils.createFloatBuffer(kvaoSize);
                                kdBuffer.put(kd);
                                kdBuffer.flip();
                                glBindBuffer(GL_ARRAY_BUFFER, kdvbo);
                                glBufferData(GL_ARRAY_BUFFER, kdBuffer, GL_STATIC_DRAW);

                                int vao = glGenVertexArrays();
                                glBindVertexArray(vao);

                                glBindBuffer(GL_ARRAY_BUFFER, fvbo);
                                glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);

                                glBindBuffer(GL_ARRAY_BUFFER, ksvbo);
                                glVertexAttribPointer(3, 3, GL_FLOAT, false, 0, 0);

                                glBindBuffer(GL_ARRAY_BUFFER, kavbo);
                                glVertexAttribPointer(4, 3, GL_FLOAT, false, 0, 0);

                                glBindBuffer(GL_ARRAY_BUFFER, kdvbo);
                                glVertexAttribPointer(5, 3, GL_FLOAT, false, 0, 0);

                                glEnableVertexAttribArray(0);
                                glEnableVertexAttribArray(3);
                                glEnableVertexAttribArray(4);
                                glEnableVertexAttribArray(5);

                                glBindVertexArray(0);

                                glDeleteBuffers(fvbo);
                                glDeleteBuffers(ksvbo);
                                glDeleteBuffers(kavbo);
                                glDeleteBuffers(kdvbo);
                                ksBuffer=null;
                                kaBuffer=null;
                                kdBuffer=null;
                                vertexPositionsBuffer=null;
                                vaos.add(vao);

                                glBindBuffer(GL_ARRAY_BUFFER, 0);
                                currentPlace=0;
                                kcurrentPlace=0;
                                faces=new float[fvaoSize];
                                ks=new float[kvaoSize];
                                ka=new float[kvaoSize];
                                kd=new float[kvaoSize];
                            }
                            break;
                        case NORMALS:
                            throw new RuntimeException("File is unsupported.");
                        case NORMALS_AND_TEXTURE:
                            throw new RuntimeException("File is unsupported.");
                        case TEXTURE:
                            throw new RuntimeException("File is unsupported.");
                        default:
                            throw new RuntimeException("File is unsupported.");
                    }

                    break;
                case OBJ_MTLLIB:
                    materials=MTLLibLoader.loadMTLLib(f.toPath().getParent()+"/"+words[1]);
                    break;
                case OBJ_USEMTL:
                    System.out.println("Using Material "+words[1]+": Exists in hmap: "+materials.containsKey(words[1]));
                    currMtl=materials.get(words[1]);
                    break;
                default:
                    break;
            }
        }
        int fvbo=glGenBuffers();
        FloatBuffer vertexPositionsBuffer=BufferUtils.createFloatBuffer(fvaoSize);
        vertexPositionsBuffer.put(faces);
        vertexPositionsBuffer.flip();
        glBindBuffer(GL_ARRAY_BUFFER, fvbo);
        glBufferData(GL_ARRAY_BUFFER, vertexPositionsBuffer, GL_STATIC_DRAW);

        int ksvbo=glGenBuffers();
        FloatBuffer ksBuffer=BufferUtils.createFloatBuffer(kvaoSize);
        ksBuffer.put(ks);
        ksBuffer.flip();
        glBindBuffer(GL_ARRAY_BUFFER, ksvbo);
        glBufferData(GL_ARRAY_BUFFER, ksBuffer, GL_STATIC_DRAW);

        int kavbo=glGenBuffers();
        FloatBuffer kaBuffer=BufferUtils.createFloatBuffer(kvaoSize);
        kaBuffer.put(ka);
        kaBuffer.flip();
        glBindBuffer(GL_ARRAY_BUFFER, kavbo);
        glBufferData(GL_ARRAY_BUFFER, kaBuffer, GL_STATIC_DRAW);

        int kdvbo=glGenBuffers();
        FloatBuffer kdBuffer=BufferUtils.createFloatBuffer(kvaoSize);
        kdBuffer.put(kd);
        kdBuffer.flip();
        glBindBuffer(GL_ARRAY_BUFFER, kdvbo);
        glBufferData(GL_ARRAY_BUFFER, kdBuffer, GL_STATIC_DRAW);

        int vao = glGenVertexArrays();
        glBindVertexArray(vao);

        glBindBuffer(GL_ARRAY_BUFFER, fvbo);
        glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, ksvbo);
        glVertexAttribPointer(3, 3, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, kavbo);
        glVertexAttribPointer(4, 3, GL_FLOAT, false, 0, 0);

        glBindBuffer(GL_ARRAY_BUFFER, kdvbo);
        glVertexAttribPointer(5, 3, GL_FLOAT, false, 0, 0);

        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(3);
        glEnableVertexAttribArray(4);
        glEnableVertexAttribArray(5);

        glBindVertexArray(0);

        glDeleteBuffers(fvbo);
        glDeleteBuffers(ksvbo);
        glDeleteBuffers(kavbo);
        glDeleteBuffers(kdvbo);
        ksBuffer=null;
        kaBuffer=null;
        kdBuffer=null;
        vertexPositionsBuffer=null;
        vaos.add(vao);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }catch(FileNotFoundException e){
        // TODO Auto-generated catch block
        e.printStackTrace();
    }catch(IOException e){
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("Object \""+f.getName().substring(0,f.getName().lastIndexOf("."))+"\" loaded, has "+facesd+" faces");
}
public void drawModel(Camera c,Vec3 offset){
    //System.err.format("rendering model, %d vaos\n",vaos.size());
    //Matrix4f modelMat=RenderMatrixHelper.getModelMatrix(offset,new Vec3(0));

    faceShader.useShader();
    c.useCameraView();
    glUniform4f(faceOffset,offset.x,offset.y,offset.z,0f);
    for(Integer i:vaos){
        glBindVertexArray(i);
        glDrawArrays(GL_TRIANGLES, 0, fvaoSize/4);
    }
    Shader.stopShader();
    glBindVertexArray(0);
}
public int getNumFaces(){
    return facesd;
}
private enum FaceType{
    COORDSONLY,
    TEXTURE,
    NORMALS,
    NORMALS_AND_TEXTURE,
}

}

我想我已经正确地将 K-VBO 绑定到正确的位置,但是着色器将它们渲染为黑色。这是顶点着色器代码:

#version 330

in vec4 position;
in vec3 normals;
in vec2 texCoords;


uniform vec4 trans;

uniform mat4 view;
uniform mat4 projection;
uniform mat4 model;

void main()
{
    gl_Position = projection*view* (position+trans);//-camera_position;
}

如果 Kd 的值为 (0,0,0),片段着色器输出黑色,否则输出白色。在我的代码中,我已经检查并知道 Kd 是 (.64,.64,.64) 和片段着色器:

#version 330
out vec4 outputColor;

in vec3 Ks;
in vec3 Ka;
in vec3 Kd;

uniform mat4 view;
uniform mat4 projection;

void main()
{   
    if(Kd==vec3(0f)){
        outputColor=vec4(0f);
    }else{
        outputColor=vec4(1f);
    }

}

我找不到问题所在,但如果有人能帮上大忙。谢谢!

我没有详细查看您的代码,但似乎对顶点属性的工作原理存在基本误解。在顶点着色器中,你有这些属性,看起来不错:

in vec4 position;
in vec3 normals;
in vec2 texCoords;

但是在片段着色器中,您有这些定义:

in vec3 Ks;
in vec3 Ka;
in vec3 Kd;

根据代码,您似乎打算将这些用作顶点属性。这是行不通的。您不能将顶点属性直接提供给片段着色器。它们需要是顶点着色器中的 in 个变量。如果您需要片段着色器中的(插值)值,则需要使用顶点着色器中的 out 变量和片段着色器中的 in 变量将它们从顶点着色器传递到片段着色器。

如果你进行错误检查,我很惊讶你的着色器程序甚至链接。 in 片段着色器中的变量(至少只要它们在代码中使用)需要在顶点着色器中具有匹配的 out 变量,而您没有,例如Kd.

当然,如果您的 material 属性至少对于单个对象是不变的,您也可以将它们设为统一而不是属性。

解决了更基本的问题后,要注意的另一个方面是属性的位置。 material 属性的值 3、4 和 5 是固定的。您将需要在着色器代码中使用 glGetAttribLocation()glSetAttribLocation()location 限定符等调用,以确保您用于 glVertexAttribPointer() 等调用的位置与着色器程序中的属性位置。