为什么这个属性数据没有正确加载到顶点着色器?

Why doesn't this attribute data get loaded to the vertex shader correctly?

我想向我的顶点数组对象添加一个整数数组,以定义应该将哪个图像用于该特定顶点,但不知何故,数据在途中被损坏或未正确加载。

我已经尝试加载预设数组并使用 gl_VertexID 选择正确的索引,这很有效,但我更希望将所有数据都放在顶点数组中,而不必加载统一的每帧整数数组。

顶点着色器

#version 330 core

layout (location = 0) in vec4 position;
layout (location = 1) in vec2 textureCoordinate;
//layout (location = 2) in vec3 normals;
layout (location = 3) in int textureIndex;
//layout (location = 4) in mat4 modelMatrix;

// ---------------Temporary--------------
uniform mat4 view;
uniform mat4 model;
// ---------------Temporary end----------

flat out int textureIndexOut;

out DATA {
    vec2 tc;
} vs_out;

void main() {
    mat4 mvp = view * model; 
    gl_Position = mvp * position;
    vs_out.tc = textureCoordinate;
    textureIndexOut = textureIndex;
}

片段着色器

#version 330 core

layout (location = 0) out vec4 color;

flat in int textureIndexOut;

in DATA {
    vec2 tc;
} fs_in;

uniform sampler2D textureSamplers[32];

void main() {
    color = texture(textureSamplers[1], fs_in.tc);
}

