【问题标题】:Drawing a line using individual pixels in OpenGl core在 OpenGL 核心中使用单个像素绘制一条线
【发布时间】:2017-03-05 16:47:51
【问题描述】:

我正在尝试在 OpenGL 中实现线条绘制算法。我从learnopengl 学到了使用 OpenGL 的基础知识。在画线算法中,我需要设置单个像素本身。我不明白如何在像素级别使用 OpenGL。我尝试在 opengl 中搜索实现 bresenham 的线算法,在任何地方,实现都使用了 OpenGl3.3 不支持的函数 glDrawPixels。我在 OpenGL3.3 中缺少什么吗?

【问题讨论】:

  • 如果您坚持核心配置文件,我使用 GL 添加了 2 种方法,而不是仅第二种方法。

标签: c++ algorithm line opengl-3 bresenham


【解决方案1】:

OpenGL 的重点是使用可以为您进行光栅化的硬件。如果您自己进行光栅化,只需将像素写入您自己分配的内存中,您根本不需要 OpenGL;无论如何,它不会为你做任何事情。

要显示您的图像,您可以将图像上传到纹理 (glTexImage2D/glTexSubImage2D),然后绘制一个映射到该纹理的四边形。或者使用您操作系统的窗口/UI 例程在窗口上绘制图像,这可能会更容易。

如果你真的想用 OpenGL 一个一个地绘制单个像素,你可以使用 GL_POINTS。您仍然需要创建顶点和片段着色器等,这是很多额外的工作。

【讨论】:

  • 我可以用什么来代替 OpenGL? “操作系统的窗口/UI 例程在窗口上绘制图像”,你在说什么例程?
  • 无论您使用什么框架来创建和管理您的窗口(Windows 上的 Win32 或 MFC,Linux 上的 Xlib/Gtk/Qt/等)都有用于绘制该窗口内容的例程.这些通常具有“设置像素”功能,以及“将图像数据从应用程序内存复制到窗口”功能。
【解决方案2】:

最简单的方法是使用旧式 GL api

const int sz=400;   // window resolution
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-1.0,-1.0,0.0);
glScalef(2.0/float(sz),2.0/float(sz),0.0);

glBegin(GL_POINTS);
glColor3f(1.0,1.0,1.0);
glVertex2i(x0,y0);
glVertex2i(x1,y1);
glVertex2i(x2,y2);
...
glEnd(); 

glFinish();
SwapBuffers(hdc);

但这仅适用于兼容性配置文件或旧 GL 实施。

对于新的东西,您需要创建一个点列表来渲染集合 VAO/VBOs 并使用 glDrawArrays/glDrawElementsGL_POINT 样式和粗糙你需要使用着色器。在这里查看完整的立方体示例:

为了让这两种方法的示例更简单(选择注释或取消注释 _gl_old 定义),仅使用一些随机点和非常简单的着色器(期望 400x400 窗口和 [像素] 单位的点)使用 gl_simple.h来自上一个链接:

//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "Unit1.h"
#include "gl_simple.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
// this define determines if old or new stuff is used
//#define _gl_old
//---------------------------------------------------------------------------
const int sz=400;   // window resolution
const int n=1024;   // points
const int n2=n+n;   // points*dimensions
GLint pnt[n2];      // points x,y ...
#ifndef _gl_old
GLuint pnt_vbo=-1;
GLuint pnt_vao=-1;
#endif
//---------------------------------------------------------------------------
void pnt_init()
    {
    // compute some points (your line algo should do it I use random instead)
    Randomize();
    for (int i=0;i<n2;i++) pnt[i]=Random(sz);
    // the new stuff need VBO
    #ifndef _gl_old
    // create VAO/VBO
    glGenVertexArrays(1,&pnt_vao);
    glGenBuffers(1,&pnt_vbo);
    glBindVertexArray(pnt_vao);
    // points -> VBO
    glBindBuffer(GL_ARRAY_BUFFER,pnt_vbo);
    glBufferData(GL_ARRAY_BUFFER,sizeof(pnt),pnt,GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribIPointer(0,2,GL_INT,0,0);
    // unbind VAO/VBO
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glDisableVertexAttribArray(0);
    #endif
    }
//---------------------------------------------------------------------------
void pnt_exit()
    {
    // the new stuff needs to release VBO/VAO
    #ifndef _gl_old
    glDeleteVertexArrays(1,&pnt_vao);
    glDeleteBuffers(1,&pnt_vbo);
    #endif
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);

    // Old GL 1.0 stuff
    #ifdef _gl_old
    // set view to 2D in [pixels]
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(-1.0,-1.0,0.0);
    glScalef(2.0/float(sz),2.0/float(sz),0.0);
    // render points froma list
    glBegin(GL_POINTS);
    glColor3f(1.0,1.0,1.0);
    for (int i=0;i<n2;i+=2) glVertex2iv(pnt+i);
    glEnd();
    #endif

    // New GL stuff
    #ifndef _gl_old
    glUseProgram(prog_id);
    glBindVertexArray(pnt_vao);
    glDrawArrays(GL_POINTS,0,sizeof(pnt)/sizeof(pnt[0]));
    glBindVertexArray(0);
    glUseProgram(0);
    #endif

//  glFlush();
    glFinish();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    // Init of program
    gl_init(Handle);    // init OpenGL
    pnt_init();         // init pooints and VAO/VBO
    #ifndef _gl_old
    // init shaders
    char   vertex[]="#version 330 core\r\nlayout(location=0) in ivec2 pos;\r\nvoid main(void) { vec2 p; p=vec2(pos); p-=200; p/=200.0; gl_Position=vec4(p,0.0,1.0); }";
    char fragment[]="#version 330 core\r\nout vec4 col;\r\nvoid main() { col=vec4(1.0,1.0,1.0,1.0); }";
    glsl_init(vertex,fragment);
    int hnd=FileCreate("GLSL.txt"); FileWrite(hnd,glsl_log,glsl_logs); FileClose(hnd); // just write logs into file
    #endif
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    // Exit of program
    gl_exit();
    pnt_exit();
    #ifndef _gl_old
    glsl_exit();
    #endif
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    // repaint
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
    {
    // resize
    gl_resize(ClientWidth,ClientHeight);
    }
//---------------------------------------------------------------------------

它是 OpenGL/VCL/C++,所以只需忽略 VCL(所有定义、编译指示、包括...除了 gl_simple.h_gl_old)东西并在您的平台上模拟事件(重绘、初始化/退出、调整大小)。新旧风格的区别在于,你需要在渲染之前提前计算渲染的像素,并将它们存储到表/数组中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 2014-03-24
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    相关资源
    最近更新 更多