【问题标题】:Texture UVs not sent to shaders correctly纹理 UV 未正确发送到着色器
【发布时间】:2016-08-06 06:30:56
【问题描述】:

我正在使用 GLSL 着色器和 VBO 渲染网格,VBO 存储 4 个属性; positionXYZ、normalXYZ、textureUV、colorRGBA。一切正常,除了 UV(也可能是法线,但我还没有办法测试它们)。

发生的情况是,阵列中的纹理 UV 位置偏移到阵列中的正常 x 和 y 位置。顺便说一下,该数组的结构为VVVNNNTTCCCC(顶点位置、法线、纹理、颜色)。我很确定问题出在将 VBO 发送到着色器的某个地方。我确定 VBO 中的数据顺序正确。

这是我的渲染代码:

VBO 类

public final class Mesh
{
    public static final int FLOAT_SIZE_BYTES = 4;
    public static final int FLOATS_PER_POSITION = 3;
    public static final int FLOATS_PER_NORMAL = 3;
    public static final int FLOATS_PER_TEXTURE = 2;
    public static final int FLOATS_PER_COLOUR = 4;
    public static final int VERTEX_SIZE_FLOATS = FLOATS_PER_POSITION + FLOATS_PER_NORMAL + FLOATS_PER_TEXTURE + FLOATS_PER_COLOUR;
    public static final int VERTEX_SIZE_BYTES = VERTEX_SIZE_FLOATS * FLOAT_SIZE_BYTES;

    public static final int POSITION_OFFSET_FLOATS = 0;
    public static final int NORMAL_OFFSET_FLOATS = POSITION_OFFSET_FLOATS + FLOATS_PER_POSITION;
    public static final int TEXTURE_OFFSET_FLOATS = NORMAL_OFFSET_FLOATS + FLOATS_PER_NORMAL;
    public static final int COLOUR_OFFSET_FLOATS = TEXTURE_OFFSET_FLOATS + FLOATS_PER_TEXTURE;
    public static final int POSITION_OFFSET_BYTES = POSITION_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
    public static final int NORMAL_OFFSET_BYTES = NORMAL_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
    public static final int TEXTURE_OFFSET_BYTES = TEXTURE_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
    public static final int COLOUR_OFFSET_BYTES = COLOUR_OFFSET_FLOATS * FLOAT_SIZE_BYTES;
    public static final int POSITION_STRIDE_BYTES = VERTEX_SIZE_BYTES;
    public static final int NORMAL_STRIDE_BYTES = VERTEX_SIZE_BYTES;
    public static final int TEXTURE_STRIDE_BYTES = VERTEX_SIZE_BYTES;
    public static final int COLOUR_STRIDE_BYTES = VERTEX_SIZE_BYTES;

    public final static int VERTICES_PER_FACE = 3;

    public static final int ATTRIBUTE_LOCATION_POSITION = 0;
    public static final int ATTRIBUTE_LOCATION_NORMAL = 1;
    public static final int ATTRIBUTE_LOCATION_TEXTURE = 2;
    public static final int ATTRIBUTE_LOCATION_COLOUR = 3;

    private int vaoID;
    private int iboID;
    private int indexCount;

    private Mesh(int vaoID, int iboID, int indexCount)
    {
        this.vaoID = vaoID;
        this.iboID = iboID;
        this.indexCount = indexCount;
    }

