用于在大满贯中绘制特征点的opengl着色器[关闭]

Posted

技术标签:

【中文标题】用于在大满贯中绘制特征点的opengl着色器[关闭]【英文标题】:opengl shader for drawing feature point in slam [closed] 【发布时间】:2020-02-26 05:14:19 【问题描述】:

我想使用 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);

+

【问题讨论】:

【参考方案1】:

您实际上要做的是创建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)。

当你想绘制点时,绑定顶点数组对象就足够了。 glDrawArrayscount 参数必须是顶点数:

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

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

#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);

glUseProgram安装程序后,通过glUniformMatrix4fv设置统一(每帧更新):

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

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

【讨论】:

感谢您的回答。在我的算法中,地标(大小和位置)非常快速地更改和更新新数据,所以我使用 for 循环。如何实时更新和绘制点? @2255jj 您也可以更新缓冲区并在每个帧中指定 vao。 (在这种情况下,您不需要矩阵转换)。动态生成std::vector&lt;TLandmarkData&gt;; 并使用我的答案代码。注意如果点数没有变化,将vbo_的内容更改为glBufferSubData(每帧)就足够了。 更新代码但显示分段错误。什么问题?请检查。 @2255jj 你在glDrawArrays 之前错过了glBindVertexArray(vao_);。如果vao_vbo_ 只是临时的,那么你必须通过glDeleteBuffers(1, &amp;vbo_); 删除它们glDeleteVertexArrays(1, &amp;vao_); 谢谢,它可以工作,但有些问题。它绘制了未知的大红色方块,并且点的颜色全是白色。还有一个问题,我可以在同一个窗口中将 glDrawarrays 与 glbegin()~ glvertex() ~ glend() 一起使用吗?

以上是关于用于在大满贯中绘制特征点的opengl着色器[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

用于绘制视频帧的 OpenGL ES 着色器

如何使用OpenGL着色器在平面上绘制没有透视的纹理?

使用C++库GLEW在openGl中绘制一个红色三角形[关闭]

用于片段着色器的 OpenGL GLSL 绑定采样器

OpenGL:将随机位置传递给顶点着色器

OpenGL gluLookat 不适用于着色器