用于在 slam 中绘制特征点的 opengl 着色器

opengl shader for drawing feature point in slam

我想使用 opengl 着色器绘制点。 现在我的代码使用 glvertex3f(pos.x, pos.y, pos.z) 但是当使用它绘制的点太多时,它会变慢。所以我想使用着色器和 glDrawarrays。但它不起作用。请检查我的代码。

原代码:

for (const auto lm : landmarks) {
     const openvslam::Vec3_t pos_w = lm->get_pos_in_world();
     glColor3ub(lm->color_[0], lm->color_[1], lm->color_[2]);
     glVertex3f(pos_w.cast<float>().eval().x(),pos_w.cast<float>().eval().y(), pos_w.cast<float>().eval().z());
    }

我的代码:

for (const auto lm : landmarks) {

const openvslam::Vec3_t pos_w = lm->get_pos_in_world();
int buffer_size =  local_landmarks.size();

glGenBuffers(2, buffers_);

glBindBuffer(GL_ARRAY_BUFFER, buffers_[0]);
glm::vec3 pos_pt = glm::vec3(pos_w.cast<float>().eval().x(),pos_w.cast<float>().eval().y(), pos_w.cast<float>().eval().z());
glBufferData(GL_ARRAY_BUFFER, 3*buffer_size*sizeof(float), &pos_pt , GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, buffers_[1]);
glm::vec3 color_pt = glm::vec3(lm->color_[0], lm->color_[1], lm->color_[2]);
glBufferData(GL_ARRAY_BUFFER, buffer_size*3*sizeof(float), &color_pt, GL_DYNAMIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);

Eigen::Matrix4f mvp = s_cam_shader_opengl->GetProjectionModelViewMatrix();
//Eigen::Matrix4f mvp = s_cam_shader_opengl->GetProjectionMatrix() * s_cam_shader_opengl->GetModelViewMatrix();
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, mvp.data());

glPointSize(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_POINTS, 0, 3*num);

}

顶点着色器

#version 460

uniform mat4 mvpMat;

layout (location = 0) in vec3 test_position;
layout (location = 1) in vec3 test_color;

out vec3 colorr;

void main(void){
       colorr = test_color;
       gl_Position = vec4(test_position,1.0);
        }

片段着色器

#version 460

uniform mat4 mvpMat;


    in vec3 colorr;
    out vec4 frag_color;

    void main(void) {
        frag_color = vec4(colorr, 1.0);
    }

////////////////////////////////////////// //////////////////////////

+编辑

我更新了代码,但它说分段错误。 有什么问题吗?

struct TLandmarkData
{
    glm::vec3 pos;
    glm::vec3 color;
};
using TLandmarks = std::vector<TLandmarkData>;

TLandmarks landmarks_;


...
code
...

glUseProgram(points_program_);


while(){

...

for (const auto lm : landmarks) {
TLandmarkData aaa;

glm::vec3 pos_pt = glm::vec3(pos_w.cast<float>().eval().x(),pos_w.cast<float>().eval().y(), pos_w.cast<float>().eval().z());
glm::vec3 color_pt = glm::vec3(lm->color_[0], lm->color_[1], lm->color_[2]);
aaa.pos = pos_pt;
aaa.color = color_pt;

landmarks_.push_back(aaa);
}

...

GLuint vbo_;
GLuint vao_;

glGenBuffers(1, &vbo_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, landmarks_.size()*sizeof(*landmarks_.data()), landmarks_.data(), GL_STATIC_DRAW);

glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TLandmarkData), 0);
glEnableVertexAttribArray( 0 );
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(TLandmarkData), (void*)(sizeof(glm::vec3)));
glEnableVertexAttribArray(1);

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


glDrawArrays(GL_POINTS, 0, landmarks_.size());


}

顶点着色器

#version 460

layout (location = 0) in vec3 test_position;
layout (location = 1) in vec3 test_color;

out vec3 colorr;

void main(void){
       colorr = test_color;
       gl_Position =   vec4(test_position,1.0);
        }

片段着色器

#version 460

in vec3 colorr;
out vec4 frag_color;

void main(void) {
    frag_color = vec4(colorr, 1.0);
}

+

您实际做的是创建 landmarks.size() 个缓冲区而不是 1 个缓冲区。您必须创建一个缓冲区。为了获得最佳性能增益,您必须创建一次缓冲区(分别在它仅更改时)并在着色器中进行世界转换。

使用以下数据结构来表示一个点(或类似的aggregate):

struct TLandmarkData
{
    glm::vec3 pos;
    glm::vec3 color;
};
using TLandmarks = std::vector<TLandmarkData>;

创建一个顶点数组对象和一个顶点缓冲区对象(在初始化时一次):
(另请参阅 Vertex Specification

TLandmarks landmarks;
GLuint vbo_;
GLuint vao_;
glGenBuffers(1, &vbo_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, landmarks.size()*sizeof(*landmarks.data()), landmarks.data(), GL_STATIC_DRAW);

glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(TLandmarkData), 0);
glEnableVertexAttribArray( 0 );
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(TLandmarkData), (void*)(sizeof(glm::vec3)));
glEnableVertexAttribArray(1);

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

如您所见,您不需要任何循环。如果数据发生变化,可以更新缓冲区(vbo_)(例如glBufferSubData)。

当你要绘制点时,绑定顶点数组对象即可。 countglDrawArrays 的参数必须是顶点数:

glBindVertexArray(vao_);
glDrawArrays(GL_POINTS, 0, landmarks.size());

使用 Uniform 类型 mat4,在顶点着色器中将点转换为世界坐标:

#version 460

uniform mat4 mvpMat;

layout (location = 0) in vec3 test_position;
layout (location = 1) in vec3 test_color;

layout (location=0) uniform mat4 worldtransform;

out vec3 colorr;

void main(void){
    colorr = test_color;
    gl_Position = worldtransform * vec4(test_position,1.0);
}

通过glUniformMatrix4fv after the program is installed by glUseProgram设置制服(每帧更新):

glm::mat4 toworld(1.0f);
// set toworld
// [...]

glUseProgram(myProgram);
glUniformMatrix4fv(0, 1, GL_FALSE, glm::value_ptr(toworld));