    public void draw(AbstractShaderProgram shader, Texture texture)
    {
        glEnable(GL_TEXTURE_2D);
        if (texture != null) texture.bind(shader);
        else Texture.MISSING_TEXTURE.bind(shader);

        glBindVertexArray(vaoID);
        glEnableVertexAttribArray(ATTRIBUTE_LOCATION_POSITION);
//        glEnableVertexAttribArray(ATTRIBUTE_LOCATION_NORMAL);
//        glEnableVertexAttribArray(ATTRIBUTE_LOCATION_TEXTURE);
//        glEnableVertexAttribArray(ATTRIBUTE_LOCATION_COLOUR);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
        glDrawElements(GL_TRIANGLES, indexCount, GL_FLOAT, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        glDisableVertexAttribArray(ATTRIBUTE_LOCATION_POSITION);
//        glDisableVertexAttribArray(ATTRIBUTE_LOCATION_NORMAL);
//        glDisableVertexAttribArray(ATTRIBUTE_LOCATION_TEXTURE);
//        glDisableVertexAttribArray(ATTRIBUTE_LOCATION_COLOUR);

        glBindVertexArray(0);

        glDisable(GL_TEXTURE_2D);
    }

    public static Mesh compile(List<Face> faces)
    {
        if (faces.size() <= 0)
            throw new RuntimeException("Failed to compile mesh. No faces were provided.");

        HashMap<Vertex, Integer> indexMap = new HashMap<>();
        ArrayList<Vertex> vertices = new ArrayList<>();
        int vertexCount = 0;


        for (Face face : faces)
        {
            for (Vertex vertex : face.getVertices())
            {
                if (!indexMap.containsKey(vertex))
                {
                    indexMap.put(vertex, vertexCount++);
                    vertices.add(vertex);
                }
            }
        }

        int indicesCount = faces.size() * VERTICES_PER_FACE;

        int dataSize = vertexCount * VERTEX_SIZE_FLOATS;
        FloatBuffer vertexData = BufferUtils.createFloatBuffer(dataSize);
        if (vertexData == null)
            System.err.println("Failed to allocate FloatBuffer with size " + dataSize);

        for (Vertex vertex : vertices)
        {
            vertexData.put(vertex.getPosition().x);
            vertexData.put(vertex.getPosition().y);
            vertexData.put(vertex.getPosition().z);
//            vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().x);
//            vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().y);
//            vertexData.put(vertex.getNormal() == null ? 1.0F : vertex.getNormal().z);
//            vertexData.put(vertex.getTexture() == null ? 0.0F : vertex.getTexture().x);
//            vertexData.put(vertex.getTexture() == null ? 0.0F : vertex.getTexture().y);
//            vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().x);
//            vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().y);
//            vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().z);
//            vertexData.put(vertex.getColour() == null ? 1.0F : vertex.getColour().getRGBA().w);
        }
        vertexData.flip();

        IntBuffer indices = BufferUtils.createIntBuffer(indicesCount);

        for (Face face : faces)
        {
            for (Vertex vertex : face.getVertices())
            {
                int index = indexMap.get(vertex);
                indices.put(index);
            }
        }
        indices.flip();

        int vaoID = glGenVertexArrays();
        glBindVertexArray(vaoID);

        int vboID = glGenBuffers();
        glBindBuffer(GL_ARRAY_BUFFER, vboID);

        glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);

        glVertexAttribPointer(ATTRIBUTE_LOCATION_POSITION, FLOATS_PER_POSITION, GL_FLOAT, false, 0, 0);
//        glVertexAttribPointer(ATTRIBUTE_LOCATION_NORMAL, FLOATS_PER_NORMAL, GL_FLOAT, false, NORMAL_STRIDE_BYTES, NORMAL_OFFSET_BYTES);
//        glVertexAttribPointer(ATTRIBUTE_LOCATION_TEXTURE, FLOATS_PER_TEXTURE, GL_FLOAT, false, TEXTURE_STRIDE_BYTES, TEXTURE_OFFSET_BYTES);
//        glVertexAttribPointer(ATTRIBUTE_LOCATION_COLOUR, FLOATS_PER_COLOUR, GL_FLOAT, false, COLOUR_STRIDE_BYTES, COLOUR_OFFSET_BYTES);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);

        int iboID = glGenBuffers();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

        return new Mesh(vaoID, iboID, indicesCount);
    }
}

顶点着色器:

#version 400 core

in vec3 vertPosition;
in vec3 vertNormal;
in vec2 vertTexture;
in vec4 vertColour;

uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;

out vec3 pVertPosition;
out vec3 pVertNormal;
out vec2 pVertTexture;
out vec4 pVertColour;

void main()
{
    pVertPosition = vertPosition;
    pVertNormal = vertNormal;
    pVertTexture = vertTexture;
    pVertColour = vertColour;

    gl_Position = vec4(vec3(vertPosition.xy + vertTexture, vertPosition.z), 1.0);
}

片段着色器:

#version 400 core

in vec3 ppVertPosition;
in vec3 ppVertNormal;
in vec2 ppVertTexture;
in vec4 ppVertColour;

uniform sampler2D texture;

void main()
{
    gl_FragColor = texture2D(texture, ppVertTexture);
}

