How to force openGL to draw a non-convex filled polygon - c

It seems to be the standart that polygon are drawn in a convex shape. See stackoverflow.com/questions/15556929/open-gl-polygon However it is not for me if I choose it to be filled. How can I have my polygon filled while maintaining the shape I defined?
void drawFloor(){
// White
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // GL_LINE works the way I want it too
//glDisable(GL_POLYGON_SMOOTH); // has no effect :(
glBegin(GL_POLYGON);
glColor3f(1.0, 1.0, 1.0);
glVertex3f(0, 0, 0); //0
glVertex3f(2*boxSize, 0, 0); //1
glVertex3f(2 * boxSize, -boxSize, 0); //2
glVertex3f(5 * boxSize, -boxSize, 0); //3
glVertex3f(5 * boxSize, 4 * boxSize, 0); //4
glVertex3f(6 * boxSize, 4 * boxSize, 0); //5
glVertex3f(6 * boxSize, 6 * boxSize, 0); //6
glVertex3f(0 * boxSize, 6 * boxSize, 0); //7
glVertex3f(0 * boxSize, 2 * boxSize, 0); //8
glVertex3f(1 * boxSize, 2 * boxSize, 0); //9
glVertex3f(1 * boxSize, 4 * boxSize, 0); //10
glVertex3f(2 * boxSize, 4 * boxSize, 0); //11
glVertex3f(2 * boxSize, 3 * boxSize, 0); //12
glVertex3f(3 * boxSize, 3 * boxSize, 0); //13
glVertex3f(3 * boxSize, 2 * boxSize, 0); //14
glVertex3f(2 * boxSize, 2 * boxSize, 0); //15
glVertex3f(2 * boxSize, 1 * boxSize, 0); //16
glVertex3f(0, 1 * boxSize, 0); //17
glEnd();
}
This code results in:
http://postimg.org/image/o4wt9ij33/ with GL_LINE
http://postimg.org/image/l31fltgkf/ with GL_FILL
I want only the inside of the polygon filled, keeping the shape of the version with the GL_LINE. I did not expect the output of GL_FILL to be so different.
What I want (created with MS paint):
http:// postimg.org/image/d3gbf613d/
I am using Win7+ Visula studio express2013+ Renderer Intel HD Graphics Version: 3.1.0 - Bulid 8.15.10.2509+ GLSL Version 1.40

Note: This answer shares content with my recent answer to a similar question here: Black out everything outside a polygon. I did not nominate the questions as duplicates because they sound different, and could potentially have different answers, even though this one happens to be mostly the same.
One approach for drawing non-convex polygons is to break them down into triangles. There are a number of algorithms that can do this, which can be found by searching for keywords like "polygon triangulation".
OpenGL has another mechanism that works great for this: stencil buffers. An explanation of this approach is in the Red Book under Drawing Filled, Concave Polygons Using the Stencil Buffer. The main idea is that one can draw a triangle fan with an arbitrary origin and your polygon vertices. The pixels that are inside the polygon will then be drawn an odd number of times, while the pixels outside the polygons are drawn an even number of times. The stencil buffer is used to track the odd/even count.
To outline the main steps:
While setting up the context and drawing surface, make sure that a configuration with a stencil buffer is requested.
During drawing, clear the stencil buffer along with the color buffer, and enable the stencil test.
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glEnable(GL_STENCIL_TEST);
Set up state for the render pass that counts if pixels are rendered an odd/even number of times. Note that this must only write to the stencil buffer, so color writes are disabled. The key part is the GL_INVERT for the stencil op, which flips the stencil value each time a pixel is rendered, which ends up storing the odd/even count in the stencil buffer.
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilFunc(GL_ALWAYS, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
glStencilMask(1);
Render a triangle fan with an arbitrary point, e.g. (0.0, 0.0), as the first vertex, and the polygon corners as the remaining vertices. The polygon must be closed, so the first and last polygon corner must be the same. If p1, p2, ... , pN are the polygon corners, the sequence of vertices for the GL_TRIANGLE_FAN draw call is:
(0.0f, 0.0f), p1, p2, ... , pN, p1
A trivial shader can be used for this pass since the color value is not even written.
Enable color writes again, and set up the stencil test attributes to render only pixels that were rendered an odd number of times in the previous pass.
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
Draw geometry that covers the entire area of the polygon, and possibly more. This can for example be the triangle fan from step 4, or a bounding box of the polygon. Only the part within the polygon outline will be rendered, the rest is eliminated by the stencil test.

Related

Object rendering strangely after adding transformations

I'm adding transformations to my C OpenGL program. I'm using CGLM as my maths library. The program has no warnings or errors. Still however, when I compile and run the program, I get a distorted version of my intended image (it was not distorted before adding transformations).
The following is my program's main loop:
// Initialize variables for framerate counting
double lastTime = glfwGetTime();
int frameCount = 0;
// Program loop
while (!glfwWindowShouldClose(window)) {
// Calculate framerate
double thisTime = glfwGetTime();
frameCount++;
// If a second has passed.
if (thisTime - lastTime >= 1.0) {
printf("%i FPS\n", frameCount);
frameCount = 0;
lastTime = thisTime;
}
processInput(window);
// Clear the window
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Bind textures on texture units
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
// Create transformations
mat4 transform = {{1.0f}};
glm_mat4_identity(transform);
glm_translate(transform, (vec3){0.5f, -0.5f, 0.0f});
glm_rotate(transform, (float)glfwGetTime(), (vec3){0.0f, 0.0f, 1.0f});
// Get matrix's uniform location and set matrix
shaderUse(myShaderPtr);
GLint transformLoc = glGetUniformLocation(myShaderPtr->shaderID, "transform");
// mat4 transform;
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, (float*)transform);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window); // Swap the front and back buffers
glfwPollEvents(); // Check for events (mouse movement, mouse click, keyboard press, keyboard release etc.)
}
The Program is up on github here if you'd like to check out the full code.
The Output of the program is this (The square also rotates):
However, the intended output of the program is the penguin at 20% opacity on top and the box at 100% opacity underneath the penguin.
In the vertex shader, the location of the texture coordinate is 1:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
However, when you specify the vertices, location 1 is used for the color attribute and position 2 for the text coordinates:
// Colour attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// Texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
Remove the color attribute and use location 1 for the texture coordinates. e.g.:
// Texture coord attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(1);
Looking at your source code, you're passing in three attributes (position, color and texture coordinates), but your vertex shader only takes two.
Removing the color attribute and instead passing the texture coordinates as attribute #1 instead of #2 should make it look like intended.

