多个实例数组缓冲区输入未全部/部分发送到顶点着色器

时间:2019-02-06 00:13:12

标签: c++ opengl glsl vbo

尝试在单个绘制指令中渲染多个动画(相同)3D模型。跨模型的动画和当前帧可能无法同步,例如一个人类模型可能正在运行,而另一个模型正在跳跃。

我为此选择的方法是由我正在使用的基础模型格式驱动的:wavefront,这对于动画效果不是很好。每个框架都存储为单独的独立模型。因此,为了实现我的目标,我仅将第一个帧用于渲染(也称为原始模型),然后构建一个纹理缓冲区,以保存每个顶点的帧0和每个帧的平移。

到目前为止,我已经实现了一半的目标:使用实例缓冲区渲染(glVertexAttribDivisorglDrawArraysInstanced),我能够渲染一次帧0,但是可以多次转换以使其得以渲染在几个位置和方向(按实例矩阵输入)。

第二部分更加困难,引入了两个新的输入: 1.一个samplerBufferglTexBuffer),其中包含FramesCount x VerticePerFrame转换向量 2.第二个实例数据输入:每个模型当前帧的索引

// --------------------------------------------------------------
// Preparing my rendering buffers... 
// This is working well, at least as far as the model rendering and dynamic 
// positioning goes ("transfsLocation" input)
// frameIdLocation is the one I'm unsure of
buffer_ids = std::vector<GLuint>(3, 0);
glGenBuffers(3, &buffer_ids[0]);

glBindBuffer(GL_ARRAY_BUFFER, buffer_ids[0]);
glBufferData(GL_ARRAY_BUFFER, vsize * sizeof(bump_t), &data[0], GL_STATIC_DRAW);
glGenVertexArrays(1, &vertexArray);
glBindVertexArray(vertexArray);
{
    glBindBuffer(GL_ARRAY_BUFFER, buffer_ids[0]);
    glVertexAttribPointer(vpointsLocation, 3, GL_FLOAT, GL_FALSE, sizeof(bump_t), (void*)(0));
    glVertexAttribPointer(normalsLocation, 3, GL_FLOAT, GL_FALSE, sizeof(bump_t), (void*)(sizeof(glm::vec3)));
    glVertexAttribPointer(tcoordsLocation, 2, GL_FLOAT, GL_FALSE, sizeof(bump_t), (void*)(sizeof(glm::vec3) + sizeof(glm::vec3)));
    glVertexAttribPointer(tangentLocation, 3, GL_FLOAT, GL_FALSE, sizeof(bump_t), (void*)(sizeof(glm::vec3) + sizeof(glm::vec3) + sizeof(glm::vec2)));
    glVertexAttribPointer(coloursLocation, 4, GL_FLOAT, GL_FALSE, sizeof(bump_t), (void*)(sizeof(glm::vec3) + sizeof(glm::vec3) + sizeof(glm::vec2) + sizeof(glm::vec3)));
    glEnableVertexAttribArray(vpointsLocation);
    glEnableVertexAttribArray(normalsLocation);
    glEnableVertexAttribArray(tcoordsLocation);
    glEnableVertexAttribArray(tangentLocation);
    glEnableVertexAttribArray(coloursLocation);

    // Dynamic buffer of integers (frame indexes). Note the GL_INT type, which I am assuming is the appropriate one here?
    glBindBuffer(GL_ARRAY_BUFFER, buffer_ids[1]);
    glEnableVertexAttribArray(frameIdLocation);
    glVertexAttribPointer(frameIdLocation, 1, GL_INT, GL_FALSE, 0, 0);
    glVertexAttribDivisor(frameIdLocation, 1);

    // Dynamic buffer for 4x4 matrices
    glBindBuffer(GL_ARRAY_BUFFER, buffer_ids[2]);
    for (auto i = 0; i < 4; ++i)
    {
        glEnableVertexAttribArray(transfsLocation + i);
        glVertexAttribPointer(transfsLocation + i, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (const void*)(sizeof(float) * 4 * i));
        glVertexAttribDivisor(transfsLocation + i, 1);
    }
}
glBindVertexArray(0);


// --------------------------------------------------------------
// Preparing the frame transformations texture
std::vector<glm::vec3> framesTransforms;

// Filling framesTransforms with something like this,
// Where each vec3 is a translation of a vertex from the original frame 0 position
framesTransforms = { 
    vec3(), vec3(), vec3(), vec3(), vec3(), // End of frame 0
    vec3(), vec3(), vec3(), vec3(), vec3(), // End of frame 1
    ...
};

const size_t size = framesTransforms.size() * sizeof(glm::vec3);

glGenBuffers(1, &frameBufferId);
glBindBuffer(GL_TEXTURE_BUFFER, frameBufferId);
glBufferData(GL_TEXTURE_BUFFER, size, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_TEXTURE_BUFFER, 0, size, &framesTransforms[0]);

