在OpenGL中绘制像素

时间:2016-09-10 20:41:46

标签: c++ opengl graphics

我在我的大学学习计算机图形学课程。我需要在现代OpenGL(3.3+)中实现基本的线条绘制算法,以在屏幕上绘制基元。这是我想要实现的Bresenham线绘制算法的功能 -

void bresenham(GLint xStart, GLint yStart, GLint xEnd, GLint yEnd) {
    if (!(xStart < xEnd)) {
    swap(xStart, xEnd);
    swap(yStart, yEnd); 
    }

    GLint dx = xEnd - xStart;
    GLint dy = yEnd - yStart;
    GLint p = 2 * dy - dx;

    GLint x = xStart;
    GLint y = yStart;
    setPixel(x,y);

    while (x < xEnd) {
        x += 1;
        if (p < 0)
            p += (2 * dy);
        else {
            p += (2 * (dy - dx));
            y += 1;
        setPixel(x,y);
        }
    }
}

我对如何实现setPixel()功能一无所知。我在这里和其他地方找到的大多数答案都使用较旧的OpenGL函数 -

void setPixel(int x, int y)
{
    glColor3f(0.0, 0.0, 0.0); //Set pixel to black  
    glBegin(GL_POINTS);
    glVertex2i(x, y); //Set pixel coordinates 
    glEnd();
    glFlush(); //Render pixel
}

在OpenGl 3.3+中执行此操作的等效方法是什么? 假设我可以添加&#34;像素&#34;到std::vector数组,如何初始化顶点缓冲区数组来存储这些数据?

我在尝试使用GL_POINTS绘制点时遇到的另一个问题是,由于在转换为规范化设备坐标时剪切,超出范围[-1,1]的任何一个方向上的点都不显示在窗口。

例如,只有前三个点显示在窗口屏幕上。请参阅initialize()功能 -

#include <stdio.h>
#include <stdlib.h>

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cstdlib>
#include <vector>
#include <iostream>
#include <fstream>

// Read a shader source from a file
// store the shader source in a std::vector<char>
void read_shader_src(const char* fname, std::vector<char> &buffer);

// Compile a shader
GLuint load_and_compile_shader(const char *fname, GLenum shaderType);

// Create a program from two shaders
GLuint create_program(const char *path_vert_shader, const char *path_frag_shader);

// Render scene
void display(GLuint &vao, GLFWwindow* window);

// Initialize the data to be rendered
void initialize(GLuint &vao);


//GLFW Callbacks
static void error_callback(int error, const char* description) {
    fprintf(stderr, "Error: %s\n", description);
}

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
}

int main() {
    glfwSetErrorCallback(error_callback);
    //Initialize GLFW
    if (!glfwInit()) {
        fprintf(stderr, "Failed to initialize GLFW.\n");
        return -1;
    }

    //Set GLFW window settings and create window
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    GLFWwindow* window = glfwCreateWindow(500, 500, "My window", NULL, NULL);
    if(!window) {
        fprintf(stderr, "Window or context creation failed.\n");
        return -1;
    }

    glfwSetKeyCallback(window, key_callback);
    glfwMakeContextCurrent(window);

    //Initialize GLEW
    glewExperimental = GL_TRUE;
    if(glewInit() != GLEW_OK) {
        fprintf(stderr, "Failed to initialize glew");
        glfwTerminate();
        return -1;
    }
    //Create a vertex array object
    GLuint vao;

    //Initialize the data to be rendered
    initialize(vao);

    while (!glfwWindowShouldClose(window)) {
        display(vao, window);
        glfwPollEvents();
    }
    glfwTerminate();
    return 0;
}

//Render scene
void display(GLuint &vao, GLFWwindow* window) {
    //Red background
    glClearColor(1.0f, 0.0f, 0.0f, 0.0f); 
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArray(vao);
    glDrawArrays(GL_POINTS, 0, 12);
    // Swap front and back buffers
    glfwSwapBuffers(window);
}

void initialize(GLuint &vao) {
    glEnable(GL_PROGRAM_POINT_SIZE);
    // Use a Vertex Array Object
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    //Store verex positions in an array
    GLfloat vertices[24] = {
        0.0, 0.0, // Only these
        0.5, 0.5, //three points show up
        1.0, 1.0, //on the window screen

        4.0, 4.0,
        5.0, 5.0,
        6.0, 6.0,

        7.0, 7.0,
        8.0, 8.0,
        9.0, 9.0,

        10.0, 10.0,
        11.0, 11.0,
        12.0, 12.0,
    };

    //Create a vertex buffer object to store the vertex data
    GLuint vbo;
    //Generates 1 buffer object name and stores it in vbo
    glGenBuffers(1, &vbo);
    //Bind the buffer object to the buffer binding target
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    //Creates and initializes the buffer object's data store(with data from vertices)
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    GLuint shaderProgram = create_program("/Users/.../vert.shader", "/Users/.../frag.shader"); //path to shader files

    // Get the location of the attributes that enters in the vertex shader
    GLint posAttrib = glGetAttribLocation(shaderProgram, "position");

    // Specify how the data for position can be accessed
    glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);

    //Enable the attribute
    glEnableVertexAttribArray(posAttrib);
}