OpenGL: Wrapping texture around cylinder

I am trying to add textures to a cylinder to draw a stone well. I'm starting with a cylinder and then mapping a stone texture I found here but am getting some weird results. Here is the function I am using:
void draw_well(double x, double y, double z,
double dx, double dy, double dz,
double th)
{
// Set specular color to white
float white[] = {1,1,1,1};
float black[] = {0,0,0,1};
glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,shinyvec);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,white);
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,black);
glPushMatrix();
// Offset
glTranslated(x,y,z);
glRotated(th,0,1,0);
glScaled(dx,dy,dz);
// Enable textures
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
glBindTexture(GL_TEXTURE_2D,texture[0]); // Stone texture
glBegin(GL_QUAD_STRIP);
for (int i = 0; i <= 359; i++)
{
glNormal3d(Cos(i), 1, Sin(i));
glTexCoord2f(0,0); glVertex3f(Cos(i), -1, Sin(i));
glTexCoord2f(0,1); glVertex3f(Cos(i), 1, Sin(i));
glTexCoord2f(1,1); glVertex3f(Cos(i + 1), 1, Sin(i + 1));
glTexCoord2f(1,0); glVertex3f(Cos(i + 1), -1, Sin(i + 1));
}
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
// Later down in the display function
draw_well(0, 0, 0, 1, 1, 1, 0);
and the output I receive is
I'm still pretty new to OpenGL and more specifically textures so my understanding is pretty limited. My thought process here is that I would map the texture to each QUAD used to make the cylinder, but clearly I am doing something wrong. Any explanation on what is causing this weird output and how to fix it would be greatly appreciated.
There are possibly three main issues with your draw routine. quad-strip indexing, texture coordinates repeating too often and possible incorrect usage of the trig functions;
Trigonometric functions usually accept values which represent angles expressed in radians and not degrees. Double check what the parameters of the Sin and Cos functions you are using.
Quadstrip indexing is incorrect. Indexing should go like this...
Notice how the quad is defined in a clock-wise fashion, however the diagonal vertices are defined sequentially. You are defining the quad as v0, v1, v3, v2 instead of v0, v1, v2, v3 so swap the last two vertices of the four. This also leads to another error in not sharing the vertices correctly. You are duplicating them along each vertical edge since you draw the same set of vertices (i+1) in one loop, as you do in the next (i.e since i has now been incremented by 1).
Texture coordinates are in the range from 0, 1 for each quad which means you are defining a cylinder which is segmented 360 times and this texture is repeated 360 times around the cylinder. I'm assuming the texture should be mapped 1:1 to the Cylinder and not repeated?
Here is some example code using what you provided. I have reduced the number of segments down to 64, if you wish to still have 360 then ammend numberOfSegments accordingly.
float pi = 3.141592654f;
unsigned int numberOfSegments = 64;
float angleIncrement = (2.0f * pi) / static_cast<float>(numberOfSegments);
float textureCoordinateIncrement = 1.0f / static_cast<float>(numberOfSegments);
glBegin(GL_QUAD_STRIP);
for (unsigned int i = 0; i <= numberOfSegments; ++i)
{
float c = cos(angleIncrement * i);
float s = sin(angleIncrement * i);
glTexCoord2f( textureCoordinateIncrement * i, 0); glVertex3f( c, -1.0f, s);
glTexCoord2f( textureCoordinateIncrement * i, 1.0f); glVertex3f( c, 1.0f, s);
}
glEnd();
N.BYou are using an old version of OpenGL (the use of glBegin/glVertex etc).

