I'll try to explain my problem with images. So this is a test texture I'm using for my OpenGL application:
As you can see, there is a 2-pixels wide border around the image with different colors for me to be able to see if coordinates are properly set in my application.
I'm using a 9-cell pattern so I'm drawing 9 quads with specific texture coordinates. At first sight everything works fine, but there is a small problem with displaying a texture:
In the picture I marked where is first quad, and where is the second one. As you can see, first one is displayed correctly, but second one smoothly goes from first quad's colors to it's own, but it should start with pure green and pink. So I'm guessing it's a problem with texture coordinates.
This is how they are set:
// Bottom left quad [1st quad]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(0.0f, 1.0);
glVertex2i(pos.x, pos.y + height);
// Top left
glTexCoord2f(0.0f, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(pos.x, pos.y + height - m_borderWidth);
// Top right
glTexCoord2f(maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);
// Bottom right
glTexCoord2f(maxTexCoordBorderX, 1.0);
glVertex2i(pos.x + m_borderWidth, pos.y + height);
glEnd();
// Bottom middle quad [2nd quad]
glBegin(GL_QUADS);
// Bottom left
glTexCoord2f(maxTexCoordBorderX, 1.0);
glVertex2i(pos.x + m_borderWidth, pos.y + height);
// Top left
glTexCoord2f(maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);
// Top right
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, (GLfloat)1.0 - maxTexCoordBorderY);
glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);
// Bottom right
glTexCoord2f((GLfloat)1.0 - maxTexCoordBorderX, 1.0);
glVertex2i(pos.x + width - m_borderWidth, pos.y + height);
glEnd();
You can see that I'm using maxTexCoordBorderX variable which is calculated based on border and image size. Image width is 32 and border width is 2.
maxTexCoordBorderX = 2 / 32 = 0.0625
Could anyone please help with with finding out where the problem is?
Most likely culprit is that you are not sampling on the texel centers. For example, if you have a 32x32 pixel texture, the texel-centers are offset by 1/64.
Here's a rough diagram of a 4x4 texture. The squares are the texels (or pixels) of the image.
_________________1,1
| | | | |
| | | | |
|___|___|___|___|_0.75
| | | | |
| | | | |
|___|___|___|___|_0.5
| | | | |
| | | | |
|___|___|___|___|_0.25
| | | | |
| X | | | |
|___|___|___|___|
0,0 | 0.5 | 1
0.25 0.75
x = (0.125, 0.125)
If you sample on one of the lines, you will get a value exactly between two texels, which will (if you have texture sampling set to linear blend) give you an average value. If you want to sample the exact texel value, you need to specify a u,v in the center of the texel.
You've running into a fencepost problem. I answered the solution to your very problem here
https://stackoverflow.com/a/5879551/524368
Related
I am struggling with OpenGL lighting. I have the following enabled:
Specular[0] = 1f;
Specular[1] = 1f;
Specular[2] = 1f;
Specular[3] = 1f;
Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK, Gl.GL_SHININESS, new float[] { 70 });
Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK, Gl.GL_SPECULAR, Specular);
Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, LightDef.LightPosToArray);
Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, LightDef.AmbientToArray);
Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, LightDef.DiffuseToArray);
Gl.glEnable(Gl.GL_LIGHT0);
Gl.glEnable(Gl.GL_LIGHTING);
Gl.glShadeModel(Gl.GL_SMOOTH);
When I draw rectangles adjacent to each other and they have the same size everything looks fine. When I draw them at different sizes the lighting changes on each one. How can I make them look seamless?
Gl.glNormal3f(0, 0, 1);
Gl.glRectf(0, 0, 1000, 500);
Gl.glRectf(0, 500, 500, 1000);
Gl.glRectf(500, 500, 700, 700);
The Legacy OpenGLlight model uses Gouraud Shading. The light is computed for the vertices and interpolated on the fragments which are covered by the polygons.
The specular light depends on the location or direction of the light source, the normal vector of the surface and the viewing direction. Since direction of view is different to each vertex, the lighting of the surfaces is different.
In compare to the specular light, the diffuse light does not depend on the viewing direction. It depends on the location or direction of the light source and the normal vector of the surface. If the normal vectors of the surfaces are equal and the light source is a directional light, then the light would be the same over all the surfaces.
Set the specular light 0:
Specular[0] = 0f;
Specular[1] = 0f;
Specular[2] = 0f;
Specular[3] = 0f;
and ensure that the light source is a directional light (4th component of LightDef.LightPosToArray has to be 0).
Another option would be to tessellate the larger surfaces in that way, that the share the vertices with the smaller ones. e.g.:
+---+---+
| | |
+---+---+---+
| | | |
+---+---+---+---+
| | | | |
+---+---+---+---+
See also GLSL fixed function fragment program replacement
glBegin(GL_POLYGON);
// color of the shape
glColor3f(1.0, 1.0, 1.0);
// draw shape
glVertex2f(50, 200);
glVertex2f(50, 170);
glVertex2f(80, 200);
glVertex2f(80, 240);
glVertex2f(50, 240);
glEnd();
I am struggling to draw the shape below. My shape just needs to be rotated.
Preview:
How the shapes should look like:
The primitive type GL_POLYGON concatenates the vertex coordinates to a convex polygon. The last point is concatenated to the first point. For a shape with 4 corner points, 4 vertex coordinates are sufficient:
+ (80, 240)
/ |
Y / |
^ / |
| (50, 200) + |
| | |
| | |
| | |
| (50, 170) +-----+ (80, 170)
|
+-------------> X
glBegin(GL_POLYGON);
glVertex2f(50, 170);
glVertex2f(80, 170);
glVertex2f(80, 240);
glVertex2f(50, 200);
glEnd();
I have been writing my own SSAA fragment shader, so far I am sampling 4 points: top left, top right, bottom left and bottom right.
I am rendering to a small window, I have noticed when I full screen this window I have bars on all side of the screen that repeats what should be on the other side of the screen.
My shader currently calculates if we are looking at an edge pixel like this:
TL = TopLeft
if(texCoord.s <= 1 || texCoord.s >= textureWidth - 1)
{
//dont offset by -x, instead just use the current x and only offset y
TL = texture2D(texture, vec2(texCoord.s , texCoord.t + y ));
}
else
{
TL = texture2D(texture, vec2(texCoord.s - x, texCoord.t + y ));
}
Texel coordinates range from 0 to 1 on both axes over the whole texture. Therefore, texture coordinates (0, 0) refers to the bottom-left corner (i.e. not the center) of the bottom-left texel.
Illustrated:
d_x = 1 / textureWidth
d_y = 1 / textureHeight
+-----+-----+-----+
| | | |
| | | |
| | | |
(-d_x,d_y) +-----+-----+-----+ (2d_x, d_y)
| | | |
| | A | |
| | | |
+-----+-----+-----+
(-d_x,0) (0,0) (d_x,0) (2d_x, 0)
A: (d_x/2, d_y/2) <= center of the bottom-left texel
If you sample at point A, linear texture filtering will produce the value of the bottom-left texel exactly. If you sample at (0, 0) however, linear filtering will give the average of all the corners texels.
This behavior can be controlled by configuring GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T with glTexParameter. In your case, GL_CLAMP_TO_EDGE is probably the right mode to use.
I have a Problem when drawing with the MFC CDC class and the LineTo and MoveTo function.
The CDC Object doesn't begin at the point where I move the Pointer and leaves the first Pixel blanc like in the center of the image. When I draw around a corner like on the left side of the image it is clear that the CDC object leaves the outmost pixel free.
I did try to load a custom brush but had no different results.
memDC.FillSolidRect(client, BACKGROUND_COLOR);
CPen penBorder(PS_ENDCAP_SQUARE | PS_SOLID, BORDER_WIDTH, BORDER_COLOR);
//Draw the Horizontal line for the Status Bar
CPen* oldPen = memDC.SelectObject(&penBorder);
memDC.MoveTo(client.left + 0.5f * BORDER_WIDTH, client.top + 0.5f * BORDER_WIDTH);
memDC.LineTo(client.Width() - 0.5f * BORDER_WIDTH, client.top + 0.5f * BORDER_WIDTH);
CPen penRecess(PS_ENDCAP_SQUARE | PS_SOLID, BORDER_WIDTH, RECESS_COLOR);
//Draw the recess
memDC.SelectObject(&penRecess);
memDC.MoveTo(client.left + 1.5f * BORDER_WIDTH, client.top + 1.5f * BORDER_WIDTH);
memDC.LineTo(client.Width() - 0.5f * BORDER_WIDTH, client.top + 1.5f * BORDER_WIDTH);
The problem has nothing to do with MFC but is inherent in the underlying Windows GDI function. The documentation for LineTo says:
The LineTo function draws a line from the current position up to, but not including, the specified point.
If you need the last point drawn, you should do a second LineTo one pixel away from the first.
I am reading the depthbuffer of a scene, however as I rotate the camera I notice that towards the edges of the screen the depth is returned closer to camera. I think the angle of impact has an effect on the depthbuffer, however as I am drawing a quad to the framebuffer, I do not want this to happen (this is not actually the case ofcourse but this sums up my what I need).
I linearize the depth with the following:
float linearize(float depth) {
float zNear = 0.1;
float zFar = 40.0;
return (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
}
I figured the following to correct for this, but it's not quite right yet. 45.0 is the angle of the camera vertically / 2. side is the space from the center of the screen.
const float angleVert = 45.0 / 180.0 * 3.17;
float sideAdjust(vec2 coord, float depth) {
float angA = cos(angleVert);
float side = (coord.y - 0.5);
if (side < 0.0) side = -side;
side *= 2.0;
float depthAdj = angA * side;
return depth / depthAdj;
}
To show my problem with a drawing with results of depth of a flat surface in front of the camera:
c
/ | \
/ | \
/ | \
closer further closer
is what I have, what I need:
c
| | |
| | |
| | |
even even even
An idea of how to do it, would be to find the position P in eye-space. Consider P a vector from origin to the point. Project the P onto the the eye direction vector (which in eye-space always is (0,0,-1)). The length of the projected vector is what you need.