Flag effect in opengl - opengl

I'm trying to follow this online tutorial to create some waves
http://nehe.gamedev.net/tutorial/flag_effect_(waving_texture)/16002/.
I want to make the wave much bigger, but I'm not sure if I'm going about it the right way, the current mesh of quads is sized 45 in the tutorial, so i have increased to 450, however the size doesn't seem to increase that much.
Can someone point me in the right direction as to what needs to be modified to make the quads bigger.

If you just want to make the quads bigger, then you need to modify the vertex position code. In the NeHe tutorial you posted change this part:
// Loop Through The X Plane
for(int x=0; x<45; x++)
{
// Loop Through The Y Plane
for(int y=0; y<45; y++)
{
// Apply The Wave To Our Mesh
points[x][y][0]=float((x/5.0f)-4.5f);
points[x][y][1]=float((y/5.0f)-4.5f);
points[x][y][2]=float(sin((((x/5.0f)*40.0f)/360.0f)*3.141592654*2.0f));
}
}
To this:
// Loop Through The X Plane
float spacing = 0.5f;
float spacingInv = 1.0f/spacing;
float offset = (45 / spacingInv) / 2.0f; // The 45 comes from the number of points (if you change this, change the for loop and the variable creation)
for(int x=0; x<45; x++)
{
// Loop Through The Y Plane
for(int y=0; y<45; y++)
{
// Apply The Wave To Our Mesh
// We change the x/5.0f-4.5f to change the size of the quads
// See text after for more details
points[x][y][0]=float((x/spacingInv)-offset);
points[x][y][1]=float((y/spacingInv)-offset);
points[x][y][2]=float(sin((((x/spacingInv)*40.0f)/360.0f)*3.141592654*2.0f));
}
}
Explanation:
x/5.0f gives you values 0, 0.2, 0.4, 0.6, 0.8, 1.0, ......, 9.0.
If you were to take just those values, you would now have an off center grid of quads. Now taking x/5.0f - 4.5f gives you values -4.5 -4.3, -4.1, ...... 4.1, 4.3, 4.5
If you wanted to make the quads bigger, you need to increase the spacing between the points (i.e. change the x/5.0f to something like x/2.0f (which is what happens in the example I gave)). And then you want to recenter (i.e. change the -4.5f).

Related

How to draw points in random locations but within screen or window boundaries