glGenTextures(1, &frameTextureId);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_BUFFER, frameTextureId);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32F, frameBufferId);



// --------------------------------------------------------------
// And now rendering...
// Of course frameIdx.size() == transforms.size()
std::vector<glm::mat4> transforms;
std::vector<int> frameIdx;

// frameIdx is updated regularily with the next frame for each model
// something like:
// for each: frameIdx[ ... ] = (frameIdx[ ... ] + 1) % NumberOfFrames;

glBindBuffer(GL_ARRAY_BUFFER, buffer_ids[buffer_ids.size() - 2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(int) * frameIdx.size(), &frameIdx[0], GL_DYNAMIC_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, buffer_ids[buffer_ids.size() - 1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * transforms.size(), &transforms[0], GL_DYNAMIC_DRAW);

glBindVertexArray(vertexArray);
glDrawArraysInstanced(GL_TRIANGLES, 0, data.size(), transforms.size());
glBindVertexArray(0);




// --------------------------------------------------------------
// And now on the vertex shader side
// All the inputs we saw earlier
in vec3 VS_Position; 
in vec4 VS_Color;
in vec2 VS_TexCoord;
in vec3 VS_Normal;
in vec3 VS_Tangent;
in mat4 VS_Transform;
in int  VS_FrameIndex;

// Frame data sampler: note that I didn't show the C++ setting of those,
// but I was able to test that they are being set correctly 
// (at least FrameSampler is, as I will explain later)
uniform samplerBuffer FrameSampler;
uniform int VertexPerFrame;

// Now we can apply the per instance transformations:
vec3 frameTransform = texelFetch(FrameSampler, VertexPerFrame * VS_FrameIndex + gl_VertexID).xyz;

vec3 position = VS_Position + frameTransform

// P, V and W are of course other uniforms we don't need to explain here :)
gl_Position = (P * V * W) * (VS_Transform * vec4(position, 1.0));

// -> The outcome is several models at different locations/rotations (the effect of VS_Transform), but --mostly-- immobile i.e. VS_FrameIndex or the vertex-translation fetching not working. 
// Note that I do see glitches from time to time, where the model gets sort of dislocated for a split second, and then back to normal


// Here is a little test I ran to prove that I was able to read data from my sampler:

// TEST 1
// Modifying the code above as follows:
// On C++ side, the frame texture is filled with very small/simple data:
framesTransforms = { glm::vec3(0, 0, 0), glm::vec3(0, 3, 0), glm::vec3(0, 6, 0) };

// And assuming we are rendering 3 models, the vertex shader now does:
vec3 frameTransform = texelFetch(FrameSampler, gl_InstanceID).xyz;

// The outcome is indeed 3 models whos respective Y-position is 0, 3 and 6, 
// thus showing that my sampler holds the data I fed in, and I am able to read from it.


// TEST 2
// Using the same data setup for framesTransforms 
// And making sure VS_FrameIndex is within [0,2]
vec3 frameTransform = texelFetch(FrameSampler, VS_FrameIndex).xyz;

// With this, I don't see my 3 models at different heights...

// -> my issue seems to be connected to the dynamic input "VS_FrameIndex" itself...

正如评论中所解释的那样,预期结果是在不同位置有多个模型并被动画化,即遍历帧。

看到的结果确实是几个对象被变换,但是没有动画。

我在前面的评论中提到的故障可能指向该问题:

  1. 以每种方式构建每帧翻译数据
  2. 或使用我提取它的方式(用VS_FrameIndex测试)

第1点可能仍然是开放的,但我在这里没有介绍,因为在我看来VS_FrameIndex的行为是要解决的第一个问题。

您可以从我粘贴的OpenGL / GLSL代码中看到任何错误吗?

编辑: 我在此问题上取得了一些进展,这证实了我在VS_FrameIndex

中设置和/或使用帧ID方面存在问题

我的想法是:显然,实例化矩阵输入正在工作,并且帧ID是顶点着色器中唯一的int输入。因此,我尝试改用vec3

in int  VS_FrameIndex;
vec3 frameTransform = texelFetch(FrameSampler, VertexPerFrame * VS_FrameIndex + gl_VertexID).xyz;

现在变成:

in vec3  VS_FrameIndex;
vec3 frameTransform = texelFetch(FrameSampler, VertexPerFrame * int(VS_FrameIndex.x) + gl_VertexID).xyz;

在初始化方面:

glVertexAttribPointer(frameIdLocation, 1, GL_INT, GL_FALSE, 0, 0);

更改为:

glVertexAttribPointer(frameIdLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);

当然,我还必须调整C ++才能使用vec3中的帧ID,但是通过这些更改,所有内容都可以像魅力一样工作……显然,这只是一个hack,在某个地方仍然存在错误找到。

0 个答案:

没有答案