创建顶点数组`

public static VertexArray createVAO(float[] vertices, int[] indices, float[] textureCoordinates, 
            float[] normals, int[]textureIndices) {
        int count = indices.length;
        int indexBufferObject = createIndexBuffer(indices);
        int vertexArrayObject = laodVertexArrayObject();
        storeDataInAttributeList(ShaderProgram.VERTEX_ATTRIB, vertices, 3);
        storeDataInAttributeList(ShaderProgram.TEXTURECOORDINATE_ATTRIB, textureCoordinates, 2);
        storeDataInAttributeList(ShaderProgram.TEXTURE_INDEX_ATTRIB, textureIndices, 1);
        return new VertexArray(count, vertexArrayObject, indexBufferObject, indices, vertices, normals, textureCoordinates);
    }

创建 VAO

private static int laodVertexArrayObject() {
        int vertexArrayObjectID = glGenVertexArrays();
        vaos.add(vertexArrayObjectID);                                                          //Adding the VAO to the list of all VAOs
        glBindVertexArray(vertexArrayObjectID);
        return vertexArrayObjectID;
    }

创建 VBO

private static int createIndexBuffer(int[] indices) {
        int indexBufferObjectID = glGenBuffers();
        ibos.add(indexBufferObjectID);                                                          //Adding the IBO to the list of all IBOs
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObjectID);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, BufferUtils.createIntBuffer(indices), GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        return indexBufferObjectID;
    }

storeDataInAttributeList 函数

private static void storeDataInAttributeList(int attributeNumber, float[] data, int coordinateSize) {
        int vertexBufferObjectID = glGenBuffers();
        vbos.add(vertexBufferObjectID);                                                         //Adding the VBO to the list of all VBOs
        glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectID);
        glBufferData(GL_ARRAY_BUFFER, BufferUtils.createFloatBuffer(data), GL_STATIC_DRAW);
        glVertexAttribPointer(attributeNumber, coordinateSize, GL_FLOAT, false, 0, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

private static void storeDataInAttributeList(int attributeNumber, int[] data, int coordinateSize) {
        int vertexBufferObjectID = glGenBuffers();
        vbos.add(vertexBufferObjectID);                                                         //Adding the VBO to the list of all VBOs
        glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectID);
        glBufferData(GL_ARRAY_BUFFER, BufferUtils.createIntBuffer(data), GL_STATIC_DRAW);
        glVertexAttribPointer(attributeNumber, coordinateSize, GL_INT, false, 0, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

渲染批次

public void render() {
        // Final arrays
        float[] vertices = null;
        float[] textureCoordinates = null;
        float[] normals = null;
        int[] indices = null;
        int[] textureIndices = null;
        // The temporary array list of data
        ArrayList<Float> rawVertices = new ArrayList<Float>();
        ArrayList<Float> rawTextureCoordinates = new ArrayList<Float>();
        ArrayList<Float> rawNormals = new ArrayList<Float>();
        ArrayList<Integer> rawIndices = new ArrayList<Integer>();
        ArrayList<Integer> rawTextureIndices = new ArrayList<Integer>();
        // Adding all the data of all the vaos into the temporary array lists
        for(int j = 0; j < rawVAOs.size(); j++) {
            for(int i = 0; i < rawVAOs.get(j).getVertices().length; i++) {
                rawVertices.add(rawVAOs.get(j).getVertices()[i]);
            }
            for(int i = 0; i < rawVAOs.get(j).getIndices().length; i++) {
                if(j == 0) {
                    rawIndices.add(rawVAOs.get(j).getIndices()[i]);
                } else {
                    rawIndices.add(j*rawVAOs.get(j-1).getIndices().length + rawVAOs.get(j).getIndices()[i]);
                }
            }
            for(int i = 0; i < rawVAOs.get(j).getNormals().length; i++) {
                rawNormals.add(rawVAOs.get(j).getNormals()[i]);
            }
            for(int i = 0; i < rawVAOs.get(j).getTextureCoordinates().length; i++) {
                rawTextureCoordinates.add(rawVAOs.get(j).getTextureCoordinates()[i]);
            }
            for(int i = 0; i < rawVAOs.get(j).getTextureIndices().length; i++) {
                rawTextureIndices.add(rawVAOs.get(j).getTextureIndices()[i]);
            }
        }
        // Adding all the data from the temporaray array lists into the final arrays
        vertices = new float[rawVertices.size()];
        for(int i = 0; i < rawVertices.size(); i++) {
            vertices[i] = rawVertices.get(i);
        }
        indices = new int[rawIndices.size()];
        for(int i = 0; i < rawIndices.size(); i++) {
            indices[i] = rawIndices.get(i);
        }
        normals = new float[rawNormals.size()];
        for(int i = 0; i < rawNormals.size(); i++) {
            normals[i] = rawNormals.get(i);
        }
        textureCoordinates = new float[rawTextureCoordinates.size()];
        for(int i = 0; i < rawTextureCoordinates.size(); i++) {
            textureCoordinates[i] = rawTextureCoordinates.get(i);
        }
        textureIndices = new int[rawTextureIndices.size()];
        for(int i = 0; i < rawTextureIndices.size(); i++) {
            textureIndices[i] = rawTextureIndices.get(i);
        }
        // Creating the final vao and rendering it
        this.finalVAO = Loader.createVAO(vertices, indices, textureCoordinates, normals, textureIndices);
        Main.ShaderList.get(shaderIndex).prepare();
        //load transformation matrices
        for(int i = 0; i < texturePointers.size(); i++) {
            glActiveTexture(GL_TEXTURE0+i);
            Main.TextureBufferPointerList.get(texturePointers.get(i)).bind();
        }
        this.finalVAO.render();
        Main.ShaderList.get(shaderIndex).finish();
    }

如果我加载一个整数数组,其中包含第一个对象的所有顶点的 0 和第二个对象的所有顶点的 1,我希望第一个对象使用第一个纹理进行着色,并且使用第二个纹理着色的第二个对象。如果我为两个对象都添加 0 它会起作用,但是一旦我为任何对象添加 1,我就会收到这个巨大的错误消息:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffee7914d6e, pid=5992, tid=0x00000000000006bc
#
# JRE version: Java(TM) SE Runtime Environment (8.0_211-b12) (build 1.8.0_211-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.211-b12 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [ig9icd64.dll+0x24d6e]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

---------------  T H R E A D  ---------------

Current thread (0x000000001f03c800):  JavaThread "renderer" [_thread_in_native, id=1724, stack(0x0000000020990000,0x0000000020a90000)]

siginfo: ExceptionCode=0xc0000005, reading address 0x0000000000000220

Registers:
RAX=0x0000000024f20080, RBX=0x00000000013ae000, RCX=0x00000000013ae000, RDX=0x000000002d611b10
RSP=0x0000000020a8ebb0, RBP=0x000000002d611a50, RSI=0x0000000000000000, RDI=0x0000000024f20080
R8 =0x0000000001221bc0, R9 =0x0000000000008000, R10=0x00000000ffffffff, R11=0x0000000000000000
R12=0x0000000000000000, R13=0x000000001ca43bd0, R14=0x0000000025042310, R15=0x0000000000000000
RIP=0x00007ffee7914d6e, EFLAGS=0x0000000000010246

Top of Stack: (sp=0x0000000020a8ebb0)
0x0000000020a8ebb0:   0000000000000001 0000000001387e50
0x0000000020a8ebc0:   00000000228e5360 00007ffee7a6171f
0x0000000020a8ebd0:   fffffffffffffffe 000000001ca43bd0
0x0000000020a8ebe0:   000000000137ff20 00007ffee79145cf
0x0000000020a8ebf0:   0000000001394720 0000000000000000
0x0000000020a8ec00:   00000000013ae000 000000002d611a50
0x0000000020a8ec10:   000000000000000e 00007ffee7e35300
0x0000000020a8ec20:   0000000000000000 0000000025042310
0x0000000020a8ec30:   0000000024f20080 00007ffee790b731
0x0000000020a8ec40:   0000000001394720 00000000ffffffff
0x0000000020a8ec50:   0000000000000000 00000000ffffffff
0x0000000020a8ec60:   000000000137ff20 00007ffee7b0f4e2
0x0000000020a8ec70:   0000000000000000 00000000ffffffff
0x0000000020a8ec80:   0000000024f20080 000000000137ff20
0x0000000020a8ec90:   fffffffffffffffe 0000000025042310
0x0000000020a8eca0:   0000000000000000 0000000025042310 

Instructions: (pc=0x00007ffee7914d6e)
0x00007ffee7914d4e:   02 00 00 83 e6 01 0f 1f 40 00 0f 1f 84 00 00 00
0x00007ffee7914d5e:   00 00 4c 8b 9f 70 42 03 00 48 8d 95 c0 00 00 00
0x00007ffee7914d6e:   41 8b 8b 20 02 00 00 85 f6 0f 84 81 00 00 00 83
0x00007ffee7914d7e:   f9 10 73 06 48 6b c1 38 eb 5b 44 8d 41 f0 41 8b 


Register to memory mapping:

RAX=0x0000000024f20080 is an unknown value
RBX=0x00000000013ae000 is an unknown value
RCX=0x00000000013ae000 is an unknown value
RDX=0x000000002d611b10 is an unknown value
RSP=0x0000000020a8ebb0 is pointing into the stack for thread: 0x000000001f03c800
RBP=0x000000002d611a50 is an unknown value
RSI=0x0000000000000000 is an unknown value
RDI=0x0000000024f20080 is an unknown value
R8 =0x0000000001221bc0 is an unknown value
R9 =0x0000000000008000 is an unknown value
R10=0x00000000ffffffff is an unknown value
R11=0x0000000000000000 is an unknown value
R12=0x0000000000000000 is an unknown value
R13={method} {0x000000001ca43bd8} 'invokeV' '(J)V' in 'org/lwjgl/system/JNI'
R14=0x0000000025042310 is an unknown value
R15=0x0000000000000000 is an unknown value


Stack: [0x0000000020990000,0x0000000020a90000],  sp=0x0000000020a8ebb0,  free space=1018k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [ig9icd64.dll+0x24d6e]
C  [ig9icd64.dll+0x245cf]
C

积分属性必须由 glVertexAttribIPointer 指定 - 关注 I:

glVertexAttribIPointer(attributeNumber, coordinateSize, GL_INT, 0, 0);

参见 OpenGL 4.6 API 核心配置文件规范; 10.2.1 当前通用属性 ,第 349 页:

When values for a vertex shader attribute variable are sourced from an enabled generic vertex attribute array, the array must be specified by a command compatible with the data type of the variable. The values loaded into a shader attribute variable bound to generic attribute index are undefined if the array for index was not specified by:

  • VertexAttribFormat, for floating-point base type attributes;
  • VertexAttribIFormat with type BYTE, SHORT, or INT for signed integer base type attributes; or
  • VertexAttribIFormat with type UNSIGNED_BYTE, UNSIGNED_SHORT, or UNSIGNED_INT for unsigned integer base type attributes.

进一步注意Index buffer is stated in the Vertex Array Object。如果没有绑定顶点数组对象,则不能绑定索引缓冲区。 (在兼容性配置文件上下文中,有默认的顶点数组对象 0)。

因此必须在索引缓冲区之前创建和绑定顶点数组对象。

int vertexArrayObject = laodVertexArrayObject();
int count = indices.length;
int indexBufferObject = createIndexBuffer(indices);

当然,与 VAO 的关联不能被 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 打破:

private static int createIndexBuffer(int[] indices) {
    int indexBufferObjectID = glGenBuffers();
    ibos.add(indexBufferObjectID);                                                          
    //Adding the IBO to the list of all IBOs
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObjectID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, BufferUtils.createIntBuffer(indices), GL_STATIC_DRAW);

    // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); <----- delete

    return indexBufferObjectID;
}