I am using OpenGL library in my Visual C++ application where I want to draw say, 100 points in random locations and I would like to check if these points random co-ordinates or random locations that generated are within the screen or window boundaries. I tired using a (x,y,z) vertex option and I get the points vertical running along a line. If I try generating only (x,y) and drawing them then I do get a lot more points scattered but definitely not all 100 within the window dimensions.
my code looks something like this:
GLfloat dots_vert[99];
for (int i = 0; i < 99; i++){
if (i % 2 == 0)
dots_vert[i] = 0.0f;
else
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*100.0f - (100.0f / 2);
}
glEnable(GL_POINT_SMOOTH);
glPointSize(3.0f);
glEnableClientState(GL_VERTEX_ARRAY);
GLuint vbo_ID;
glGenBuffers(1, &vbo_ID);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glBufferData(GL_ARRAY_BUFFER, sizeof(dots_vert), dots_vert, GL_DYNAMIC_DRAW);
while (!GetAsyncKeyState(VK_DOWN)){
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glDrawArrays(GL_POINTS, 0, 100);
SwapBuffers(g_pOpenGLWindow->hDC);
Let me guide you through the glaring mistakes I can immediately see in that code.
First of all the obvious first mistake: you claim to be drawing 100 points but your dots_vert array is only 99 elements long. This is repeated in the following loop, where you go from 0 to 98 for a total of 99 times.
So first of all:
GLfloat dots_vert[100];
for (int i = 0; i < 100; ++i)
{
[...]
}
There is another huge mistake in there but we'll keep that for later, let's move on for now.
The second mistake is about the knowledge of the OpenGL API and computer graphics. First of all, your goal is to pass points to the GPU, so you need the glVertexAttribPointer function, that much you figured out. The absolute first thing you wanna do is to look at the glVertexAttribPointer reference documentation, so you have an idea of what you need. You need an index, a size, a type, a normalized flag, a stride and an offset.
Let's look at what the reference documentation says about the size parameter:
size
Specifies the number of components per generic vertex attribute. Must be 1, 2, 3, 4. Additionally, the symbolic constant GL_BGRA is accepted by glVertexAttribPointer. The initial value is 4.
This is immediately obvious to be crucial in determining what kind of data you're trying to pass to the GPU. You set the parameter to 3, which means that you have an x, a y and a z. But the previous code contradicts this. For starters, your dots_vert array is 100 elements long, and you want to draw 100 points, so you have enough for 100/100 = 1 component per point, not 3. But even worse, the inside of the for loop contradicts this even further, so let's go back and check the mistake I mentioned previously.
Mistake number three: your for loop consists of an if {} else {} statement, where you set the current element of the dots_vert array to a value of 0.0f if the index of the loop is even (if (i % 2 == 0)), and a random value between -50.0f and 50.0f otherwise. Assuming 1 component per point, this means that you're only generating the x coordinates, so you're working in a single dimension.
Clearly this is not what you intended to do, also because half of your points will be 0.0f and therefore they'll all overlap. So I assume you were trying to generate a random value for x and y, and set z to 0.0f, which would make much more sense. First of all, you have 3 components per point and therefore you'll need an array with 100*3 = 300 elements. So first of all, let's fix the previous code:
GLfloat dots_vert[300];
for (int i = 0; i < 300; ++i)
{
[...]
}
Much better. Now we need to generate a random x and y valye for each point, and set z to 0.0f since we don't need it. You wanna do all of the components at once in a single loop, so you want your loop to step by 3, not 1, so once again let's fix the previous code:
GLfloat dots_vert[300];
for (int i = 0; i < 300; i += 3)
{
[...]
}
Now we can generate x, y and z together in a single loop. This is the crucial part where understanding how computer graphics work, specifically in the context of the OpenGL API. OpenGL uses a coordinate system where the origin is in the middle of the screen, the x axis moves horizontally (positive x points to your right), the y axis moves vertically (positive y points up), and the z axis goes straight through the screen (positive z points out of the screen, towards you). Now this is the very important part: x, y and z are clipped to a specific range of values; anything outside of this range is ignored. For all coordinates, the range goes from -1.0f to 1.0f. Anything below of above that is not drawn at all.
So if you want to have 100 points to be inside the screen, ignoring projection which is outside of the scope of this exercise, you want to generate x and y in the -1.0f to 1.0f range, not -50.0f to 50.0f like you're doing there. You can keep z to 0.0f, doesn't really matter in this case. This is why most of your points fall outside of the screen: with that range, statistically speaking, around 98% of your points will fall outside of the clip space and will be ignored.
So ultimately this is what you want:
GLfloat dots_vert[300];
for (int i = 0; i < 300; i += 3)
{
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x
dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y
dots_vert[i+2] = 0.0f; // this is z
}
Finally a reminder: when you do glDrawArrays(GL_POINTS, 0, 100); you're telling the GPU to draw 100 points. Each point is made of however many components you specified in the size parameter of the glVertexAttribPointer function. In this case you wanna draw 100 points, each point is made of 3 components, so the GPU expects an array of 100*3 = 300 floats. numbers. Anything less could result in either a segmentation fault or even worse an undefined behavior (which means anything can happen), so pay close attention to what you're doing and make sure you know exactly what kind of data you're passing to the GPU because you might end up with a nonsense result and you'll be stuck trying to figure out what went wrong. In this case, you have basically no code at all to check so it's easy to fix, but when you'll end up with a decent amount of code (and you will eventually), an error like this could mean hours or even days wasted trying to find the error.
As a bonus, feel free to ignore this one: technically a point is made of 4 components. This component is called w and its use is outside of the scope of this exercise so don't worry about it, just remember that it should always be set to 1.0f, unless you are doing projection.
So technically you could do this too:
GLfloat dots_vert[400];
for (int i = 0; i < 400; i += 4)
{
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x
dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y
dots_vert[i+2] = 0.0f; // this is z
dots_vert[i+3] = 1.0f; // this is w
}
Then you set the size parameter of glVertexAttribPointer to 4 instead of 3, the result should be exactly the same.

Raytracing - Rays shot from camera through screen don't deviate on the y axis - C++

So I am trying to write a Raytracer as a personal project, and I have got the basic recursion, mesh geometry, and ray triangle intersection down.
I am trying to get a plausible image out of it but encounter the problem that all pixel rows are the same, giving me straight vertical lines.
I found that all pixel positions generated from the camera function are the same on the y axis but cannot find the problem with my vector math here (I use my Vertex structure as vectors too, its lazy I know):
void Renderer::CameraShader()
{
//compute the width and height of the screen based on angle and distance of the near clip plane
double widthRad = tan(0.5*m_Cam.angle)*m_Cam.nearClipPlane;
double heightRad = ((double)m_Cam.pixelRows / (double)m_Cam.pixelCols)*widthRad;
//get the horizontal vector of the camera by crossing the direction angle with an
Vertex cross = ((m_Cam.direction - m_Cam.origin).CrossProduct(Vertex(0, 1, 0)).Normalized(0.0001))*widthRad;
//get the up/down vector of the camera by crossing the horizontal vector with the direction vector
Vertex crossDown = m_Cam.direction.CrossProduct(cross).Normalized(0.0001)*heightRad;
//generate rays per pixel row and column
for (int i = 0; i < m_Cam.pixelCols;i++)
{
for (int j = 0; j < m_Cam.pixelRows; j++)
{
Vertex pixelPos = m_Cam.origin + (m_Cam.direction - m_Cam.origin).Normalized(0.0001)*m_Cam.nearClipPlane //vector of the screen center
- cross + (cross*((i / (double)m_Cam.pixelCols)*widthRad*2)) //horizontal vector based on i
+ crossDown - (crossDown*((j / (double)m_Cam.pixelRows)*heightRad*2)); //vertical vector based on j
//cast a ray through according screen pixel to get color
m_Image[i][j] = raycast(m_Cam.origin, pixelPos - m_Cam.origin, p_MaxBounces);
}
}
}
I hope the comments in the code make clear what is happening.
If anyone sees the problem help would be nice
The problem was that I had to substract the camera origin from the direction point. It now actually renders sillouettes, so I guess I can say its fixed :)