// Read a shader source from a file
// store the shader source in a std::vector<char>
void read_shader_src(const char *fname, std::vector<char> &buffer) {
    std::ifstream in;
    in.open(fname, std::ios::binary);

    if(in.is_open()) {
        // Get the number of bytes stored in this file
        in.seekg(0, std::ios::end);
        size_t length = (size_t)in.tellg();

        // Go to start of the file
        in.seekg(0, std::ios::beg);

        // Read the content of the file in a buffer
        buffer.resize(length + 1);
        in.read(&buffer[0], length);
        in.close();
        // Add a valid C - string end
        buffer[length] = '\0';
    }
    else {
        std::cerr << "Unable to open " << fname << " I'm out!" << std::endl;
        exit(-1);
    }
}

//Compile a shader
GLuint load_and_compile_shader(const char* fname, GLenum shaderType) {
    //Load a shader from an external file
    std::vector<char> buffer;
    read_shader_src(fname, buffer);
    const char *src = &buffer[0];

    //Create and compile the shader
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &src, NULL);
    glCompileShader(shader);

    GLint shader_compiled;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_compiled);
    if(!shader_compiled) {
        GLchar message[1024];
        glGetShaderInfoLog(shader, 1024, NULL, message);
        std::cerr << "Shader compilation failed.";
        std::cerr << "Log: " << &message << std::endl;
        glfwTerminate();
        exit(-1);
    }
    return shader;
}

// Create a program from two shaders
GLuint create_program(const char *path_vert_shader, const char *path_frag_shader) {
    // Load and compile the vertex and fragment shaders
    GLuint vertexShader = load_and_compile_shader(path_vert_shader, GL_VERTEX_SHADER);
    GLuint fragmentShader = load_and_compile_shader(path_frag_shader, GL_FRAGMENT_SHADER);

    // Attach the above shader to a program
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);

    // Flag the shaders for deletion
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // Link and use the program
    glLinkProgram(shaderProgram);
    glUseProgram(shaderProgram);

    return shaderProgram;
}

我做了哪些修改,所以我可以绘制其余的点?

顶点着色器 -

#version 150 core

in vec4 position;

void main() {
    gl_Position = position;
    gl_PointSize = 10.0;
}

片段着色器 -

#version 150 core

out vec4 out_color;

void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
}

1 个答案:

答案 0 :(得分:3)

从评论中可以看出,您正在尝试使用OpenGL代替类所需的非常古老的图形库。由于计算机图形已经发生了很大变化,以至于你在现代OpenGL中尝试做的事情是不合理的,你应该尝试为当前的作业和后来的作业做这个:

免责声明:这不是在现代OpenGL中划线的合理方法

  1. 创建一个任意大小的二维数组,大到足以在其上绘制整行。
  2. 使用原始函数绘制线条,创建一些更改该数组中元素的setPixel函数
  3. 完成绘制线后(或执行未来任务的其他任务),从该阵列创建一个OpenGL纹理。这里有一个很好的指南:https://open.gl/textures
  4. 一些粗糙的伪代码:

    GLuint tex;
    glGenTextures(1, &tex);
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_FLOAT, pixels);
    glBindTexture(GL_TEXTURE_2D, 0);
    

    然后你会创建一个四边形(实际上只是两个三角形),将这个纹理绘制到屏幕上。在open.gl指南之后应该运行良好,因为他们已经为它们的纹理做了这个。从他们提供的代码中拉出来(这有点多余,所有正确并遵循规范):

    GLfloat vertices[] = {
    //  Position      Color             Texcoords
        -0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // Top-left
         0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // Top-right
         0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // Bottom-right
        -0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f  // Bottom-left
    };
    
    GLuint elements[] = {
        0, 1, 2,
        2, 3, 0
    };
    
    // Set up buffer objects, create shaders, initialize GL, etc.
    
    //drawing
    //bind buffers, enable attrib arrays, etc
    glBindTexture(GL_TEXTURE_2D, tex);
    
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);