如何在OpenGL中画线?

问题描述 投票:0回答:4

我想在OpenGL中画一条线。

glBegin(GL_LINES);
    glVertex2f(.25,0.25);
    glVertex2f(.75,.75);
glEnd();

这段代码画了一条线,但是如果我想从坐标(10,10)到坐标(20,20)画一条线我该怎么办?

(.25, .25) 和 (.75, .75) 是什么意思?

c++ opengl line
4个回答
46
投票

使用 OpenGL2 :

glVertex2f
中的每个点值都在-1和1之间,左下为(-1, -1),右上角为(1,1),中心为(0, 0)。

将绝对点映射到标准化空间:

  • x
    除以窗口宽度
    w
    ,即可得到 0 到 1 范围内的点。

  • 乘以 2 即可得到 0 到 2 的范围。

  • 减去 1 以获得所需的 -1 到 1 范围。

  • 重复

    y
    值和窗口高度,
    h

例如:

double x1 = 10;
double y1 = 10;
double x2 = 20;
double y2 = 20;

x1 = 2*x1 / w - 1;
y1 = 2*y1 / h - 1;

x2 = 2*x2 / w - 1;
y2 = 2*y2 / h - 1;

glBegin(GL_LINES);
    glVertex2f(x1, y1);
    glVertex2f(x2, y2);
glEnd();

使用 OpenGL3+ : 使用可编程管道来画一条线稍微复杂一些。您可以创建一个

Line
类,它将获取两个点并将它们发送到 GPU,并使用简单的着色器程序绘制它们。所有设置都可以在构造函数中完成,并且可以使用一些访问函数进行修改:

class Line {
    int shaderProgram;
    unsigned int VBO, VAO;
    vector<float> vertices;
    vec3 startPoint;
    vec3 endPoint;
    mat4 MVP;
    vec3 lineColor;
public:
    Line(vec3 start, vec3 end) {

        startPoint = start;
        endPoint = end;
        lineColor = vec3(1,1,1);
        MVP = mat4(1.0f);

        const char *vertexShaderSource = "#version 330 core\n"
            "layout (location = 0) in vec3 aPos;\n"
            "uniform mat4 MVP;\n"
            "void main()\n"
            "{\n"
            "   gl_Position = MVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
            "}\0";
        const char *fragmentShaderSource = "#version 330 core\n"
            "out vec4 FragColor;\n"
            "uniform vec3 color;\n"
            "void main()\n"
            "{\n"
            "   FragColor = vec4(color, 1.0f);\n"
            "}\n\0";

        // vertex shader
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader);
        // check for shader compile errors

        // fragment shader
        int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
        glCompileShader(fragmentShader);
        // check for shader compile errors

        // link shaders
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram, vertexShader);
        glAttachShader(shaderProgram, fragmentShader);
        glLinkProgram(shaderProgram);
        // check for linking errors

        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);

        vertices = {
             start.x, start.y, start.z,
             end.x, end.y, end.z,

        };
        
        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);
        glBindVertexArray(VAO);

        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        glEnableVertexAttribArray(0);

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

    }

    int setMVP(mat4 mvp) {
        MVP = mvp;
        return 1;
    }

    int setColor(vec3 color) {
        lineColor = color;
        return 1;
    }

    int draw() {
        glUseProgram(shaderProgram);
        glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]);
        glUniform3fv(glGetUniformLocation(shaderProgram, "color"), 1, &lineColor[0]);

        glBindVertexArray(VAO);
        glDrawArrays(GL_LINES, 0, 2);
        return 1;
    }

    ~Line() {

        glDeleteVertexArrays(1, &VAO);
        glDeleteBuffers(1, &VBO);
        glDeleteProgram(shaderProgram);
    }
};

使用

Line line(vec3 ..., vec3 ...)
初始化一些 3D 线,设置模型-视图-投影矩阵
line.setMVP(projection * view * model)
line.draw()
并旋转相机将产生如下所示的结果:

xyz axis

示例代码

注意: 如果您只需要 2D 线,则只需指定 vec3 终点坐标并将 z 值设置为 0,并从

setMVP
调用中删除投影矩阵,并将相机位置设置为 ( 0,0,0)。这同样适用于绘制 2D 线条,如上面针对 OpenGL2 所解释的那样,因此需要将坐标发送到 NDC 空间中的 OpenGL。


32
投票

(.25, .25) 和 (.75,.75) 是线的起点和终点。

从 (10,10) 到 (20,20) 画一条线:

glBegin(GL_LINES);
    glVertex2f(10, 10);
    glVertex2f(20, 20);
glEnd();

1
投票

也试试这个,你可以选择颜色并调整线条宽度

def drawline(self, x1, y1, z1, x2, y2, z2, r=0, g=0, b=0, w=2):

    glLineWidth(w)
    glBegin(GL_LINES)
    glColor3fv((r/255, g/255, b/255))
    glVertex3fv((x1, y1, z1))
    glVertex3fv((x2, y2, z2))
    glEnd()

0
投票

在现代 OpenGL 中绘制线条的一种方法是批处理。由于线只有 2 个点,因此我们可以将顶点数据存储在列表中。

这里是使用 glm 在 C++ 中绘制 3D 线条的实现。它也应该很容易适应二维线。我还添加了一些简单的着色器。

std::vector<float> lineData{};

// queue line for draw
void draw_line(const glm::vec3 &p1, const glm::vec3 &p2, const glm::vec3 &color)
{
  // point 1
  lineData.push_back(p1.x);
  lineData.push_back(p1.y);
  lineData.push_back(p1.z);

  // color
  lineData.push_back(color.r);
  lineData.push_back(color.g);
  lineData.push_back(color.b);

  // point 2
  lineData.push_back(p2.x);
  lineData.push_back(p2.y);
  lineData.push_back(p2.z);

  // color
  lineData.push_back(color.r);
  lineData.push_back(color.g);
  lineData.push_back(color.b);
}
void draw_lines_flush()
{
  static unsigned int vao, vbo;

  static bool created = false;
  if (!created)
  {
    created = true;

    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, lineData.size() * sizeof(float),
                 lineData.data(), GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
                          (void *)0);

    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
                          (void *)(3 * sizeof(float)));
  }
  else
  {
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, lineData.size() * sizeof(float),
                 lineData.data(), GL_DYNAMIC_DRAW);
  }

  // 1/2 of the floats in lineData is vertex data. There are 3 floats per
  // vertex. Thus number of vertices to draw is lineData.size() / 2 / 3
  int count = lineData.size() / 6;

  glBindVertexArray(vao);
  glDrawArrays(GL_LINES, 0, count);

  lineData.clear();
}

线.垂直

#version 330 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;

out flat vec3 Color;

uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * vec4(aPos, 1.0);
    Color = aColor;
}

线.frag

#version 330 core

out vec4 FragColor;
in flat vec3 Color;

void main()
{
    FragColor = vec4(Color, 1.0);
}

在渲染循环中,您可以根据需要调用

draw_line()
。要绘制所有批处理线,请调用
draw_lines_flush()
。它有效地绘制了一个包含线条的动态创建的大型网格。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.