Add sin wave to triangle mesh

can someone help me addd a sin wave onto my triangle mesh to help me get a wave effect.
for(int i = 0; i<150; i++){
for(int j = 0; j<150; j++){
grid[i][j] = 0;
glBegin(GL_LINE_LOOP);
glVertex3f(i*3,grid[i][j],j*3);
glVertex3f(i*3,grid[i][j],j*3+3);
glVertex3f(i*3+3,grid[i][j],j*3);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex3f(i*3,grid[i][j],j*3+3);
glVertex3f(i*3+3,grid[i][j],j*3+3);
glVertex3f(i*3+3,grid[i][j],j*3);
glEnd();
}
}
If i've got it right, all i should need to do is add a sin value to grid[i][j], am i right?
Are all the y values to be set to the same grid[i][j]?
It really depends on what you are trying to accomplish.
Are you trying to set up a surface that when looked on edge it looks like a sine wave?
If that is the case then assuming that you are modulating the y-axis and the z-axis plays no effect then you need to determine the frequency you want to use.
i.e y = A * sine (w * x + p) where A is amplitude, w is angular frequency, and p is phase.
You will also have to take into account the number of sample points on the x-axis so that it doesn't look to aliased. Sine is a continuous function but you are take only 150 samples.
Also you may want to reconsider how to calculate and draw your final triangle mesh. Your current code is not the most efficient because you are recalculating your mesh every frame.
You may want to consider initializing grid and then drawing triangle strips, etc. There is a lot online that discusses that.

