I was trying to draw pixel perfect bitmaps using quads in OpenGL... and to my surprise, a very important row of pixels was missing: (green is ok, red is bad)
The sizes of the quads were 30x30 px, with the red 2x2 in the top left corner.
Can someone explain what is happening?
How does OpenGL decide where to put pixels?
Which correction should I choose?
The texture uses GL_NEAREST.
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
I don't use glViewport and glOrtho. Instead, I send the screen dimensions through uniforms to the shaders:
uniform float cw;
uniform float ch;
...
gl_Position = vec4( -1.0f + 2.0f*(in_pos.x + in_offset.x)/cw,
1.0f - 2.0f*(in_pos.y + in_offset.y)/ch,
0.0f, 1.0f);
But that doesn't seem to be the source of the problem because when I add (0.5,0.5) in the shader (equivalent to the 3rd case), the problem goes away...
Ok, now I realize that the third option doesn't work either:
Check that you've passed correct screen size into shader.
When you create window, you define its outer size, but the client area, where the rendering context is put, can be smaller when window has header/decorations.
So you should either ask the client area size with GetClientRect(), or find the "correct" window size by calling AdjustWindowRect() before creating window - this would give you the window size that will have client area of the size you wanted initially.
Related
I have a torus rendered by OpenGL and can map a texture; there is no problem as long as the texture is opaque. But it doesn't work when I make the color selectively transparent in fragment shader. Or rather: it works but only in some areas depending on the order of triangles in vertex buffer; see the difference along the outer equator.
The torus should be evenly covered by spots.
The source image will be png, however for now I work with bmp as it is easier to load (the texture loading function is part of a tutorial).
The image has white background and spots of different colors on top of it; it is not transparent.
The desired result is nearly transparent torus with spots. Both spots in the front and the back side must be visible.
The rendering will be done offline, so I don't require speed; I just need to generate image of torus from an image of its surface.
So far my code looks like this (it is a merge of two examples):
https://gist.github.com/juriad/ba66f7184d12c5a29e84
Fragment shader is:
#version 330 core
// Interpolated values from the vertex shaders
in vec2 UV;
// Ouput data
out vec4 color;
// Values that stay constant for the whole mesh.
uniform sampler2D myTextureSampler;
void main(){
// Output color = color of the texture at the specified UV
color.rgb = texture2D( myTextureSampler, UV ).rgb;
if (color.r == 1 && color.g == 1 && color.b == 1) {
color.a = 0.2;
} else {
color.a = 1;
}
}
I know that the issue is related to order.
What I could do (but don't know what will work):
Add transparency to the input image (and find a code which loads such image).
Do something in vertex shader (see Fully transparent OpenGL model).
Sorting would solve my problem, but if I get it correctly, I have to implement it myself. I would have to find a center of each triangle (easy), project it with my matrix and compare z values.
Change somehow blending and depth handling:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.0f, 1.0f);
I need an advice, how to continue.
Update, this nearly fixes the issue:
glDisable(GL_DEPTH_TEST);
//glDepthMask(GL_TRUE);
glDepthFunc(GL_NEVER);
//glDepthRange(0.0f, 1.0f);
I wanted to write that it doesn't distinguish sports in front and the back, but then I realized they are nearly white and blending with white doesn't make difference.
The new image of torus with colorized texture is:
The remaining problems are:
red spots are blue - it is related to the function loading BMP (doesn't matter)
as in the input images all the spots are of the same size, the bigger spots should be on the top and therefore saturated and not blended with white body of the torus. It seems that the order is opposite than it should be. If you compare it to the previous image, there the big spots by appearance were drawn correctly and the small ones were hidden (the back side of the torus).
How to fix the latter one?
First problem was solved by disabling depth-test (see update in the question).
Second problem was solved by manual sorting of array of all triangles. It works well even in real-time for 20000 triangles, which is more than sufficient for my purpose
The resulting source code: https://gist.github.com/juriad/80b522c856dbd00d529c
It is based on and uses includes from OpenGL tutorial: http://www.opengl-tutorial.org/download/.
I have texture already rendered and I'm mapping a quad/rectangle on it. (Quad may be smaller or equal to total texture size)
Once the Quad is mapped, I want to remove the rest (what ever is drawn outside quad).
So far i can map quad and get my sub texture(not to be removed) however I'm unable to delete the remaining region(outside quad).
Following Images show the procedure;
1.Original Image
2.Original Image with quad in red color
3.Everything removed except quad. Texture after Cropping
I don't know how you compute your texture coordinates in your code but there is not millions way to do it, so I'll give a solution for the three easiest way I have in mind :
You only have a vertex array containing the positions of your vertice for your quad, and use them to compute your texture coordinates. In that case, just modify the position of your vertice to your crop area before drawing.
You have a vertex array containing both the positions and texture coordinates (or two vertex arrays, one for each). You must change the area covered in both. For your specific use case I would advise to compute the texture coordinates from the vertice positions in the vetex shader for simplicity and efficiency.
You send your cropping area as a uniform to your fragment shader. This solution assumes you work in ortho space at the picture will always fill the screen. In that case, from the input vector position, you know where you are. With a simple if condition, you can check if you are out of boundaries. If so, set the pixel to black or use discard to cancel the drawing of the pixel. Conditions are time consuming so I would only advise this solution is you wish to set the cropped pixels to black. If you prefer to have them not displayed at all, the solution 1 is the fastest.
I have solved it using Nehe's Lesson 3. I used
glColor3f(0.0f,0.0f,0.0f); // Set The Color To Black
glBegin(GL_QUADS); // Start Drawing Quads
glVertex3f(-1.0f, 1.0f, 0.0f); // Left And Up 1 Unit (Top Left)
glVertex3f( 1.0f, 1.0f, 0.0f); // Right And Up 1 Unit (Top Right)
glVertex3f( 1.0f,-1.0f, 0.0f); // Right And Down One Unit(Bottom Right)
glVertex3f(-1.0f,-1.0f, 0.0f); // Left And Down One Unit (Bottom Left)
glEnd(); // Done Drawing A Quad`
to draw 4 quads of black color, to crop the region outside my selected region.
Thanks to Nehe.
How can i set the texture coordinate offset and multiplier for the gluCylinder() and gluDisk() etc. functions?
So if normally the texture would start at point 0, i would like to set it start at point 0.6 or 3.2 etc. by multiplier i mean the texture would either get bigger or smaller.
The solution cant be glScalef() because 1) im using normals, 2) i want to adjust the texture start position as well.
Try using the texture matrix stack:
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.6f, 3.2f, 0.0f);
glScalef(2.0f, 2.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
drawObject();
The solution has nothing to do with the GLU functions and is indeed glScalef (and glTranslatef for the offset adjustment), but applying it to the texture matrix (assuming you don't use shaders). The texture matrix, selected by calling glMatrixMode with GL_TEXTURE, transforms the vertices' texture coordinates before they are interpolated and used to access the texture (no matter how these texture coordinates are computed, in this case by GLU, which just computes them on the CPU and calls glTexCoord2f).
So to let the texture start at (0.1,0.2) (in texture space, of course) and make it 2 times as large, you just call:
glMatrixMode(GL_TEXTURE);
glTranslatef(0.1f, 0.2f, 0.0f);
glScalef(0.5f, 0.5f, 1.0f);
before calling gluCylinder. But be sure to revert these changes afterwards (probably wrapping it between glPush/PopMatrix).
But if you want to change the texture coordinates based on the world space coordinates, this might involve some more computation. And of course you can also use a vertex shader to have complete control over the texture coordinate generation.
im rendering png's on simple squares in opengl es 2.0, but when i try and draw something behind an square i have already drawn the transparent area in my top square are rendered the same color as the background.
I am calling these at the start of every render call.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable (GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Your title is essentially the answer to your question!
Generally transparency is done by first rendering all opaque objects in the scene (letting the z-buffer figure out what's visible), then rendering all transparent objects from back to front.
Drew Hall gave you a good answer but another option is to set glEnable(GL_ALPHA_TEST) with glAlphaFunc(GL_GREATER, 0.1f). This will prevent transparent pixels (in this case, ones with alpha < 0.1f) from being rendered at all. That way they do not write into the Z buffer and other things can "show through". However, this only works on fully transparent objects. It also has rough edges wherever the 0.1 alpha edge is and this can look bad for distant features where the pixels are large compared to the object.
Figured it out. You can discard in the fragment shader
mediump vec4 basecolor = texture2D(sTexture, TexCoord);
if (basecolor.a == 0.0){
discard;
}
gl_FragColor = basecolor;
I'm using python but OpenGL is pretty much done exactly the same way as in any other language.
The problem is that when I try to render a texture or a line to a texture by means of a frame buffer object, it is rendered upside down, too small in the bottom left corner. Very weird. I have these pictures to demonstrate:
This is how it looks,
www.godofgod.co.uk/my_files/Incorrect_operation.png
This is how it did look when I was using pygame instead. Pygame is too slow, I've learnt. My game would be unplayable without OpenGL's speed. Ignore the curved corners. I haven't implemented those in OpenGL yet. I need to solve this issue first.
www.godofgod.co.uk/my_files/Correct_operation.png
I'm not using depth.
What could cause this erratic behaviour. Here's the code (The functions are indented in the actual code. It does show right), you may find useful,
def texture_to_texture(target,surface,offset): #Target is an object of a class which contains texture data. This texture should be the target. Surface is the same but is the texture which should be drawn onto the target. offset is the offset where the surface texture will be drawn on the target texture.
#This will create the textures if not already. It will create textures from image data or block colour. Seems to work fine as direct rendering of textures to the screen works brilliantly.
if target.texture == None:
create_texture(target)
if surface.texture == None:
create_texture(surface)
frame_buffer = glGenFramebuffersEXT(1)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame_buffer)
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, target.texture, 0) #target.texture is the texture id from the object
glPushAttrib(GL_VIEWPORT_BIT)
glViewport(0,0,target.surface_size[0],target.surface_size[1])
draw_texture(surface.texture,offset,surface.surface_size,[float(c)/255.0 for c in surface.colour]) #The last part changes the 0-255 colours to 0-1 The textures when drawn appear to have the correct colour. Don't worry about that.
glPopAttrib()
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)
glDeleteFramebuffersEXT(1, [int(frame_buffer)]) #Requires the sequence of the integer conversion of the ctype variable, meaning [int(frame_buffer)] is the odd required way to pass the frame buffer id to the function.
This function may also be useful,
def draw_texture(texture,offset,size,c):
glMatrixMode(GL_MODELVIEW)
glLoadIdentity() #Loads model matrix
glColor4fv(c)
glBegin(GL_QUADS)
glVertex2i(*offset) #Top Left
glVertex2i(offset[0],offset[1] + size[1]) #Bottom Left
glVertex2i(offset[0] + size[0],offset[1] + size[1]) #Bottom, Right
glVertex2i(offset[0] + size[0],offset[1]) #Top, Right
glEnd()
glColor4fv((1,1,1,1))
glBindTexture(GL_TEXTURE_2D, texture)
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0)
glVertex2i(*offset) #Top Left
glTexCoord2f(0.0, 1.0)
glVertex2i(offset[0],offset[1] + size[1]) #Bottom Left
glTexCoord2f(1.0, 1.0)
glVertex2i(offset[0] + size[0],offset[1] + size[1]) #Bottom, Right
glTexCoord2f(1.0, 0.0)
glVertex2i(offset[0] + size[0],offset[1]) #Top, Right
glEnd()
You don't show your projection matrix, so I'll assume it's identity too.
OpenGL framebuffer origin is bottom left, not top left.
The size issue is more difficult to explain. What is your projection matrix after all ?
also, you don't show how to use the texture, and I'm not sure what we're looking at in your "incorrect" image.
Some non-related comments:
creating a framebuffer each frame is not the right way to go about it.
come to think about it, why use framebuffer at all ? it seems that the only thing you're after is blending to the frame buffer ? glEnable(GL_BLEND) does that just fine.