I'm trying to attach two textures of Gaussian blur to a fbo in order to subtract them in the shader (return c2-c in dog) but the first texture gives strange results. I tried to find the problem but I do not see where it is. If anyone can enlighten me I would be very grateful. Thank you in advance.
Here is the C code:
static void draw(void) {
static int b1 = 0;
static int b2 = 50;
glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
blur(_vao, b1, _tId, _fboTex[0], 1, 0);
glUseProgram(0);
blur(_vao, b2, _tId, _fboTex[0], 1, 1);
glUseProgram(0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, _dim[0], _dim[1], 0, 0, _dim[0], _dim[1], GL_COLOR_BUFFER_BIT, GL_NEAREST);
//glBlitFramebuffer(0, 0, _dim[0], _dim[1], _dim[0]/2, 0, _dim[0], _dim[1], GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void tex_to_shader(GLuint tid, char * sampler_name, GLuint num_tex){
glActiveTexture(!num_tex ? GL_TEXTURE0 : GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glUniform1i(glGetUniformLocation(blurPId, sampler_name), num_tex);
glBindTexture(GL_TEXTURE_2D, tid);
}
void blur(GLuint plate_vao, GLuint radius, GLuint in, GLuint out, GLuint nb_iterations, GLuint current_texture) {
int i, n;
GLuint temp, rin = in;
glGenTextures(1, &temp);
glBindTexture(GL_TEXTURE_2D, temp);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
radius = radius > MAX_RADIUS ? MAX_RADIUS : radius;
for(n = 0; n < (int)nb_iterations; n++) {
for(i = 0; i < 2; i++) {
glFramebufferTexture2D(GL_FRAMEBUFFER, !current_texture ? GL_COLOR_ATTACHMENT0 : GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, i == 0 ? temp : out, 0);
glUseProgram(blurPId);
glUniform1i(glGetUniformLocation(blurPId, "inv"), i ? 1 : 0);
glUniform1fv(glGetUniformLocation(blurPId, "weight"), MAX_RADIUS, &weights[(radius * (radius - 1)) >> 1]);
glUniform2fv(glGetUniformLocation(blurPId, "offset"), MAX_RADIUS, (i % 2) ? offsetH : offsetV);
glUniform1i(glGetUniformLocation(blurPId, "nweights"), radius);
glDisable(GL_DEPTH_TEST);
glBindVertexArray(plate_vao);
tex_to_shader(rin, !current_texture ? "blur0" : "blur1", current_texture);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
rin = out;
}
glDeleteTextures(1, &temp);
}
Here is our fragment shader:
#version 330
uniform sampler2D blur0;
uniform sampler2D blur1;
uniform int current_texture;
uniform int nweights;
uniform float weight[128];
uniform vec2 offset[128];
in vec2 vsoTexCoord;
out vec4 fragColor;
vec4 dog(sampler2D a, sampler2D b){
vec4 c = texture(a, vsoTexCoord.st) * weight[0];
vec4 c2 = texture(b, vsoTexCoord.st) * weight[0];
for (int i = 1; i < nweights; i++) {
c += texture(a, vsoTexCoord.st + offset[i]) * weight[i];
c += texture(a, vsoTexCoord.st - offset[i]) * weight[i];
c2 += texture(b, vsoTexCoord.st + offset[i]) * weight[i];
c2 += texture(b, vsoTexCoord.st - offset[i]) * weight[i];
}
return c;
}
vec4 gray(vec4 c){
float moyenne = 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b;
return vec4(moyenne, moyenne, moyenne, 1.0);
}
void main(void) {
fragColor = dog(blur0,blur1);
//fragColor = gray(fragColor);
}
If you use a framebuffer with multiple color attachments, then you have to specify the color attachment(s), which should be written to. The color buffer(s) in which should be drawn, can be specified by glDrawBuffers.
e.g. If only should be drawn on GL_COLOR_ATTACHMENT1 the this can be specified like this:
GLenum attachment = GL_COLOR_ATTACHMENT1;
glDrawBuffers(1, &attachment);
In your case this mans you have to choose the proper color attachment at the begin of the function blur:
void blur(GLuint plate_vao, GLuint radius, GLuint in, GLuint out,
GLuint nb_iterations, GLuint current_texture) {
GLenum attachment = !current_texture ? GL_COLOR_ATTACHMENT0 : GL_COLOR_ATTACHMENT1;
glDrawBuffers(1, &attachment);
.....
}
Related
I am trying to rotate a text in OpenGL, but however, the problem is that the text rotates like it should but in the wrong point i.e, it does not rotate at the center of the text(and by that I want to know how I could do that!).
The reason I am confused because I am using multiple texture for different letters of the text which makes me confused.
If you are wondering which library I'm using, it is CGLM
But when I compile this code the rotate function rotates the object with the wrong point of rotation.
According to Rabbid76. I did the following to get the size of the whole text:-
for (int i = 0; i < (signed)strlen(text); i++)
{
tw += iterator[(int)text[i]].Character_Array.Size[0];
th += iterator[(int)text[i]].Character_Array.Size[1];
}
Still I am not getting the proper result, the text is still misplaced.
Before any rotation(this is where IT SHOULD rotate):-
After 45 degrees rotation(it gets misplaced from its position):-
Edit: The whole code of the source file:-
// Std. Includes
#include <stdio.h>
#include <stdlib.h>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
// GLM
#include <cglm/cglm.h>
// FreeType
#include <ft2build.h>
#include FT_FREETYPE_H
// Properties
const GLuint WIDTH = 800, HEIGHT = 600;
const GLchar * vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec4 vertex;\n"
"out vec2 TexCoords;\n"
"uniform mat4 projection;\n"
"uniform mat4 model;\n"
"void main()\n"
"{\n"
"gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);\n"
"TexCoords = vertex.zw;\n"
"}\n\0";
const GLchar * fragmentShaderSource =
"#version 330 core\n"
"in vec2 TexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D text;\n"
"uniform vec4 textColor;\n"
"void main()\n"
"{\n"
"vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n"
"color = textColor * sampled;\n"
"}\n\0";
/// Holds all state information relevant to a character as loaded using FreeType
typedef struct {
GLuint TextureID; // ID handle of the glyph texture
int Size[2]; // Size of glyph
int Bearing[2]; // Offset from baseline to left/top of glyph
GLuint Advance; // Horizontal offset to advance to next glyph
} Character;
typedef struct
{
GLchar char_Array;
Character Character_Array;
} Iterator;
Iterator * iterator;
GLuint VAO, VBO;
// RenderText function.. to render our text...
void RenderText(GLuint program, const char * text, GLfloat originx, GLfloat originy, GLfloat x, GLfloat y, GLfloat scalex, GLfloat scaley, float rotation, float r, float g, float b, float a);
// The MAIN function, from here we start our application and run the Game loop
int main()
{
iterator = NULL;
// Init GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", NULL, NULL); // Windowed
glfwMakeContextCurrent(window);
// Initialize GLEW to setup the OpenGL Function pointers
glewExperimental = GL_TRUE;
glewInit();
// Define the viewport dimensions
glViewport(0, 0, WIDTH, HEIGHT);
// Set OpenGL options
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Compile and setup the shader
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertexShaderSource, NULL);
glCompileShader(vertex_shader);
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragment_shader);
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
mat4 projection;
glm_ortho(0.0f, (GLfloat)WIDTH, (GLfloat)HEIGHT, 0.0f, -1, 1, projection);
glUseProgram(program);
glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, (GLfloat *)projection);
// FreeType
FT_Library ft;
// All functions return a value different than 0 whenever an error occurred
if (FT_Init_FreeType(&ft))
printf("ERROR::FREETYPE: Could not init FreeType Library\n");
// Load font as face
FT_Face face;
if (FT_New_Face(ft, "playfair.ttf", 0, &face))
printf("ERROR::FREETYPE: Failed to load font\n");
// Set size to load glyphs as
FT_Set_Pixel_Sizes(face, 0, 72);
// Disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
int i = 0;
// Load first 128 characters of ASCII set
for (GLubyte c = 0; c < 255; c++)
{
// Load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
printf("ERROR::FREETYTPE: Failed to load Glyph\n");
continue;
}
// Generate texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
// Set texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Now store character for later use
Character character = {
texture,
{(signed)face->glyph->bitmap.width, (signed)face->glyph->bitmap.rows},
{face->glyph->bitmap_left, face->glyph->bitmap_top},
(GLuint)face->glyph->advance.x
};
iterator = (Iterator*)realloc(iterator, sizeof(Iterator) * (i + 1));
iterator[i].Character_Array = character;
iterator[i].char_Array = c;
i++;
}
glBindTexture(GL_TEXTURE_2D, 0);
// Destroy FreeType once we're finished
FT_Done_Face(face);
FT_Done_FreeType(ft);
// Configure VAO/VBO for texture quads
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glfwVulkanSupported();
// Game loop
float k = 0;
while (!glfwWindowShouldClose(window))
{
// Check and call events
glfwPollEvents();
// Clear the colorbuffer
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (k > 360)
{
k = 0;
}
k += 0.1f;
RenderText(program, "Rotation", 0, 0, 10.0f, 10.0f, 1.0f, 1.0f, k, 0.5f, 0.8f, 0.2f, 1.0f);
// Swap the buffers
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
void RenderText(GLuint program, const char * text, GLfloat originx, GLfloat originy, GLfloat x, GLfloat y, GLfloat scalex, GLfloat scaley, float rotation, float r, float g, float b, float a)
{
// Activate corresponding render state
glUseProgram(program);
glUniform4f(glGetUniformLocation(program, "textColor"), r, g, b, a);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
GLfloat tw = iterator[(int)text[i]].Character_Array.Bearing[0],
th = 0.0f;
for (int i = 0; i < (signed)strlen(text); i++)
{
Character ch = iterator[(int)text[i]].Character_Array;
tw += (ch.Advance >> 6);
th += ch.Size[1];
}
GLfloat rx = tw / 2.0f;
GLfloat ry = th / 2.0f;
mat4 model;
glm_mat4_identity(model);
glm_translate(model, (vec3) { originx, originy, 0.0f });
glm_translate(model, (vec3) { scalex * rx, scaley * ry, 0.0f });
glm_rotate(model, glm_rad(rotation), (vec3) { 0.0f, 0.0f, 1.0f });
glm_translate(model, (vec3) { -scalex * rx, -scaley * ry, 0.0f });
glm_scale(model, (vec3) { scalex, scaley, 1.0f });
GLfloat xpos = 0.0;
GLfloat ypos = 0.0;
for (int i = 0; i < (signed)strlen(text); i++)
{
Character ch = iterator[(int)text[i]].Character_Array;
mat4 ch_model;
memcpy(ch_model, model, 16 * sizeof(float));
glm_translate(ch_model, (vec3) { x, 0.0f, 0.0f });
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6); // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, (GLfloat *)ch_model);
// Render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
GLfloat w = ch.Size[0] * scalex;
GLfloat h = ch.Size[1] * scaley;
GLfloat vertices[6][4] = {
{ 0.0f, h, 0.0, 1.0 },
{ w, 0.0f, 1.0, 0.0 },
{ 0.0f, 0.0f, 0.0, 0.0 },
{ 0.0f, h, 0.0, 1.0 },
{ w, h, 1.0, 01.0 },
{ w, 0.0f, 01.0, 0.0 },
};
// Update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
glm_rotate applies rotation at origin. So if your geometry's center is not at the origin then rotation will not made around center of object/geometry.
Solution: X = T(p)Rz(φ)T(−p) where X is final transform, p is pivot
Translate pivot (or object center, not object's position, it is not same) to origin
Apply Rotation or scaling
Translate pivot back to it's original position
If you want to rotate around center of object (if object's center is not at the origin) then you must compute center of that object/geometry. Before apply any rotation. You could compute bounding box then get center of that box.
cglm also provides functions for that: glm_vec_center(min, max, pivot); /* pivot = center of object */. Now we have center point. Let's rotate around that point:
/* ... */
glm_vec_center(min, max, pivot); /* center of object */
glm_vec_inv_to(pivot, pivotInv); /* -pivot */
/* ... */
glm_translate(model, pivot);
glm_rotate(model, angle, axis);
glm_translate(model, pivotInv);
The code above do same thing as X = T(p)Rz(φ)T(−p) (translate(-pivot), rotate, translate(pivot)). The order seems reverse in code because glm_translate = Transform * Translate. It would not be reverse order if glm_translate = Translate * Transform. cglm may provide this alternative translation multiplication too in the future
EDIT: By starting v0.4.2 version cglm provides functions for this purpose: check glm_rotate_at() and glm_quat_rotate_at(), glm_rotate_atm and glm_quat_rotate_atm creates NEW rotations for pivot point since glm_rotate_at and glm_quat_rotate_at rotates existing transforms. To use these functions make sure you have latest version.
I'm new to OpenGL, and I'm trying to move an object using the mouse. I'm using OpenGL 4.4 Core Profile, MinGW32, freeGLUT, GLU, and GLEW, programming in C.
The program draw an hexagon with GL_LINE_LOOP and the color (0.5, 0.5, 0.5, 1.0).
The problem is when I move it using the mouse, the object is softly blinking, the color changes to a darker grey. The blinking also occurs when drawing with the color (1.0, 1.0, 1.0, 1.0), but it is less visible.
I tried to change the swap interval using wglSwapIntervalEXT(), but it accepts only values 0 and 1. I also tried to enable Triple Buffering and "wait for Vsync" parameter of my graphic card. Changing these three parameters doesn't solve the problem.
The code is very simple, the vertex shader takes an Uniform vector t that corresponds to the translation to apply to the object.
Vertex shader program:
#version 440 core
in vec3 vertex_position;
uniform vec3 vertex_color;
uniform vec4 t;
uniform mat4 matrix;
out vec4 color;
vec4 vp;
void main() {
color = vec4(vertex_color,1.0);
vp = matrix * vec4(vertex_position,1.0);
gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);
}
Fragment shader program:
#version 440 core
in vec4 color;
void main()
{
gl_FragColor = color;
}
The draw function is very simple, and I have a timer function that call glutPostRedisplay() every 16 ms, in order to have arround 60 FPS. I tried without the timer function, it increases the FPS, but the blinking even occurs.
The draw function:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int init = 1;
if(init == 1) {
glUseProgram(shader_program_core);
matrixloc = glGetUniformLocation(shader_program_core,"matrix");
// Load the matrix into the vertex shader:
glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
// translation localisation:
tloc = glGetUniformLocation(shader_program_core,"t");
init = 0;
}
glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);
glBindVertexArray(vao);
glDrawArrays(GL_LINE_LOOP, 0, 6);
glBindVertexArray(0);
glutSwapBuffers();
The complete source code that shows the problem is here:
#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
// coordinates of the hexagon:
GLfloat hexagon[18];
GLuint vao;
GLuint vbo;
// translations:
GLfloat tx = 0.0;
GLfloat ty = 0.0;
GLfloat tz = 0.0;
GLfloat tw = 0.0;
// window dimensions:
GLint width;
GLint height;
int window;
// coordinates of clicked point
int clicked_x;
int clicked_y;
// set to 1 if clicked down:
int clicked_down = 0;
/////////////////////////////////////////////////////////
//
// Shader programs for core profile:
//
const char * vsprog_core =
"#version 440 core\n"
"in vec3 vertex_position;\n"
"uniform vec3 vertex_color;\n"
"uniform vec4 t;\n"
"uniform mat4 matrix;\n"
" \n"
"out vec4 color;\n"
" \n"
"vec4 vp;\n"
" \n"
"void main() {\n"
" color = vec4(vertex_color,1.0);\n"
" vp = matrix * vec4(vertex_position,1.0);\n"
" gl_Position = vec4(vp.x+t.x, vp.y+t.y, vp.z+t.z, vp.w+t.w);\n"
"}\n";
const char * fsprog_core =
"#version 440 core\n"
"in vec4 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = color;\n"
"}\n";
// uniforms locations:
GLint tloc;
GLint colorloc;
GLint matrixloc;
GLuint shader_program_core;
GLfloat PMVmatrix[16] = {
0.500000, 0.000000, 0.000000, 0.000000,
0.000000, 0.500000, 0.000000, 0.000000,
0.000000, 0.000000, 0.500000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000
};
void Draw()
{
int i,j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static int init = 1;
if(init == 1) {
glUseProgram(shader_program_core);
matrixloc = glGetUniformLocation(shader_program_core,"matrix");
// Load the matrix into the vertex shader:
glUniformMatrix4fv(matrixloc, 1, GL_FALSE, PMVmatrix);
colorloc = glGetUniformLocation(shader_program_core,"vertex_color");
// translation localisation:
tloc = glGetUniformLocation(shader_program_core,"t");
init = 0;
}
glUniform3f(colorloc,0.5,0.5,0.5);
// translation:
glUniform4f(tloc,tx,ty,tz,tw);
glBindVertexArray(vao);
glDrawArrays(GL_LINE_LOOP, 0, 6);
glBindVertexArray(0);
glutSwapBuffers();
//glutPostRedisplay();
}
void onMouseClick(int button, int state, int x, int y) {
if(state == GLUT_UP && button == GLUT_LEFT_BUTTON) clicked_down = 0;
if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON) {
clicked_down = 1;
clicked_x = x;
clicked_y = y;
}
}
void onMouseMove(int x, int y) {
int i,j;
if(clicked_down == 1) {
// compute x coordinate of the clicked point from the clicked x pixel:
GLfloat x1 = (clicked_x)*2.0/width - 1.0;
// compute x coordinate of the actual point from the actual x pixel:
GLfloat x2 = (x)*2.0/width - 1.0;
// compute y coordinate of the clicked point from the clicked y pixel:
GLfloat y1 = (clicked_y)*2.0/height - 1.0;
// compute y coordinate of the actual point from the actual y pixel:
GLfloat y2 = (y)*2.0/height - 1.0;
tx += x2 - x1;
ty += y1 - y2;
// save actual coordinates as previous ones, for the next move:
clicked_x = x;
clicked_y = y;
}
}
void timer( int value )
{
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
int main( int argc, char *argv[ ], char *envp[ ] )
{
int i,j;
glutInitContextVersion(4, 4);
glutInitContextFlags(GLUT_FORWARD_COMPATIBLE/* | GLUT_DEBUG*/);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(640,480);
window = glutCreateWindow("Program");
//glutFullScreen();
width = glutGet(GLUT_WINDOW_WIDTH);
height = glutGet(GLUT_WINDOW_HEIGHT);
// get version info
const GLubyte* renderer;
const GLubyte* version;
///////////////////////////////////////////////////////////////////////
//
// start GLEW extension handler
//
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
return(-1);
}
fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
// get version info
renderer = glGetString(GL_RENDERER); // get renderer string
version = glGetString(GL_VERSION); // version as a string
printf("\nRenderer: %s", renderer);
printf("\nOpenGL version supported %s", version);
fflush(stdout);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable(GL_DEPTH_TEST); // enable depth-testing
glDepthFunc(GL_LESS); // depth-testing interprets a smaller value as "closer"
//////////////////////////////////////////////////////////
//
// Shaders:
//
GLint params;
GLint len;
GLuint vscore = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vscore, 1, &vsprog_core, NULL);
glCompileShader(vscore);
glGetShaderiv(vscore,GL_COMPILE_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetShaderInfoLog(vscore,100000,&len,log);
printf("\n\n%s\n\n",log);
return(-1);
}
GLuint fscore = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fscore, 1, &fsprog_core, NULL);
glCompileShader(fscore);
glGetShaderiv(fscore,GL_COMPILE_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetShaderInfoLog(fscore,100000,&len,log);
printf("\n\n%s\n\n",log);
return(-1);
}
shader_program_core = glCreateProgram();
glAttachShader(shader_program_core, fscore);
glAttachShader(shader_program_core, vscore);
glLinkProgram(shader_program_core);
glGetProgramiv(shader_program_core,GL_LINK_STATUS,¶ms);
if(params == GL_FALSE) {
GLchar log[100000];
glGetProgramInfoLog(shader_program_core,100000,&len,log);
printf("\n\n%s\n\n",log);
fflush(stdout);
return(-1);
}
//
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
//
// Compute coordinates of the hexagon:
//
hexagon[0] = cos(0.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[1] = sin(0.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[2] = 0.0;
hexagon[3] = cos(1.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[4] = sin(1.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[5] = 0.0;
hexagon[6] = cos(2.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[7] = sin(2.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[8] = 0.0;
hexagon[9] = cos(3.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[10] = sin(3.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[11] = 0.0;
hexagon[12] = cos(4.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[13] = sin(4.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[14] = 0.0;
hexagon[15] = cos(5.0*M_PI/3.0 + M_PI/6.0)*500.0/width;
hexagon[16] = sin(5.0*M_PI/3.0 + M_PI/6.0)*500.0/height;
hexagon[17] = 0.0;
// VAO:
glGenVertexArrays(1, &(vao));
glBindVertexArray(vao);
// VBO:
glGenBuffers(1,&(vbo));
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), hexagon, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0*sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
// End VAO:
glBindVertexArray(0);
glutMouseFunc(onMouseClick);
glutMotionFunc(onMouseMove);
glutDisplayFunc(Draw);
glutTimerFunc(0,timer,0);
glutMainLoop();
return 0;
}
The shaders are defined in two char* constants. Left-clicking and moving the mouse allow to move the object.
From your description, my (wild) guess is you have texturing enabled but you're not providing any texture information.
So, just call glDisable(GL_TEXTURE_2D); before drawing your cube.
I wrote a simple fragment shader that renders a mandelbrot set. I am doing this in c and with opengl using glsl.
#version 330 core
in vec2 fCoord; //position.x position.y which is -1 to 1 on both axis
uniform int maxIterations;
uniform sampler1D mandiTexture;
out vec4 color;
void main()
{
vec2 c, z;
c.x = fCoord.x;
c.y = fCoord.y;
int i;
z = vec2(0.0f, 0.0f);
for(i=0; i<maxIterations; i++) {
float x = (z.x * z.x - z.y * z.y) + c.x;
float y = (z.y * z.x + z.x * z.y) + c.y;
if((x * x + y * y) > 4.0) break;
z.x = x;
z.y = y;
}
vec4 tcolor;
if (i == maxIterations)
{
tcolor = vec4(0.0f, 0.0f, 0.0f, 1.0f);
}
else
{
tcolor = texture(mandiTexture, float(i) / float(maxIterations));
}
color = tcolor;
}
i've noticed playing around with the initial z value I get some different results but mostly they extend outside of my quad. With z as 0, 0 I get this result.
as you can see the left side of the set is not being rendered on the quad.
The c value is coming from the vertex shader so i assume it goes for -1 to 1 on both x and y axis and being interpolated in between.
My questions are:
1) How can I center the image on the quad? I am not really sure of
that.
2) How can I say zoom in on some in on the mandelbrot set and a
follow up, lets say I want to zoom in on a specific part of the set?
2B) Let's say I click the screen and get the position in NDC?
3) If I set my max iterations higher the set seems to get really
jaggy, is that normal behavior?
I think if I can understand how to zoom in on the set I can figure out how to zoom in on a specific part but I am unsure.
edit, making sure that my code is
main.c
int maxIterations = 70;
int iterAmount = 1;
char* vshad, *fshad;
GLuint verticesBuffer, colorBuffer, vao, texCoordBuffer, indicesBuffer;
GLuint mandiTextureID, sp;
mat4_s vm, pm, opm, tm;
GLint viewMat = -1;
GLint projMat = -1;
GLint modelMat = -1;
GLint mandiTexture = -1;
GLint maxIterLoc = -1;
void initShaders(void)
{
char* vertexShaderSource = getResource("vert.shad");
char* fragmentShaderSource = getResource("frag.shad");
vshad = readFile(vertexShaderSource);
fshad = readFile(fragmentShaderSource);
free(vertexShaderSource);
free(fragmentShaderSource);
}
int run_game()
{
current_utc_time(&start_time);
while(game_running)
{
current_utc_time(¤t_time);
double frameTime = (diff(start_time,current_time).tv_sec + diff(start_time,current_time).tv_nsec) * .00000001;
//printf("float time: %0.8f\n",frameTime);
if ( frameTime > 0.25 )
{
frameTime = 0.25;
}
current_utc_time(&start_time);
current_time = start_time;
accumulator += frameTime;
while ( accumulator >= dt )
{
accumulator -= dt;
t += dt;
//printf("fixed update dt: %0.8f\n",dt);
}
//render_state = currentState * alpha + previousState * ( 1.0 - alpha );
const double alpha = accumulator / dt;
render();
if(game_running < 1) { break; }
while (SDL_PollEvent(&event))
{
switch (event.type) {
case SDL_QUIT:
game_running = -1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
game_running = -1;
break;
}
break;
}
}
}
return -1;
}
int main(int argc, char const *argv[]) {
initShaders();
mat4_identity(&vm);
vec3_s eye = {0, 0, 0};
vec3_s center = {0, 0, -1};
vec3_s up = {0, 1, 0};
mat4_lookAt(&vm, &eye, ¢er, &up);
mat4_identity(&opm);
mat4_ortho(&opm, 0, 200, 0, 200, 1, 100);
mat4_identity(&tm);
mat4_scalex(&tm, &tm, 100, 100, 0);
mat4_translatex(&tm, &tm, 100.0f, 100.0f, -20);
SDL_Surface* mandiSurface = loadPNG(getResource("mandi.png"));
if(!mandiSurface) {
printf("IMG_Load: %s\n", IMG_GetError());
// handle error
}
GLenum Mode1 = GL_RGB;
if(4 == mandiSurface->format->BytesPerPixel)
{
Mode1 = GL_RGBA;
printf("mode change");
}
sp = getShaderProgram(vshad, fshad);
r = newRenderable2d();
glGenVertexArrays(1, &vao);
glGenBuffers(1, &verticesBuffer);
glGenBuffers(1, &colorBuffer);
glGenBuffers(1, &indicesBuffer);
glGenBuffers(1, &texCoordBuffer);
glBindVertexArray(vao); //bind vertex array buffer
glBindBuffer(GL_ARRAY_BUFFER, verticesBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(r->vertices), r->vertices, GL_STATIC_DRAW);
//bind n setup indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(r->indices), r->indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind indices
//bind n setup colors
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(r->colors), r->colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind colors
//bind n setup texture coords
glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(r->texCoords), r->texCoords, GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind texture coords
glBindVertexArray(0); //unbind vertex array buffer
//mandi 1d texture
glGenTextures(1, &mandiTextureID);
glBindTexture(GL_TEXTURE_1D, mandiTextureID);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D(GL_TEXTURE_1D, 0, Mode1, mandiSurface->w, 0, Mode1, GL_UNSIGNED_BYTE, mandiSurface->pixels);
glBindTexture(GL_TEXTURE_1D, 0);
free(mandiSurface);
while(run_game() >= 0);
free(r);
IMG_Quit();
SDL_GL_DeleteContext(maincontext);
SDL_DestroyWindow(window);
return 0;
}
void render()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glUseProgram(sp);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_1D, mandiTextureID);//mandiTexture
mandiTexture = getUniformLocation(sp, "mandiTexture");
glUniform1i(mandiTexture, 0);
glBindVertexArray(verticesBuffer);
viewMat = getUniformLocation(sp, "viewMat");
modelMat = getUniformLocation(sp, "modelMat");
projMat = getUniformLocation(sp, "projMat");
maxIterLoc = getUniformLocation(sp, "maxIterations");
glUniformMatrix4fv(viewMat, 1, GL_FALSE, vm.m);
glUniformMatrix4fv(projMat, 1, GL_FALSE, opm.m);
glUniformMatrix4fv(modelMat, 1, GL_FALSE, tm.m);
glUniform1i(maxIterLoc, maxIterations);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
SDL_GL_SwapWindow(window);
}
int init_sdl(int width, int height, char* title, double fps)
{
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
SDL_Log("sdl failed to init");
SDL_Quit();
return -1;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if(window == NULL)
{
SDL_Log("sdl failed to create window");
SDL_Quit();
return -1;
}
maincontext = SDL_GL_CreateContext(window);
if(maincontext == NULL)
{
SDL_Log("sdl failed to create opengl context");
SDL_Quit();
return -1;
}
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
SDL_GL_SetSwapInterval(1);
return 1;
}
vertex shader
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 icolor;
layout (location = 2) in vec2 vTexCoord;
uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;
out vec4 fcolor;
out vec2 fTexCoord;
out vec2 fCoord;
void main()
{
gl_Position = projMat * viewMat * modelMat * vec4(position, 1.0);
fCoord = vec2(position);
fTexCoord = vTexCoord;
fcolor = vec4(icolor, 1.0f);
}
thanks to #samgak I was able to fixed the issues that I was having and now I am adding some shots of the Mandelbrot set.
The c value is coming from the vertex shader so i assume it goes for -1 to 1 on both x and y axis and being interpolated in between.
That's correct.
1) How can I center the image on the quad? I am not really sure of that.
You just need to zoom out by a factor of 1.5 and center it on -0.5. The interesting parts of the Mandelbrot set extend from roughly -2 to 1 on the real axis and -i to i on the imaginary axis:
2) How can I say zoom in on some in on the mandelbrot set and a follow up, lets say I want to zoom in on a specific part of the set?
2B) Let's say I click the screen and get the position in NDC?
Put back the 2 uniforms that you had in your previous version:
uniform vec2 center;
uniform float scale;
Declare variables to hold these values in your C code and set them with glUniform2f and glUniform1f. To center the set the initial values should be -0.5, 0.0 for the center, and 1.5 for the scale (larger values zoom out). Then in your fragment shader, just apply them like this:
c = (fCoord * scale) + center;
To click the screen and zoom in on a particular location, turn the mouse location into a value between -1,-1 and 1,1 based on its position on the screen then apply the above equation to it to find the location you clicked on. Set that as the new center and multiply scale by a value less than 1 to zoom in a given amount.
3) If I set my max iterations higher the set seems to get really jaggy, is that normal behavior?
The screenshot you posted looks ok. It would probably look better if you implemented some kind of multi-sampling in your fragment shader (e.g. calculate several values in a loop and add them together so that each pixel is actually the average of a 2x2 or 4x4 block of pixels etc).
If you zoom in far enough eventually you will run into the limits of the precision of the floating point numbers used by the GPU.
I have some code that draws squares by passing points through a geometry shader. I construct an array which is sequences of 3 floats, bind that to the in vec3 vert attribute of my vertex shader, and everything is fine.
However, I want to add another float which the fragment shader will use to calculate color. This is in the vertex shader (to pass through) as in float val. Despite being able to find vert, glGetAttribLocation can't find val (get_program_attrib(): Atrrib val not found (-1)).
Code:
void load_model(GLuint* vao, GLuint* vbo) {
glGenVertexArrays(1, vao);
glBindVertexArray(*vao);
glGenBuffers(1, vbo);
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
float data[SQUARES_PER_AXIS_SQ * 4] = {0};
squares_count = 0;
for (int i = 0; i < SQUARES_PER_AXIS_SQ; i++) {
int x_pos = i % SQUARES_PER_AXIS;
int y_pos = i / SQUARES_PER_AXIS;
if (fabs(squares[i]) > 0.0) {
data[squares_count * 4 + 0] = x_pos / ((float)SQUARES_PER_AXIS) * 2 - 1;
data[squares_count * 4 + 1] = (SQUARES_PER_AXIS - y_pos) / ((float)SQUARES_PER_AXIS) * 2 - 1;
data[squares_count * 4 + 2] = 0.5f;
data[squares_count * 4 + 3] = (float)squares[i];
squares_count++;
}
}
DPRINT("Loaded %d squares\n", squares_count);
glBufferData(GL_ARRAY_BUFFER, squares_count * 4 * sizeof(float), data, GL_STATIC_DRAW);
glEnableVertexAttribArray(get_program_attrib(main_shader, "vert"));
glEnableVertexAttribArray(get_program_attrib(main_shader, "val"));
glVertexAttribPointer(get_program_attrib(main_shader, "vert"), 3, GL_FLOAT, GL_FALSE, 4, NULL);
glVertexAttribPointer(get_program_attrib(main_shader, "val"), 1, GL_FLOAT, GL_FALSE, 4, (float*)(3 * sizeof(float)));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
GLuint get_program_attrib(program_t* prog, GLchar* name) {
if (!name) {
DPRINT("ERROR: name == NULL\n");
return -1;
}
GLint attrib = glGetAttribLocation(prog->id, name);
if (attrib < 0)
DPRINT("Atrrib %s not found (%d)\n", name, attrib);
return attrib;
}
Vertex shader:
#version 150
in vec3 vert;
in float val;
out float value;
void main() {
gl_Position = vec4(vert, 1);
value = val;
}
Fragment shader:
#version 150
in float value;
out vec4 color;
void main() {
color = vec4(value, 0, 0, 1);
}
Geometry shader:
#version 150
layout (points) in;
layout (triangle_strip, max_vertices=4) out;
uniform float square_size;
void main() {
vec4 position = gl_in[0].gl_Position;
gl_Position = vec4(position.x, position.y, position.zw);
EmitVertex();
gl_Position = vec4(position.x, position.y + square_size, position.zw);
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y, position.zw);
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y + square_size, position.zw);
EmitVertex();
EndPrimitive();
}
Vertex shader outputs are not passed directly to the fragment shader when you have a geometry shader.
It is this that is causing all of your problems. For a vertex attribute to be active, it has to contribute to the final output of your program. Basically that means something calculated in the fragment shader has to be based off of it.
Unfortunately, that is not happening right now. You have a variable called value that is output from your vertex shader and a variable called value that is input by your fragment shader. Because the geometry shader sits inbetween the two of them, the fragment shader only looks for an output named value in the geometry shader -- no such output exists.
Naturally you might think that the solution would be to create a variable called value in the geometry shader that serves as the input and the output. However, that will not work, you would have to declare it inout value and that is invalid.
Here are the necessary corrections:
Vertex shader:
#version 150
in vec3 vert;
in float val;
out float value_vtx; // Output is fed to the Geometry Shader
void main() {
gl_Position = vec4(vert, 1);
value_vtx = val;
}
Fragment shader:
#version 150
in float value_geo; // Takes its input from the Geometry Shader
out vec4 color;
void main() {
color = vec4(value_geo, 0, 0, 1);
}
Geometry shader:
#version 150
layout (points) in;
layout (triangle_strip, max_vertices=4) out;
uniform float square_size;
in float value_vtx []; // This was output by the vertex shader
out float value_geo; // This will be the input to the fragment shader
void main() {
vec4 position = gl_in[0].gl_Position;
gl_Position = vec4(position.x, position.y, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x, position.y + square_size, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y, position.zw);
value_geo = value_vtx[0];
EmitVertex();
gl_Position = vec4(position.x + square_size, position.y + square_size, position.zw);
value_geo = value_vtx[0];
EmitVertex();
EndPrimitive();
}
You may be asking why I assigned value_geo 4 times when it is constant. That is because EmitVertex (...) causes all output variables to become undefined when it returns, so you have to set it every time.
I started playing around with OpenGL and GLUT. I would like to draw some points, but the problem is that they turn out to be squares, and I would like them to be round dots (filled circles).
This is what I do:
void onInitialization( )
{
glEnable( GL_POINT_SMOOTH );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glPointSize( 6.0 );
}
void onDisplay()
{
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glBegin( GL_POINTS );
glColor3f( 0.95f, 0.207, 0.031f );
for ( int i = 0; i < g_numPoints; ++i )
{
glVertex2f( g_points[i].X, g_points[i].Y );
}
glEnd();
glFinish();
glutSwapBuffers();
}
This is the result:
The points show up where expected, only their shape is wrong.
Unlike what was said previously, this is possible with the fixed-function pipeline, even with the GL_POINTS primitive type, as long as you have support for OpenGL 1.4 or the GL_ARB_point_sprite extension. Consult this document, or the OpenGL core specification of your choice : http://www.opengl.org/registry/specs/ARB/point_sprite.txt
GL_ARB_point_sprite converts points into "quads", i.e a polygon with the form of a plane. The exact primitive type it gets converted to is not defined by the specification, though it is not important. What is important is that GL_COORD_REPLACE auto-generates texture coordinates for the surface when enabled, so you can texture-map them with a sphere-shaped RGBA-texture.
EDIT: It seems like you (the poster) is right. Anti-aliased points get rounded with respect to their radius. (I've used OpenGL since 2003, and I didn't know this. [/shame])
So enabling GL_POINT_SMOOTH while you have a multisample-able visual/pixelformat, you get rounded points. Still, multisampling can be slow, so I'd implement both. Textured quads are cheap.
To request a visual with multisampling with XLib, use these two attributes in the list to glXChooseFBConfig():
GLX_SAMPLE_BUFFERS - its value should be True. This is an on/off toggle.
GLX_SAMPLES - the number of samples.
To request a pixelformat with Win32, use these two attributes in the list to ChoosePixelFormat() or wglChoosePixelFormatARB():
WGL_SAMPLE_BUFFERS_ARB Same as above, a toggle.
WGL_SAMPLES_ARB Same as above, the number of samples.
It seem that you can OR in the flag GLUT_MULTISAMPLE to glutInitDisplayMode to get multisampling in GLUT, but you can't request the number of sample buffers.
Here is how alpha-blended quads could be implemented using your test case.
void onInitialization( )
{
glEnable( GL_POINT_SPRITE ); // GL_POINT_SPRITE_ARB if you're
// using the functionality as an extension.
glEnable( GL_POINT_SMOOTH );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glPointSize( 6.0 );
/* assuming you have setup a 32-bit RGBA texture with a legal name */
glActiveTexture(GL_TEXTURE0);
glEnable( GL_TEXTURE_2D );
glTexEnv(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glTexEnv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBindTexture(GL_TEXTURE_2D, texture_name);
}
void onDisplay()
{
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glBegin( GL_POINTS );
glColor4f( 0.95f, 0.207, 0.031f, 1.0f );
for ( int i = 0; i < g_numPoints; ++i )
{
glVertex2f( g_points[i].X, g_points[i].Y );
}
glEnd();
glFinish();
glutSwapBuffers();
}
Image of rounded points using per-fragment alpha blending + textures:
(source: mechcore.net)
Image of rounded points by using GL_POINT_SMOOTH and multisampling:
(source: mechcore.net)
A little sample I made which shows both techniques. Requires libSDL and libGLEW to compile:
#include <iostream>
#include <exception>
#include <memory>
#include <SDL/SDL.h>
#include <cmath>
#include <GL/glew.h>
#include <GL/glu.h>
#define ENABLE_TEXTURE
#define ENABLE_MULTISAMPLE
int Width = 800;
int Height = 600;
void Draw(void);
void Init(void);
inline float maxf(float a, float b)
{
if(a < b)
return b;
return a;
}
inline float minf(float a, float b)
{
if(a > b)
return b;
return a;
}
GLuint texture_name;
int main(void)
{
try {
SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#ifdef ENABLE_MULTISAMPLE
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
#endif
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
SDL_SetVideoMode(Width, Height, 32, SDL_OPENGL);
glewInit();
Init();
SDL_Event event;
bool running = true;
while(running){
while(SDL_PollEvent(&event)){
switch(event.type)
{
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE)
running = false;
break;
case SDL_QUIT:
running = false;
break;
}
}
Draw();
SDL_GL_SwapBuffers();
}
SDL_Quit();
}
catch(std::bad_alloc& e)
{
std::cout << "Out of memory. " << e.what() << std::endl;
exit(-1);
}
catch(std::exception& e)
{
std::cout << "Runtime exception: " << e.what() << std::endl;
exit(-1);
}
catch(...)
{
std::cout << "Runtime exception of unknown type." << std::endl;
exit(-1);
}
return 0;
}
void Init(void)
{
const GLint texWidth = 256;
const GLint texHeight = 256;
const float texHalfWidth = 128.0f;
const float texHalfHeight = 128.0f;
printf("INIT: \n");
unsigned char* pData = new unsigned char[texWidth*texHeight*4];
for(int y=0; y<texHeight; ++y){
for(int x=0; x<texWidth; ++x){
int offs = (x + y*texWidth) * 4;
float xoffs = ((float)x - texHalfWidth) / texHalfWidth;
float yoffs = ((float)y - texHalfWidth) / texHalfHeight;
float alpha = 1.0f - std::sqrt(xoffs*xoffs + yoffs*yoffs);
if(alpha < 0.0f)
alpha = 0.0f;
pData[offs + 0] = 255; //r
pData[offs + 1] = 0; //g
pData[offs + 2] = 0; //b
pData[offs + 3] = 255.0f * alpha; // *
//printf("alpha: %f\n", pData[x + y*texWidth + 3]);
}
}
#ifdef ENABLE_TEXTURE
glGenTextures(1, &texture_name);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_name);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData);
glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif
glPointSize(32.0f);
glMatrixMode(GL_PROJECTION);
glOrtho(0, Width, 0, Height, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
#ifdef ENABLE_MULTISAMPLE
glEnable(GL_POINT_SMOOTH);
#endif
GLenum e;
do{
e = glGetError();
printf("%s\n",gluErrorString(e));
} while(e != GL_NO_ERROR);
delete [] pData;
}
void Draw(void)
{
const int gridWidth = 1024;
const int gridHeight = 1024;
float t1, t2;
t1 = t2 = (float)SDL_GetTicks() * 0.001f;
t1 = fmod(t1, 10.0f) / 10.0f;
t2 = fmod(t2, 4.0f) / 4.0f;
float scale = 0.5f + (-sin(t2 * 2.0 * M_PI) + 1.0f) * 1.2f;
//glColor4f(0.4f, 0.5f, 0.9f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef((Width>>1), (Height>>1), 0.0f);
glScalef(scale,scale,scale);
glRotatef(t1 * 360.0f, 0.0f, 0.0f, 1.0f);
glBegin(GL_POINTS);
for(int j=0; j<gridHeight; j+=64){
for(int i=0; i<gridWidth; i+=64){
glVertex2i(i-(gridWidth>>1),j-(gridHeight>>1));
}
}
glEnd();
}
Mads' answer provides everything you need if you go for the fixed function pipeline. However, if you have a system that does not provide the ARB_point_sprite extension or with a broken implementation (some ATI drivers), you can solve this part also with geometry shaders. The ARB_geometry_shader4
extension allows you to convert a point primitive to two triangles, which can be used as the quad created by the ARB_point_sprite extension. On OpenGL 3.2, geometry shaders are already supported in core, no extension needed. The OpenGL wiki has two examples.
Not possible with a fixed opengl function. Dots are always square :)
You have to draw your own circle (by building it up like a cake, piece by piece) or draw a GL_QUAD with a "circle" texture on.
best regards,
andre