CPU Ray Casting

I'm attempting ray casting an octree on the CPU (I know the GPU is better, but I'm unable to get that working at this time, I believe my octree texture is created incorrectly).
I understand what needs to be done, and so far I cast a ray for each pixel, and check if that ray intersects any nodes within the octree. If it does and the node is not a leaf node, I check if the ray intersects it's child nodes. I keep doing this until a leaf node is hit. Once a leaf node is hit, I get the colour for that node.
My question is, what is the best way to draw this to the screen? Currently im storing the colours in an array and drawing them with glDrawPixels, but this does not produce correct results, with gaps in the renderings, as well as the projection been wrong (I am using glRasterPos3fv).
Edit: Here is some code so far, it needs cleaning up, sorry. I have omitted the octree ray casting code as I'm not sure it's needed, but I will post if it'll help :)
void Draw(Vector cameraPosition, Vector cameraLookAt)
{
// Calculate the right Vector
Vector rightVector = Cross(cameraLookAt, Vector(0, 1, 0));
// Set up the screen plane starting X & Y positions
float screenPlaneX, screenPlaneY;
screenPlaneX = cameraPosition.x() - ( ( WINDOWWIDTH / 2) * rightVector.x());
screenPlaneY = cameraPosition.y() + ( (float)WINDOWHEIGHT / 2);
float deltaX, deltaY;
deltaX = 1;
deltaY = 1;
int currentX, currentY, index = 0;
Vector origin, direction;
origin = cameraPosition;
vector<Vector4<int>> colours(WINDOWWIDTH * WINDOWHEIGHT);
currentY = screenPlaneY;
Vector4<int> colour;
for (int y = 0; y < WINDOWHEIGHT; y++)
{
// Set the current pixel along x to be the left most pixel
// on the image plane
currentX = screenPlaneX;
for (int x = 0; x < WINDOWWIDTH; x++)
{
// default colour is black
colour = Vector4<int>(0, 0, 0, 0);
// Cast the ray into the current pixel. Set the length of the ray to be 200
direction = Vector(currentX, currentY, cameraPosition.z() + ( cameraLookAt.z() * 200 ) ) - origin;
direction.normalize();
// Cast the ray against the octree and store the resultant colour in the array
colours[index] = RayCast(origin, direction, rootNode, colour);
// Move to next pixel in the plane
currentX += deltaX;
// increase colour arry index postion
index++;
}
// Move to next row in the image plane
currentY -= deltaY;
}
// Set the colours for the array
SetFinalImage(colours);
// Load array to 0 0 0 to set the raster position to (0, 0, 0)
GLfloat *v = new GLfloat[3];
v[0] = 0.0f;
v[1] = 0.0f;
v[2] = 0.0f;
// Set the raster position and pass the array of colours to drawPixels
glRasterPos3fv(v);
glDrawPixels(WINDOWWIDTH, WINDOWHEIGHT, GL_RGBA, GL_FLOAT, finalImage);
}
void SetFinalImage(vector<Vector4<int>> colours)
{
// The array is a 2D array, with the first dimension
// set to the size of the window (WINDOW_WIDTH * WINDOW_HEIGHT)
// Second dimension stores the rgba values for each pizel
for (int i = 0; i < colours.size(); i++)
{
finalImage[i][0] = (float)colours[i].r;
finalImage[i][1] = (float)colours[i].g;
finalImage[i][2] = (float)colours[i].b;
finalImage[i][3] = (float)colours[i].a;
}
}
Your pixel drawing code looks okay. But I'm not sure that your RayCasting routines are correct. When I wrote my raytracer, I had a bug that caused horizontal artifacts in on the screen, but it was related to rounding errors in the render code.
I would try this...create a result set of vector<Vector4<int>> where the colors are all red. Now render that to the screen. If it looks correct, then the opengl routines are correct. Divide and conquer is always a good debugging method.
Here's a question though....why are you using Vector4 when later on you write the image as GL_FLOAT? I'm not seeing any int->float conversion here....
You problem may be in your 3DDDA (octree raycaster), and specifically with adaptive termination. It results from the quantisation of rays into gridcell form, that causes certain octree nodes which lie slightly behind foreground nodes (i.e. of a higher z depth) and which thus should be partly visible & partly occluded, to not be rendered at all. The smaller your voxels are, the less noticeable this will be.
There is a very easy way to test whether this is the problem -- comment out the adaptive termination line(s) in your 3DDDA and see if you still get the same gap artifacts.