Texture do not rotate with OpenGL (C)

I am trying to rotate a texture extracted from a video frame (provided by ffmpeg), I have tried the following code :
glTexSubImage2D(GL_TEXTURE_2D,
0,
0,
0,
textureWidth,
textureHeight,
GL_RGBA,
GL_UNSIGNED_BYTE,
//s_pixels);
pFrameConverted->data[0]);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5,0.5,0.0);
glRotatef(90,0.0,0.0,1.0);
glTranslatef(-0.5,-0.5,0.0);
glMatrixMode(GL_MODELVIEW);
//glDrawTexiOES(-dPaddingX, -dPaddingY, 0, drawWidth + 2 * dPaddingX, drawHeight + 2 * dPaddingY);
glDrawTexiOES(0, 0, 0, drawWidth, drawHeight);
The image is not rotated, do you see the problem ?
From the GL_OES_draw_texture extension specification:
Note also that s, t, r, and q are computed for each fragment as part of DrawTex rendering. This implies that the texture matrix is ignored and has no effect on the rendered result.
You are trying to transform the texture coordinates using the fixed-function texture matrix, but like point sprites, those coordinates are generated per-fragment rather than per-vertex. Thus, that means that nothing you do to the texture matrix is ever going to affect the output of glDrawTexiOES (...).
Consider using a textured quad instead, those will pass through the traditional vertex processing pipeline.

Why is the third vertex of my first triangle always at the origin and the rest of my triangles not being drawn?