在它们之间有一个几何着色器,但它目前是多余的,只是将信息直接传递到片段着色器(这就是 out 和 in 变量不匹配的原因。)另外,添加 textureUV 的原因到片段着色器中的顶点位置是为了调试实际传递的纹理 UV 值是什么。这就是我知道 UV 偏移到正常 xy 的方式。如果我将纹理 UV 放入正常的 xy 中,它们就可以正常工作。

如果您想查看任何我没有包含的额外代码,我会添加它。我没有添加所有内容,例如整个 VBO 类,因为它的代码太多。我只列出了我认为相关的内容以及我认为问题出在哪里。

编辑#1: 着色器中的变量位置,例如vertPositionvertNormal 是绑定的。这是我绑定它们的代码

glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_POSITION, "vertPosition");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_NORMAL, "vertNormal");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_TEXTURE, "vertTexture");
glBindAttribLocation(program, Mesh.ATTRIBUTE_LOCATION_COLOUR, "vertColour");

改变顶点着色器以使用布局,像这样,产生完全相同的结果;

layout(location = 0) in vec3 vertPosition;
layout(location = 1) in vec3 vertNormal;
layout(location = 2) in vec2 vertTexture;
layout(location = 3) in vec4 vertColour;

编辑 #2 我决定发布整个 Mesh 类,而不仅仅是其中的一部分。我也尝试过实现 VAO 而不是 VBO,但它不起作用。

【问题讨论】:

    标签: java opengl glsl vbo texture-mapping


    【解决方案1】:

    您将标准管道功能与自定义着色器变量混合在一起。

    调用glEnableClientState(GL_VERTEX_ARRAY); 告诉OpenGL 使用某个数据绑定点,一切都很好。

    调用glVertexPointer( 告诉OpenGL 在哪里找到它的顶点。由于您之前启用了正确的数组,所以一切都很好。

    然后我们进入顶点着色器,你使用in vec3 vertPosition;,但 GLSL 不知道你想要你的顶点数据。当然,我们可以看到名称是“vertPosition”,但是 GLSL 当然不应该根据变量名称来猜测您想要的数据!相反,GLSL 的默认管道行为是使用gl_Vertex,这是一个与GL_VERTEX_ARRAY 绑定的预构建 GLSL 变量。

    那么为什么它适用于职位?我猜,您定义的变量偶然被分配了预构建的常量,这真是太幸运了。

    您应该做的是将glEnableClientState 切换到glEnableVertexAttribArray,使用Layouts 为每个变量分配一个数字,然后调用glVertexAttribPointer 而不是glVertexPointer 将该数字链接到正确的数据。

    现在,您声明的变量(如 vertPosition)指向缓冲区中的正确数据,这不是偶然的,而是因为您告诉他们这样做!

    这是在现代 OpenGL 中做事的正确方法,使用像 gl_Vertex 这样的预构建变量和像 glEnableClientState 这样的函数被认为是旧的和坏的,因为它不灵活。

    您也可以省略布局(因为它需要 OGL 4+,并不是每个人都有),但这需要在链接着色器之前做更多的工作。

    祝你好运!

    More info on converting your code

    (我希望我是对的,我无法评论以实际验证这是问题所在)

    【讨论】:

    • 嗯,对不起,我没有包含此代码,但它的工作原理并不是运气。我绑定了vertPositionvertNormal 等,只是没有在问题上发布该代码。对不起。我的代码如下:glBindAttribLocation(program,Mesh.ATTRIBUTE_LOCATION_POSITION, "vertPosition");
    • 哈哈,好吧,可惜了。我仍然建议您删除客户端状态并改用glEnableVertexAttribArray(Mesh.ATTRIBUTE_LOCATION_POSITION ),它仍然可能会导致问题。并将glVertexAttribPointer 与您指定的索引一起使用。所以glVertexAttribPointer(Mesh.ATTRIBUTE_LOCATION_POSITION ....
    • glVertexAttribPointer 应该替换 glVertexPointer 和其他,只是为了澄清。
    • 所以,我似乎无法让 VAO 工作。它什么也不渲染。我已将整个课程以当前状态发布在主帖中。
    【解决方案2】:

    好的,我得到了它的工作......终于。我不知道 VBO 最初的问题是什么,但是一旦我切换到使用 VAO,而不是使用 glClientState 进行渲染,它就可以正常工作了。此外,我遇到的 VAO 没有渲染任何东西的问题是:

    glDrawElements(GL_TRIANGLES, indexCount, GL_FLOAT, 0);
    

    应该是

    glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-29
      • 2013-05-06
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多