2D tile based game, shows gaps between the tile sprites when I zoom in with the camera?

I am using the D3DXSPRITE method to draw my map tiles to the screen, i just added a zoom function which zooms in when you hold the up arrow, but noticed you can now see gaps between the tiles, here's some screen shots
normal size (32x32) per tile
zoomed in (you can see white gaps between the tiles)
zoomed out (even worst!)
Here's the code snipplet which I translate and scale the world with.
D3DXMATRIX matScale, matPos;
D3DXMatrixScaling(&matScale, zoom_, zoom_, 0.0f);
D3DXMatrixTranslation(&matPos, xpos_, ypos_, 0.0f);
device_->SetTransform(D3DTS_WORLD, &(matPos * matScale));
And this is my drawing of the map, (tiles are in a vector of a vector of tiles.. and I haven't done culling yet)
LayerInfo *p_linfo = NULL;
RECT rect = {0};
D3DXVECTOR3 pos;
pos.x = 0.0f;
pos.y = 0.0f;
pos.z = 0.0f;
for (short y = 0;
y < BottomTile(); ++y)
{
for (short x = 0;
x < RightTile(); ++x)
{
for (int i = 0; i < TILE_LAYER_COUNT; ++i)
{
p_linfo = tile_grid_[y][x].Layer(i);
if (p_linfo->Visible())
{
p_linfo->GetTextureRect(&rect);
sprite_batch->Draw(
p_engine_->GetTexture(p_linfo->texture_id),
&rect, NULL, &pos, 0xFFFFFFFF);
}
}
pos.x += p_engine_->TileWidth();
}
pos.x = 0;
pos.y += p_engine_->TileHeight();
}
Your texture indices are wrong. 0,0,32,32 is not the correct value- it should be 0,0,31,31. A zero-based index into your texture atlas of 256 pixels would yield values of 0 to 255, not 0 to 256, and a 32x32 texture should yield 0,0,31,31. In this case, the colour of the incorrect pixels depends on the colour of the next texture along the right and the bottom.
That's the problem of magnification and minification. Your textures should have invisible border populated with part of adjacent texture. Then magnification and minification filters will use that border to calculate color of edge pixels rather than default (white) color.
I think so.
I also had a similar problem with texture mapping. What worked for me was changing the texture address mode in the sampler state description; texture address mode is used to control what direct3d does with texture coordinates outside of the ([0.0f, 1.0f]) range: i changed the ADDRESS_U, ADDRESS_V, ADDRESS_W members to D3D11_TEXTURE_ADDRESS_CLAMP which basically clamps all out-of-range values for the texture coordinates into the [0.0f, 1.0f] range.
After a long time searching and testing people solutions I found this rules are the most complete rules that I've ever read.
pixel-perfect-2d from Official Unity WebSite
plus with my own experience i found out that if sprite PPI is 72(for example), you should try to use more PPI for that Image(96 maybe or more).It actually make sprite more dense and make no space for white gaps to show up.
Welcome to the world of floating-point. Those gaps exist due to imperfections using floating-point numbers.
You might be able to improve the situation by being really careful when doing your floating-point math but those seams will be there unless you make one whole mesh out of your terrain.
It's the rasterizer that given the view and projection matrix as well as the vertex positions is slightly off. You maybe able to improve on that but I don't know how successful you'll be.
Instead of drawing different quads you can index only the visible vertexes that make up your terrain and instead use texture tiling techniques to paint different stuff on there. I believe that won't get you the ugly seam because in that case, there technically isn't one.