简体   繁体   English

将自定义顶点结构传递给GLSL着色器

[英]Passing custom vertex structure to GLSL shaders

I'm trying to pass a structure to a simple GLSL vetrex shader. 我正在尝试将结构传递给简单的GLSL vetrex着色器。 Here's how the structure look like on the C++ side: 以下是C ++方面的结构:

struct Vertex
{
    float position[3];
    char boneIndex[4];
    float weights[4];
    float normals[3];
    float textureCords[2];
};

Is it possible to pass array of this vertex to the vertex shader without creating a separate array for each component? 是否可以将此顶点的数组传递给顶点着色器而无需为每个组件创建单独的数组?

Can I do something like this: 我可以这样做:

#version 330 core

uniform mat4 MVP;

layout(location = 0) in struct Vertex
{
    vec3 position;
    uint boneIndex;
    vec4 weights;
    vec3 normals;
    vec2 textureCords;
} vertex;

out vec2 UV;

void main()
{
    gl_Position =  MVP * vec4(vertex.position, 1.0f);
    UV = vertex.textureCords;
}

(Dont mind that not all of the components are in use, it's just for the example.) (不要介意并非所有组件都在使用中,它只是用于示例。)

And if I can, how can I pass the data to it from the C++ side using the glVertexAttribPointer() function? 如果可以,我如何使用glVertexAttribPointer()函数从C ++端传递数据? (According to my understanding you can pass only 1,2,3,4 to the size parameter). (根据我的理解,你只能将1,2,3,4传递给size参数)。

Is it the even the right way to do things? 这是做正确的事情吗? I'm a beginner in OpenGL programming so if you have an answer please don't hesitate to include obvious details. 我是OpenGL编程的初学者,所以如果你有答案,请不要犹豫,包括明显的细节。

Edit: 编辑:

I ended up doing something like this: 我最终做了这样的事情:

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);
    glEnableVertexAttribArray(4);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);  //float position[3]
    glVertexAttribPointer(1, 1, GL_INT, GL_FALSE, 12, (void*)0);    //char boneIndex[4]
    glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 16, (void*)0); //float weights[4]
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 32, (void*)0); //float normals[3]
    glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, 44, (void*)0); //float textureCords[2]


    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indiceBuffer);

    glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, (void*)0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
    glDisableVertexAttribArray(4);

On the C++ size, and on the GLSL vertex shader: 在C ++大小和GLSL顶点着色器上:

    #version 330 core

uniform mat4 MVP;

layout(location = 0) in vec3 position;
layout(location = 1) in int boneIndex;
layout(location = 2) in vec4 weight;
layout(location = 3) in vec3 normal;
layout(location = 4) in vec2 UVCords;

out vec2 UV;

void main()
{
    gl_Position =  MVP * vec4(position, 1.0f);
    UV = UVCords;
}

But it still won't work, the model wont render correctly 但它仍然无法正常工作,模型无法正确呈现

The method you've used to transfer the interleaved data is correct (that is, using glVertexAttribPointer , however, your last two parameters are incorrect). 您用于传输交错数据的方法是正确的(即,使用glVertexAttribPointer ,但是,您的最后两个参数不正确)。

The penultimate is the stride (which is the same for every item in the struct, and should be the size of the struct), and the last is the offset , which should be different for each element (as they are at different offsets in the struct itself). 倒数第二个是stride (对于结构中的每个项都是相同的,应该是结构的大小),最后一个是offset ,对于每个元素应该是不同的(因为它们在不同的偏移量中)结构本身)。

Also it is best not to use constants here, but instead, use the sizeof() operator, to make your code as platform independent as possible. 此外,最好不要在此处使用常量,而是使用sizeof()运算符,以使代码尽可能与平台无关。

Here's what it should look like: 这是它应该是什么样子:

glVertexAttribPointer(
    0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr
); //float position[3]

glVertexAttribIPointer(
    1, 1, GL_INT, GL_FALSE, sizeof(Vertex), 
    std::reinterpret_cast<void *>(offsetof(Vertex, boneIndex))
); //char boneIndex[4]

glVertexAttribPointer(
    2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 
    std::reinterpret_cast<void *>(offsetof(Vertex, weights))
); //float weights[4]

glVertexAttribPointer(
    3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 
    std::reinterpret_cast<void *>(offsetof(Vertex, normals))
); //float normals[3]

glVertexAttribPointer(
    4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 
    std::reinterpret_cast<void *>(offsetof(Vertex, textureCoords))
); //float textureCoords[2]

Also, you should probably ensure that your Vertex struct is not packed to fit into a nice word boundary. 此外,您应该确保不打包Vertex结构以适应漂亮的单词边界。 This is done by using #pragma pack(0) , if your compiler supports it. 如果编译器支持,则使用#pragma pack(0)完成此操作。 (Remember to reset this after after your struct, because otherwise the compiler will use this directive throughout the rest of the compilation process, and all your aggregate data structures will be structured in a way that doesn't yield to the best possible fit with regards to world alignment.), here's what that looks like: (请记住在结构之后重置它,因为否则编译器将在整个编译过程的其余部分使用此指令,并且所有聚合数据结构的结构将不会达到最佳方式为了世界一致。),这是看起来像:

#pragma pack(push, 0)

struct Vertex {
    float position[3];
    char  boneIndex[4];
    float weights[4],
          normals[4],
          textureCoords[2];
};

#pragma pack(pop)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM