如何在OpenGL中画线?
Posted
技术标签:
【中文标题】如何在OpenGL中画线?【英文标题】:How to draw line in OpenGL? 【发布时间】:2013-01-23 18:00:12 【问题描述】:我想在 OpenGL 中画一条线。
glBegin(GL_LINES);
glVertex2f(.25,0.25);
glVertex2f(.75,.75);
glEnd();
这段代码画了一条线,但是如果我想画一条从坐标(10,10)到坐标(20,20)的线,我该怎么办?
(.25,.25) 和 (.75, .75) 是什么意思?
【问题讨论】:
【参考方案1】:(.25, .25) 和 (.75,.75) 是直线的起点和终点。
从 (10,10) 到 (20,20) 画一条线:
glBegin(GL_LINES);
glVertex2f(10, 10);
glVertex2f(20, 20);
glEnd();
【讨论】:
已弃用 ...什么是“新黑”【参考方案2】:使用 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()
并旋转相机会产生如下结果:
Example code
注意:如果您只需要 2D 线,您只需指定 vec3 端点坐标并将 z 值设置为 0,并从 setMVP
调用中删除投影矩阵, 并将相机位置设置为 (0,0,0)。这同样适用于绘制 OpenGL2 的 2D 线,因此需要将坐标发送到 NDC 空间中的 OpenGL。
【讨论】:
"glVertex2f
中的每个点值都在 -1 和 1 之间..." — 这完全取决于当前矩阵:GL_PROJECTION
和 GL_MODELVIEW
,其中是旧版本/兼容性配置文件 OpenGL 中状态的一部分。
感谢您的澄清。我有第一部分作为答案,在我添加 OpenGL3.3+ 示例之前它得到了支持,所以我也把它留在那里,因为我想有些人在尝试学习 2D 图形时将它用作垫脚石(即没有管道),即使它在技术上不是正确的方法。【参考方案3】:
也试试这个,你可以选择color并调整线条width。
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()
【讨论】:
OpenGL2 已弃用。此外,并非所有机器都支持glLineWidth
。
当然,作为开发人员检查您的依赖关系!但我不同意你的看法。所有(2.0 2.1 3.0 3.1 3.2 3.3 4.0 4.1 4.2 4.3 4.4 4.5)opengl 版本都支持“glLineWidth”。 -> khronos.org/registry/OpenGL-Refpages/gl4/html/glLineWidth.xhtml
支持glLineWidth
函数,但iirc大多数驱动程序拒绝值!= 1。最大值/最小值取决于机器。
浮点线宽[2]; glGetFloatv(GL_LINE_WIDTH_RANGE, lineWidth);您可以检查您的驱动程序或显卡支持哪个宽度范围
不会改变我的观点。依赖glLineWidth
不是很好,因为它可能不支持1以外的任何东西。以上是关于如何在OpenGL中画线?的主要内容,如果未能解决你的问题,请参考以下文章