I've checked the results of everything and I've tidied up multiple bugs in my draw function already, but I still can't find the reason for the behavior described in the question title. I'm using OpenGL 1.4, 3D textures, vertex arrays, texture coordinate arrays, and glDrawArrays to draw models (from my model API) with textures (from my texture API) to the screen. Through looking at the results of everything (printfs), I've concluded the problem has to be in the block of code that actually draws everything, and not my code that fills these arrays with post animating vertex data (so I'm only posting the former to save on bloating this post).
The current color is used to achieve a per current window brightness effect. The variable msindex is already set to the number of model draw specifications before the loop featured begins. Vertex data and texture coordinate data for every model being drawn are actually all stuffed into one segment, and as you can see below there are glVertexPointer and glTexCoordPointer calls on different parts of the start of it to register this data. The contents of this segment are tightly packed, with three floats for the position of a vertex first and then three floats following for its texture coordinates. There is multitexturing (up to two textures specified much earlier in the model), but both textures share the same texture coordinates (which is why both calls to glTexCoordPointer specify the same location in memory). The while loop is meant to draw each individual specified model according to information for the model draw specification in the miaptr segment. Start is, in my code, the starting 6 float wide index into the overall vertex data segment for the first vertex of the model to be drawn, and count is the number of vertices. In my example case these are just 0 for start and 6 for count (attempted to draw one model with two triangles). Type can be multiple things depending on the model, but in this case it is GL_TRIANGLES. I've tried this with other primitive types, but they all suffer from the same problem. Additionally, the texture being drawn is entirely opaque (and green), the brightness of the target window is always 1, and all the primitives are front facing.
The following is my broken source code:
/* Enable/set global things. */
jgl.Viewport(
(GLint) x, (GLint) y, (GLsizei) width, (GLsizei) height
);
fvals[0] = (jWindowsptr + jGetCurrentWindow())->brightness;
jgl.Color4f(
(GLfloat) fvals[0],
(GLfloat) fvals[0],
(GLfloat) fvals[0],
1
);
jgl.Enable(GL_ALPHA_TEST);
jgl.Enable(GL_CULL_FACE);
jgl.CullFace(GL_BACK);
jgl.Enable(GL_DEPTH_TEST);
jgl.Enable(GL_POINT_SPRITE_ARB);
jgl.EnableClientState(GL_VERTEX_ARRAY);
const GLvoid *vaptrc = vaptr;
jgl.VertexPointer(3, GL_FLOAT, 12, vaptrc);
/* Color clearing is in here so I could see better while testing. */
jgl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* Enable/set per texture unit things. */
jgl.ActiveTexture(GL_TEXTURE0 + 1);
jgl.TexEnvi(
GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE
);
jgl.ClientActiveTexture(GL_TEXTURE0 + 1);
jgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
jgl.TexCoordPointer(3, GL_FLOAT, 12, (vaptrc + 3));
jgl.Enable(GL_TEXTURE_3D);
jgl.ActiveTexture(GL_TEXTURE0);
jgl.TexEnvi(
GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE
);
jgl.ClientActiveTexture(GL_TEXTURE0);
jgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
jgl.TexCoordPointer(3, GL_FLOAT, 12, (vaptrc + 3));
jgl.Enable(GL_TEXTURE_3D);
/* Pass #1. */
jgl.MatrixMode(GL_TEXTURE);
jgl.DepthFunc(GL_LESS);
jgl.AlphaFunc(GL_EQUAL, 1);
const GLfloat *tctm;
while (msindex > 0) {
msindex = msindex - 1;
jgl.ActiveTexture(GL_TEXTURE0);
jgl.BindTexture(
GL_TEXTURE_3D, (miaptr + msindex)->textureids[0]
);
if ((miaptr + msindex)->textureids[0] != 0) {
tctm
= (miaptr
+ msindex)->transformationmatrices[0];
jgl.LoadMatrixf(tctm);
}
jgl.ActiveTexture(GL_TEXTURE0 + 1);
jgl.BindTexture(
GL_TEXTURE_3D, (miaptr + msindex)->textureids[1]
);
if ((miaptr + msindex)->textureids[1] != 0) {
tctm
= (miaptr
+ msindex)->transformationmatrices[1];
jgl.LoadMatrixf(tctm);
}
jgl.DrawArrays(
(miaptr + msindex)->type,
(GLint) (miaptr + msindex)->start,
(GLsizei) (miaptr + msindex)->count
);
}
/* WIP */
/* Disable per texture unit things. */
jgl.ActiveTexture(GL_TEXTURE0 + 1);
jgl.ClientActiveTexture(GL_TEXTURE0 + 1);
jgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
jgl.Disable(GL_TEXTURE_3D);
jgl.ActiveTexture(GL_TEXTURE0);
jgl.ClientActiveTexture(GL_TEXTURE0);
jgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
jgl.Disable(GL_TEXTURE_3D);
/* WIP */
/* Disable global things. */
jgl.DisableClientState(GL_VERTEX_ARRAY);
jgl.Disable(GL_POINT_SPRITE_ARB);
jgl.Disable(GL_DEPTH_TEST);
jgl.Disable(GL_CULL_FACE);
jgl.Disable(GL_ALPHA_TEST);
Your description says that you have interleaved vertex attributes, with 3 floats for the position and 3 floats for the texture coordinates per vertex. This also matches the code you posted.
The values you pass as stride to the glVertexPointer() and glTexCoordPointer() does not match this, though. With 6 floats (3 for position + 3 for texture coordinate) per vertex, and a float being 4 bytes large, the stride should be 6 * 4 = 24. So all these calls need to use 24 for the stride:
jgl.VertexPointer(3, GL_FLOAT, 24, vaptrc);
jgl.TexCoordPointer(3, GL_FLOAT, 24, ...);

How do I fill the screen with a rectangle in OpenGL ortho mode?

I have a single 640x480 texture that needs to fill the screen. So far, I can make it work with a square texture, but not a rectangular one.
glViewport(0, 0, display->w, display->h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double aspectRatio = (double)display->w / (double)display->h;
if (display->w <= display->h)
glOrtho(-1, 1, -1 / aspectRatio, 1 / aspectRatio, -1, 1);
else
glOrtho(-1 * aspectRatio, 1 * aspectRatio, -1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
What modifications do I need to make so that it will fit any texture to the screen, regardless of its aspect ratio?
This may have some relevance.
Tiling texture bmp file as texture onto a rectangle in OpenGL?
You may wish to consider ARB extension texture rectangle as an alternative approach to (assuming glTexImage2D?) http://glprogramming.com/red/chapter09.html

Resources