Related
I'm trying to pass a list of integers to the fragment shader and need random access to any of its positions. I can't use uniforms since index must be a constant, so I'm using the usual technique of passing the data through a texture.
Things seem to work, but calling texture2D to obtain specific pixels is not behaving as I'd expect.
My data looks like this:
this.textureData = new Uint8Array([
0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30, 0, 0, 0, 40,
0, 0, 0, 50, 0, 0, 0, 60, 0, 0, 0, 70, 0, 0, 0, 80,
]);
I then copy that over through a texture:
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
this.gl.texImage2D(
this.gl.TEXTURE_2D,
0,
this.gl.RGBA,
4, // width: using 4 since its 4 bytes per pixel
2, // height
0,
this.gl.RGBA,
this.gl.UNSIGNED_BYTE,
this.textureData);
So this texture is 4x2 pixels.
When I call texture2D(uTexture, vec2(0,0)); I get a vec4 pixel with the correct values (0,0,0,10).
However, when I call with locations such as (1,0), (2,0), (3,0), (4,0), etc they all return a pixel with (0,0,0,30).
Same for the second row. If I call with (0,1) I get the first pixel of the second row.
Any number greater than 1 for the X coordinate returns the last pixel of the second row.
I'd expect the coordinates to be:
this.textureData = new Uint8Array([
// (0,0) (1,0) (2,0) (3,0)
0, 0, 0, 10, 0, 0, 0, 20, 0, 0, 0, 30, 0, 0, 0, 40,
// (0,1) (1,1) (2,1) (3,1)
0, 0, 0, 50, 0, 0, 0, 60, 0, 0, 0, 70, 0, 0, 0, 80,
]);
What am I missing? How can I correctly access the pixels?
Thanks!
Texture coordinates are not integral, they are in the range [0.0, 1.0]. They map the vertices of the geometry to a point in the texture image. The texture coordinates specifies which part of the texture is placed on an specific part of the geometry and together with the texture parameters (see gl.texParameteri) it specifies how the geometry is wrapped by the texture. In general, the lower left point of the texture is addressed by the texture coordinate (0.0, 0.0) and the upper right point of the texture is addressed by (1.0, 1.0).
Texture coordinates work the same in OpenGL, OpenGL Es and WebGL. See How do opengl texture coordinates work?
I want to do smooth transitions between different colors(rather than just toggling it) by pressing the keyboard key 't'.
Below is my code which toggles the colors at once but i want a smooth transitions of color:
case 't':
// code for color transition
changeColor += 1;
if(changeColor>8) //Toggling between 9 different colors
changeColor=0;
break;
Color storing code:
GLfloat diffColors[9][4] = { {0.3, 0.8, 0.9, 1.0},
{1, 0, 0, 1},
{0, 1, 0, 1},
{0, 0, 1, 1},
{0.5, 0.5, 0.9, 1},
{0.2, 0.5, 0.5, 1},
{0.5, 0.5, 0.9, 1},
{0.9, 0.5, 0.5, 1},
{0.3, 0.8, 0.5, 1} };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, diffColors[changeColor]);
Change the changeColor parameter to float and instead of increment by 1 add some small value like 0.1 or smaller depends on how quick you want to change the colors and how often your event is firing.
case 't':
// code for color transition
changeColor += 0.025;
break;
Use linear interpolation to compute the color based on parameter changeColor.
//---------------------------------------------------------------------------
GLfloat diffColors[9][4] =
{
{0.3, 0.8, 0.9, 1.0},
{1.0, 0.0, 0.0, 1.0},
{0.0, 1.0, 0.0, 1.0},
{0.0, 0.0, 1.0, 1.0},
{0.5, 0.5, 0.9, 1.0},
{0.2, 0.5, 0.5, 1.0},
{0.5, 0.5, 0.9, 1.0},
{0.9, 0.5, 0.5, 1.0},
{0.3, 0.8, 0.5, 1.0}
};
GLfloat changeColor=0.0; // This must be float !!!
//---------------------------------------------------------------------------
void set_color()
{
int i;
const int N=9; // colors in your table
const GLfloat n=N+1.0; // colors in your table + 1
float *c0,*c1,c[4],t;
// bound the parameter
t=changeColor; // I renamed it so I do nto need to write too much)
while (t>= n) t-=n;
while (t<0.0) t+=n;
i=floor(t);
changeColor=t; // update parameter
t-=i; // leave just the decimal part
// get neighboring colors to t
c0=diffColors[i]; i++; if (i>=N) i=0;
c1=diffColors[i];
// interpolate
for (i=0;i<4;i++) c[i]=c0[i]+((c1[i]-c0[i])*t);
//glColor4fv(c);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c);
}
//---------------------------------------------------------------------------
so the idea is to dissect the changeColor to integer and fractional/decimal part. The integer part tells you between which 2 colors in your table you are and the fractional part <0..1> tells how far from the one color to the other one.
Linear interpolation of value x between 2 values x0,x1 and parameter t=<0..1> is like this:
x = x0 + (x1-x0)*t
If you look at the code above it does the same for c,c0,c1,t... In order this to get working the first chunk of code where you add to the parameter starting with case 't': must be executed repetitively like in timer ... and also invoke rendering. If it is just in some onkey handler that is called only once per key hit (no autorepeat) then it will not work and you need to implement the addition in some timer or on redraw event if you continuously redrawing screen... Again if not even that is happening you need to change the architecture of your app.
So this is how I solved it.
case 't':
// code for color transitioncol
changeColor=8; //I am doing the color transition at 9th number color
if(initialValue>=1.0)
initialValue=0.1;
initialValue+=0.01;
break;
Color storing code:
GLfloat diffColors[9][4] = { {initialValue, 0.5, 0.9, 1.0},
{initialValue, 1.0, 0.0, 0.0},
{initialValue, 0.0, 1.0, 0.0},
{initialValue, 0.8, 0.5, 0.8},
{initialValue, 0.5, 0.5, 0.9},
{initialValue, 0.9, 0.9, 0.5},
{initialValue, 0.5, 0.7, 0.9},
{initialValue, 0.9, 0.5, 0.5},
{initialValue, 0.7, 0.3, 0.5}};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, diffColors[changeColor]);
I have written the following function to draw a cube:
void drawCube() {
Point vertices[8] = { Point(-1.0, -1.0, -1.0), Point(-1.0, -1.0, 1.0), Point(1.0, -1.0, 1.0), Point(1.0, -1.0, -1.0),
Point(-1.0, 1.0, -1.0), Point(-1.0, 1.0, 1.0), Point(1.0, 1.0, 1.0), Point(1.0, 1.0, -1.0) };
int faces[6][4] = {{0, 1, 2, 3}, {0, 3, 7, 4}, {0, 1, 5, 4}, {1, 2, 6, 5}, {3, 2, 6, 7}, {4, 5, 6, 7}};
glBegin(GL_QUADS);
for (unsigned int face = 0; face < 6; face++) {
Vector v = vertices[faces[face][1]] - vertices[faces[face][0]];
Vector w = vertices[faces[face][2]] - vertices[faces[face][0]];
Vector normal = v.cross(w).normalised();
glNormal3f(normal.dx, normal.dy, normal.dz);
for (unsigned int vertex = 0; vertex < 4; vertex++) {
switch (vertex) {
case 0: glTexCoord2f(0, 0); break;
case 1: glTexCoord2f(1, 0); break;
case 2: glTexCoord2f(1, 1); break;
case 3: glTexCoord2f(0, 1); break;
}
glVertex3f(vertices[faces[face][vertex]].x, vertices[faces[face][vertex]].y, vertices[faces[face][vertex]].z);
}
}
glEnd();
}
When the cube is rendered with a light shining on to it, it appears that as I rotate the cube, the correct shading transitions are only happening for around half the faces. The rest just remain a very dark shade, as if I had removed the normal calculations.
I then decided to remove a couple of faces to see inside the cube. The faces that are not reflecting the light correctly on the outside, are doing so correctly on the inside. How can I ensure that the normal to each face is pointing out from that face, rather than in towards the centre of the cube?
To reverse the direction of the normal, swap the order you use for the cross product:
Vector normal = w.cross(v).normalised();
Maybe there is a more efficient way, but a imho quite easy to understand way is the following....
Calculate the vector that points from the center of the side to the center of the cube. Call it
m = center cube - center side
Then calculate the scalar product of that vector with your normal:
x = < m , n >
The scalar product is positive if the two vectors point in the same direction with respect to the side (the angle between them is less than 90 degree). It is negative, if they point in opposite directions (angle is bigger than 90 degree). Then correct your normal via
if ( x > 0 ) n = -n;
to make sure it always points outwards.
I am trying to draw one line with ar[]. It contains the point cords. I am also trying to use the color described in clr[]. Can any one tell me what is wrong with my ver function. When I run it, only a white screen comes up.
void ver(void)
{
glClear(GL_DEPTH_BUFFER_BIT);
glPushMatrix();
GLfloat ar [] = {0.25, 0.25,
0.5, 0.25,
};
GLfloat clr [] = {1.0, 0.0,0.0
};
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2,GL_FLOAT, 0, ar);
glColorPointer(3,GL_FLOAT,0,clr);
glDrawElements(GL_LINES, 2, GL_FLOAT, ar);
glDrawElements(GL_LINES, 3, GL_FLOAT, clr);
glPopMatrix();
glutSwapBuffers();
}
Your call to glDrawElements() is wrong. You need to pass an array of indices to it, and you only need to call it once. So you need something like this:
GLuint indices[] = { 0, 1, 2, 3 };
glDrawElements (GL_LINES, 2, GL_UNSIGNED_INT, indices);
Also, I think you need to expand your color array to have one color per vertex, so it should look more like:
GLfloat clr [] = { 1.0, 0.0, 0.0,
1.0, 0.0, 0.0 };
I'm creating a cuboid in OpenGL using Vertex arrays but my texture seems to have gone a bit wrong.
Heres my code:
float halfW = getW() / 2;
float halfH = getH() / 2;
GLubyte myIndices[]={
1, 0, 2, //front
2, 0, 3,
4, 5, 7, //back
7, 5, 6,
0, 4, 3, //left
3, 4, 7,
5, 1, 6, //right
6, 1, 2,
7, 6, 3, //up
3, 6, 2,
1, 0, 5, //down
5, 0, 4
};
float myVertices[] = {
-halfW, -halfH, -halfW, // Vertex #0
halfW, -halfH, -halfW, // Vertex #1
halfW, halfH, -halfW, // Vertex #2
-halfW, halfH, -halfW, // Vertex #3
-halfW, -halfH, halfW, // Vertex #4
halfW, -halfH, halfW, // Vertex #5
halfW, halfH, halfW, // Vertex #6
-halfW, halfH, halfW // Vertex #7
};
float myTexCoords[]= {
1.0, 1.0, //0
0.0, 1.0, //1
0.0, 0.0, //2
1.0, 0.0, //3
0.0, 0.0, //4
1.0, 0.0, //5
1.0, 1.0, //6
0.0, 1.0 //7
};
Heres the problem:
The front and back are rendering fine but top, bottom, left and right are skewed.
Where am I going wrong?
Your texture coordinates and vertex indices look are off. Since Vertex #2 (with the coordinates halfW, halfH, -halfW) has texture coordinate (0, 0), Vertex #6 (with the coordinates halfW, halfH, halfW) should not have the texture coordinate (1, 1). What it does is it puts vertices with the texture coordinates (0, 0) and (1, 1) along the same edge and that leads to trouble.
The problem with a cube is that one 2D texture coordinate per vertex is not enough to for mapping a texture onto a cube like this (however you try to put them, you will end up with weird sides).
The solution is to either add extra triangles so that no side share vertices with another side, or look in to Cube Maps where you specify the texture coordinates in 3D (just as the vertices). I would suggest using Cube Maps, since it avoids adding redundant vertices.