Zeichnen von Pixel in OpenGL
Ich bin dabei, ein Computer-Grafik-Kurs an meiner Uni. Ich brauche zu implementieren-basic-line-drawing-algorithmen, die in modernen OpenGL(3.3+) zu zeichnen primitive auf dem Bildschirm. Hier ist die Funktion für den Bresenham - Linien-Algorithmus, den ich umsetzen will -
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);
}
}
}
Ich bin ratlos, wie realisieren Sie das setPixel()
Funktion. Die meisten Antworten fand ich hier und anderswo mit älteren OpenGL-Funktionen -
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
}
Was ist das äquivalent Möglichkeit, dies zu tun in OpenGl 3.3+?
Angenommen, Sie können hinzufügen, die "Pixel" auf eine std::vector
array, wie kann ich die Initialisierung des vertex-buffer-array-Daten zu speichern?
Einem anderen problem, das ich gestoßen bin, während Sie versuchen zu zeichnen einen Punkt mit GL_POINTS
ist, dass durch clipping während der Konvertierung in normalisierten device-Koordinaten, die Punkte außerhalb des Intervalls [-1,1] in beide Richtungen zeigen nicht auf die Fenster.
Beispielsweise nur die ersten drei Punkte zeigen, bis auf die Fenster-Bildschirm. Finden Sie die initialize()
Funktion -
#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;
}
Welche änderungen muss ich machen, damit ich zeichnen können der rest der Punkte?
Vertex-Shader -
#version 150 core
in vec4 position;
void main() {
gl_Position = position;
gl_PointSize = 10.0;
}
Fragment-Shader -
#version 150 core
out vec4 out_color;
void main() {
out_color = vec4(1.0, 1.0, 1.0, 1.0);
}
Tun Sie nur haben, um Linien zu zeichnen oder benutzen Sie Bresenham-Algorithmus?
Ich habe die Verwendung des Algorithmus für die "rasterisation". Ich weiß, ich hätte
GL_LINES
sonst.Einfach speichern Sie die x und y in der Reihenfolge in ein array und verwenden Sie
glDrawArrays()
mit GL_POINTS Rendern der Linien. Als pro -1,1 erstellen Sie eine 2D-Projektion-matrix, vielleicht mit glm und senden Sie es an Ihre shader und multiplizieren Sie einfach Punkte, indem Sie es.Dies kann ein bisschen eine dumme Art und Weise, es zu tun, aber man könnte die Grenze ziehen w/ Bresenham-Algorithmus, um eine textur auf der CPU Ende und ziehen Sie dann das quad auf den Bildschirm, in der Regel. Ich kann schreiben, bis eine ausführlichere Antwort, wenn Sie interessiert sind
InformationsquelleAutor ByteMan2021 | 2016-09-10
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ab in die Kommentare, es klingt wie Sie versuchen, die OpenGL verwenden statt einem wirklich alten Grafik-Bibliothek, die benötigt wird für eine Klasse. Da computer-Grafiken haben sich so sehr verändert, dass das, was Sie zu tun versuchen, in der modernen OpenGL-unzumutbar ist, sollten Sie versuchen, dies zu tun für die aktuelle Belegung und Ihrem später:
Disclaimer: Dies ist kein angemessener Weg, um eine Linie zu zeichnen, die in modernen OpenGL
setPixel
- Funktion, die änderungen der Elemente im arrayEinige grobe psuedocode:
Dann erstellen Sie ein quad - (eigentlich nur zwei Dreiecken) , zeichnen Sie diese textur auf den Bildschirm. Nach dem öffnen.gl guide sollte gut funktionieren, da Sie bereits tun dies für Ihre Texturen. Ziehen aus Ihren bereitgestellten code (was aber ein bisschen extra, alles korrekt und nach dem spec):
Können Sie näher auf die Punkte 1. und 2.? Genauer gesagt, möchte ich wissen, wie Sie deklarieren und initialisieren Sie die
pixel
variable übergebenglTexImage2D
. Das tutorial zeigt nur, wie das laden von Texturen aus einem bereits vorhandenen Bild.Basierend auf deiner Antwort hier(stackoverflow.com/a/18369213/5306573 ): "Aber eine textur ist vielleicht nicht der effizienteste Weg, um direkt update einzelner Pixel auf dem Bildschirm. Es ist jedoch eine tolle Idee, auf den ersten draw-Pixel eines pixel-buffer, die für die Anzeige geladen wird, in eine textur, dann wird gezogen auf eine volle viewport-quad." Irgendwelche Tipps, wie dies zu tun (Zeichnung Pixel auf einen pixel-Puffer); die, die ich vermute, kann dann übergeben werden, der in einem Aufruf
glTexImage2D
?könnte so einfach sein wie
float pixels[w * h * 3];
mitsetPixel
Umsetzung so einfach wiepixels[(y * w * 3) + (x * 3)] = 1; pixels[(y * w * 3) + (x * 3) + 1] = 1; pixels[(y * w * 3) + (x * 3) + 2] = 1;
Den dreien in diesem Fall beziehen sich auf die R -, G-und B-Kanäle der textur, die ich oben beschrieben habe. Sie können immer ändern der anderen ParameterglTexImage2D
um dies zu vereinfachen, um eine Graustufen-textur.Arbeitete wie ein Charme!! Vielen Dank. Der einzige Haken ist glaube ich, dass
w
undh
werden müssen, Recht groß, so dass die oberen rechten Punkt geplottet werden können, ohne eine index out of bounds Fehler in dersetPixel
Funktion.InformationsquelleAutor Robert Rouhani