Changing a heightmap so it show 16 hieghtmaps on a 4x4 grid - c++

Change the program to display 16 identical heightmaps arranged in a 4 x 4 grid. The edges of the heightmaps should be side by side in X and Z coordinates. However, they will not touch in the Y direction because the heights will be different.
C++
The below code is what I have already, i am just not too sure how to make it show the 16 identical heightmaps arranged in a 4x4 grid. I know it has to do with the squares on the height map, but i am very confused.
const int HEIGHTMAP_SIZE = 12;
float heights[HEIGHTMAP_SIZE + 1][HEIGHTMAP_SIZE + 1];
initDisplay();
for (unsigned int x = 0; x <= HEIGHTMAP_SIZE; x++)
{
for (unsigned int z = 0; z <= HEIGHTMAP_SIZE; z++)
{
heights[x][z] = (x % 2) * 0.5f -
z * z * 0.05f;
}
}
//TextureManager::activate("rainbow.bmp");
initHeightmapDisplayList();
void initHeightmapHeights()
{
for (unsigned int x0 = 0; x0 < HEIGHTMAP_SIZE; x0++)
{
unsigned int x1 = x0 + 1;
float tex_x0 = (float)(x0) / HEIGHTMAP_SIZE;
float tex_x1 = (float)(x1) / HEIGHTMAP_SIZE;
glBegin(GL_TRIANGLE_STRIP);
for (unsigned int z = 0; z <= HEIGHTMAP_SIZE; z++)
{
float tex_z = (float)(z) / HEIGHTMAP_SIZE;
glTexCoord2d(tex_x1, tex_z);
glVertex3d(x1, heights[x1][z], z);
glTexCoord2d(tex_x0, tex_z);
glVertex3d(x0, heights[x0][z], z);
}
glEnd();
}
}
void initHeightmapDisplayList()
{
heightmap_list.begin();
glEnable(GL_TEXTURE_2D);
TextureManager::activate("ground.bmp");
glColor3d(1.0, 1.0, 1.0);
initHeightmapHeights();
glDisable(GL_TEXTURE_2D);
heightmap_list.end();
}

I suspect that your TextureManager already has a way of doing this without direct calls to OpenGL.
What you should do is make the texture repeat itself.
glTexParamteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
By then scaling your texture coordinates up by a factor of 4, you would obtain a 4x4 grid of the original texture.

Related

Calculate grid width given a set of points

I am drawing a grid in opengl using this -
void draw_grid()
{
glColor3f(0.32, 0.32, 0.32);
int iterations = int(WIDTH / grid_width) + 1;
glBegin(GL_LINES);
for (int i = 0; i < iterations; i++)
{
int x = i * grid_width;
glVertex2f(x, 0);
glVertex2f(x, HEIGHT);
}
for (int i = 0; i < iterations; i++)
{
int y = i * grid_width;
glVertex2f(0, y);
glVertex2f(WIDTH, y);
}
glEnd();
}
And, then I plot points at the intersections of this grid.
I am implementing simple dda method for drawing lines.
For endpoints (2,3) and (15, 8) I get this as output -
But, for endpoints (2,3) and (35, 8) I get this -
You can see that for the second case some points get plotted outside the window and thus are not visible.
This happens because I have hardcoded the grid_width.
I understand that more the difference between the endpoints the smaller the grid_width is supposed to be.
But I can't figure out how exactly to calculate the grid_width so that no matter what endpoints are given they are drawn in the bounds of the window.
You have to determine the grid_width depending on the maximum coordinate. The maximum width of the grid is WIDTH / maxC where maxC is the maximum coordinate. e.g.:
grid_width = int(WIDTH / maxC);

Height Field with average normals

I am creating height field and i want to create its normals (face/vertex), I am using Triangles to create a mesh. I already calculated GL quad Normals but confused here for Triangles instead of quads.
I searched the internet and found out that two types of normals exists like per face and per vertex but not found any my code related help.
Here is what i am doing right now to create heightfield.
int average_normal()
{
glPushMatrix();
GLfloat xdelta=xsize/xsteps;
GLfloat zdelta=zsize/zsteps;
glNormal3f(0,1,0);
for (int x=0; x<xsteps-1; x++)
for (int z=0; z<zsteps-1; z++)
{
glBegin(GL_TRIANGLES);
setMaterialHeight(map[x][z]);
glNormal3f(0, 0, 1);
glVertex3f(xdelta*x,map[x][z],zdelta*z);
setMaterialHeight(map[x+1][z]);
glNormal3f(0, 0, 1);
glVertex3f(xdelta*x+xdelta,map[x+1][z],zdelta*z);
setMaterialHeight(map[x][z+1]);
glNormal3f(0, 0, 1);
glVertex3f(xdelta*x,map[x][z+1],zdelta*z+zdelta);
glEnd();
glBegin(GL_TRIANGLES);
setMaterialHeight(map[x+1][z+1]);
glNormal3f(0, 0, 1);
glVertex3f(xdelta*x+xdelta,map[x+1][z+1],zdelta*z+zdelta);
setMaterialHeight(map[x][z+1]);
glNormal3f(0, 0, 1);
glVertex3f(xdelta*x,map[x][z+1],zdelta*z+zdelta);
setMaterialHeight(map[x+1][z]);
glNormal3f(0, 0, 1);
glVertex3f(xdelta*x+xdelta,map[x+1][z],zdelta*z);
glEnd();
}
glPopMatrix();
return true;
}
How can I calculate its normal?
The normal vector can be computed by the Cross product of 2 vectors. Create a function, which computes the cross product and sets the normal vector attribute:
void set_normal_from_cross_product(
float x1, float y1, float z1,
float x2, float y2, float z2)
{
float nx = y1*z2 - z1*y2;
float ny = z1*x2 - x1*z2;
float nz = x1*y2 - y1*x2;
float len = sqrt(nx*nx + ny*ny + nz*nz);
if (len != 0.0f)
glNormal3f(nx/len, ny/len, nz/len);
}
In a grid the normal vectors can be computed by the vectors between the adjacent vertices. Write function which computes the vectors between the adjacent vertices and invokes set_normal_from_cross_product:
void set_grid_normal(int x, int z)
{
int prev_x = x > 0 ? x - 1 : x;
int next_x = x < xsteps - 1 ? x + 1 : x;
int prev_z = z > 0 ? z - 1 : z;
int next_z = z < zsteps - 1 ? z + 1 : z;
set_normal_from_cross_product(
xdelta * 2, map[next_x][z]-map[prev_x][z], 0,
0, map[x][next_z]-map[x][prev_z], zdelta * 2);
}
Use the function to s et the normal vectors:
void set_attributes(int x, int z)
{
setMaterialHeight(map[x][z]);
set_grid_normal(x, z);
glVertex3f(xdelta*x,map[x][z],zdelta*z);
}
for (int x=0; x<xsteps-1; x++)
{
for (int z=0; z<zsteps-1; z++)
{
glBegin(GL_TRIANGLES);
set_attributes(x, z);
set_attributes(x+1, z);
set_attributes(x, z+1);
glEnd();
glBegin(GL_TRIANGLES);
set_attributes(x+1, z+1);
set_attributes(x, z+1);
set_attributes(x+1, z);
glEnd();
}
}

OpenGL + Cloth simulation physics isn't working

I am attempting to implement a cloth simulation using a spring-particle system but something isn't quite right with my physics. When I run the simulation the cloth draws as expected but over time the force of gravity pulls the cloth downward indefinitely. In other words the forces caused by the springs are not accumulating properly to overcome the downward pull of gravity and I end up with this...:
It continues to droop downwards indefinitely. From all of the debugging I have done what I have seen is that the accumulation of forces on a particle caused by all of the springs attached to it is not properly summing when the force of gravity causes increased stretch. I can not figure out what I have overlooked in my physics.
My cloth updates every time step using this function
void Cloth::updateGeometry(atlas::utils::Time const& t) {
for (int i = 0; i < mSprings.size(); ++i) {
mSprings[i].calculateForces();
}
for (int i = 0; i < mParticles.size(); ++i) {
mParticles[i].updateGeometry(t);
}
}
My springs update using the below function where p1 and p2 are pointers to each particle that this spring is attached to.
void Spring::calculateForces() {
glm::vec3 springVector = normalize((p2->getCurrentPosition() - p1->getCurrentPosition()));
GLfloat stretchLength = length(p2->getCurrentPosition(), p1->getCurrentPosition());
GLfloat displacementFromRest = restLength - stretchLength;
glm::vec3 springForce = -k * displacementFromRest * normalize(springVector);
//Multiply the displacements by the spring constant to get
//A vector which represents the force on each spring
p1->addToSumOfSpringForces(springForce);
p2->addToSumOfSpringForces(-springForce);
}
Finally my particles update using.
void Particle::updateGeometry(atlas::utils::Time const& t) {
if (!stationary) {
previousPosition = currentPosition;
glm::vec3 forceOfGravity = mass * gravity;
glm::vec3 totalForce = forceOfGravity + (mass * totalSpringForces) - velocity*Damping;
acceleration = totalForce / mass;
//Perform Euler Integration
currentPosition += t.deltaTime * velocity;
velocity += t.deltaTime * acceleration;
//============== End Euler==============//
//Reset the forces acting on the particle from all of the springs
//So that a new accumulated total can be calculated.
totalSpringForces = glm::vec3{ 0.0f, 0.0f, 0.0f };
}
}
The totalSpringForces variable is updated by the call to addToSumOfSpringForces(springForce); in the spring update function. The idea is that each spring is evaluated first according to the current position of each particle then each particle's totalSpringForcevariable is accumulated each iteration using
void Particle::addToSumOfSpringForces(glm::vec3 force) {
totalSpringForces += force;
}
Just to add clarification the cloth is constructed using structural, bend and shear springs in accordance with this description. This may be unneccesary but I've included my cloth constructor below.
Cloth::Cloth(GLfloat width_, GLfloat height_, GLuint numParticlesWide_, GLuint numParticlesHigh_) :
width(width_),
height(height_),
numParticlesHigh(numParticlesHigh_),
numParticlesWide(numParticlesWide_),
clothRotationVector{0.0f, 0.0f, 0.0f},
clothPosition{ 0.0f, 5.0f, 0.0f },
clothRotationAngle(0.0f)
{
USING_ATLAS_MATH_NS;
USING_ATLAS_GL_NS;
glm::vec3 clothColour{1.0f, 0.5f, 0.2f};
//Create Particles
GLuint count = 0;
restLength = (width * (1 / (float)numParticlesWide));
for (GLuint y = 0; y < numParticlesHigh; ++y) {
for (GLuint x = 0; x < numParticlesWide; ++x) {
glm::vec3 pos = {(width * (x / (float)numParticlesWide)), (-height * (y / (float)numParticlesHigh)), 0.0f};
mParticles.push_back(Particle(pos, count, clothColour));
++count;
}
}
//Create Springs
for (GLuint x = 0; x < numParticlesWide; ++x) {
for (GLuint y = 0; y < numParticlesHigh; ++y) {
//============ Structural springs ==========//
//Connect to the particle to the immediate right of the current particle
if (x < numParticlesWide - 1) mSprings.push_back(Spring(getParticle(x,y), getParticle(x+1,y)));
//Connect to the particle that is immediately below the current particle
if (y < numParticlesHigh - 1) mSprings.push_back(Spring(getParticle(x,y), getParticle(x,y+1)));
//============ Shear Springs ================//
//Connect the shear springs to make the X pattern
if (x < numParticlesWide - 1 && y < numParticlesHigh - 1) {
mSprings.push_back(Spring(getParticle(x, y), getParticle(x + 1, y + 1)));
mSprings.push_back(Spring(getParticle(x+1, y), getParticle(x, y+1)));
}
//============ Bend Springs ===============//
//Connect the current particle to the second particle over to the right
if (x < numParticlesWide - 2) mSprings.push_back(Spring(getParticle(x,y), getParticle(x+2,y)));
//Connect the current particle to the particle two below
if (y < numParticlesHigh - 2) mSprings.push_back(Spring(getParticle(x,y), getParticle(x, y+2)));
////Create the X pattern
//if (x < numParticlesWide - 2 && y < numParticlesHigh - 2) {
// mSprings.push_back(Spring(getParticle(x, y), getParticle(x+2,y+2)));
// mSprings.push_back(Spring(getParticle(x+2,y), getParticle(x,y+2)));
//};
}
}
//Set the top left and right as stationary
getParticle(0, 0)->makeStationary();
getParticle(numParticlesWide - 1, 0)->makeStationary();
//Make Indices for Particles
for (GLuint row = 0; row < numParticlesWide - 1; ++row) {
for (GLuint col = 0; col < numParticlesHigh - 1; ++col) {
//Triangle one
mParticleIndices.push_back(getParticle(row,col)->getIndex());
mParticleIndices.push_back(getParticle(row,col+1)->getIndex());
mParticleIndices.push_back(getParticle(row+1, col)->getIndex());
//Triangle two
mParticleIndices.push_back(getParticle(row, col+1)->getIndex());
mParticleIndices.push_back(getParticle(row+1, col+1)->getIndex());
mParticleIndices.push_back(getParticle(row+1, col)->getIndex());
}
}
glGenBuffers(1, &clothVertexBufferID);
glGenBuffers(1, &clothIndexBufferID);
sendDataToGPU();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, clothIndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mParticleIndices.size() * sizeof(GLushort), &mParticleIndices[0], GL_STATIC_DRAW);
defineVAO();
std::string shaderDir = generated::ShaderPaths::getShaderDirectory();
std::vector<ShaderInfo> shaders
{
{ GL_VERTEX_SHADER, shaderDir + "Cloth.vs.glsl" },
{ GL_FRAGMENT_SHADER, shaderDir + "Cloth.fs.glsl" }
};
mModel = glm::translate(Matrix4(1.0f), clothPosition);
mShaders.push_back(ShaderPointer(new Shader));
mShaders[0]->compileShaders(shaders);
mShaders[0]->linkShaders();
mUniforms.insert(UniformKey("mvpMat",mShaders[0]->getUniformVariable("mvpMat")));
mShaders[0]->disableShaders();
}
EDIT
I have verified that the totalSpringForcesvariable is indeed changing. I added a print statement in my Particle update function which you can see in the image below. The selected the totalSpringForces for only particle #55 which in this case is the particle immediately under particle 0 which is stationary and not allowed to move. Also the printout is after about 20-25 iterations. As you can see the totalSpringForcesin the y direction has positive value of 0.7037 (i.e. is counteracting gravity). I let it run for half an hour and it only got to 5.
Currently my constants are
k = 2.0f
mass = 0.1f
damping = 0.55f
gravity{ 0.0f, -9.81f, 0.0f },

Rotating Vertex Array Object not working

I am using vertex arrays to store circle vertices and colors.
Here is the setup function:
void setup1(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
// Enable two vertex arrays: co-ordinates and color.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
// Specify locations for the co-ordinates and color arrays.
glVertexPointer(3, GL_FLOAT, 0, Vertices1);
glColorPointer(3, GL_FLOAT, 0, Colors1);
}
The global declaration of the arrays is here:
static float Vertices1[500] = { 0 };
static float Colors1[500] = { 0 };
The arrays are all set up here (R is the radius, X and Y are the (X,Y) center, and t is the angle parameter of the circle)
void doGlobals1()
{
for (int i = 0; i < numVertices1 * 3; i += 3)
{
Vertices1[i] = X + R * cos(t);
Vertices1[i + 1] = Y + R * sin(t);
Vertices1[i + 2] = 0.0;
t += 2 * PI / numVertices1;
}
for (int j = 0; j < numVertices1 * 3; j += 3)
{
Colors1[j] = (float)rand() / (float)RAND_MAX;
Colors1[j + 1] = (float)rand() / (float)RAND_MAX;
Colors1[j + 2] = (float)rand() / (float)RAND_MAX;
}
}
Finally, this is where the shape is drawn.
// Window 1 drawing routine.
void drawScene1(void)
{
glutSetWindow(win1);
glLoadIdentity();
doGlobals1();
glClear(GL_COLOR_BUFFER_BIT);
glRotatef(15, 1, 0, 0);
glDrawArrays(GL_TRIANGLE_FAN, 0, numVertices1);
glFlush();
}
Without the Rotation, the circle draws just fine. The circle also draws fine with any Scale/Translate function. I suspect there is some special protocol necessary to rotate an object drawn with vertex arrays.
Can anyone tell me where I have gone wrong, what I will need to do in order to rotate the object, or offer any advice?
glRotatef(15, 1, 0, 0);
^ why the X axis?
The default ortho projection matrix has pretty tight near/far clipping planes: -1 to 1.
Rotating your circle of X/Y coordinates outside of the X/Y plane will tend to make those points get clipped.
Rotate around the Z axis instead:
glRotatef(15, 0, 0, 1);

How to draw a tapered arc (curve with decreasing thickness) in OpenGL?

I have the following code to draw an arbitrary arc:
void CenteredArc::drawPolygonArc(float radius, float thickness, float startAngle, float arcAngle) {
float num_segments = 360.0;
float radiusOuter = radius + thickness / 2;
float radiusInner = radius - thickness / 2;
float theta = arcAngle / num_segments;
float tangetial_factor = tanf(theta);//calculate the tangential factor
float radial_factor = cosf(theta);//calculate the radial factor
float xxOuter = radiusOuter * cosf(startAngle);
float yyOuter = radiusOuter * sinf(startAngle);
float xxInner = radiusInner * cosf(startAngle);
float yyInner = radiusInner * sinf(startAngle);
float prevXXOuter = -1;
float prevYYOuter = -1;
float prevXXInner = -1;
float prevYYInner = -1;
glPolygonMode(GL_FRONT, GL_FILL);
for(int ii = 0; ii < num_segments; ii++)
{
if (prevXXOuter != -1) {
glBegin(GL_POLYGON);
glVertex2f(prevXXOuter, prevYYOuter);
glVertex2f(xxOuter, yyOuter);
glVertex2f(xxInner, yyInner);
glVertex2f(prevXXInner, prevYYInner);
glEnd();
}
//calculate the tangential vector
//remember, the radial vector is (x, y)
//to get the tangential vector we flip those coordinates and negate one of them
float txOuter = -yyOuter;
float tyOuter = xxOuter;
float txInner = -yyInner;
float tyInner = xxInner;
//add the tangential vector
prevXXOuter = xxOuter;
prevYYOuter = yyOuter;
prevXXInner = xxInner;
prevYYInner = yyInner;
xxOuter += txOuter * tangetial_factor;
yyOuter += tyOuter * tangetial_factor;
xxInner += txInner * tangetial_factor;
yyInner += tyInner * tangetial_factor;
//correct using the radial factor
xxOuter *= radial_factor;
yyOuter *= radial_factor;
xxInner *= radial_factor;
yyInner *= radial_factor;
}
}
However, I would like for the arc to start off with the specified thickness on one end and gradually decrease to a thickness of zero on the other end. Any suggestions?
Edit: I am not using GL_LINE_STRIP because I am trying to avoid having overlapping lines and gaps like so:
I would use a line strip with decreasing glLineWidth.
This is my implementation, it doesn't gradially reduce the lineWidth but it could be modified to do so. Sorry for the extra stuff, it's from my game engine.
for(int i=0;i<arcs().size();i++)
{
Entities::Arc temp = arcs().at(i);
glLineWidth(temp.LW.value); // change LWidth
glColor3f( temp.CL.R, temp.CL.G, temp.CL.B );
// theta is now calculated from the arc angle instead, the
// - 1 part comes from the fact that the arc is open
float theta = temp.A.value*DEG2RAD / float(WW_SPLINE_ACCURACY - 1);
float tan = tanf(theta);
float cos = cosf(theta);
// we are now at the starting angle
double x = temp.R.value * cosf(temp.A.value*DEG2RAD);
double y = temp.R.value * sinf(temp.A.value*DEG2RAD);
// since the arc is not a closed curve, this is a strip now
glBegin(GL_LINE_STRIP);
for(int ii = 0; ii < WW_SPLINE_ACCURACY; ii++)
{
glVertex2d(x + temp.C.X, y + temp.C.Y);
double tx = -y;
double ty = x;
x += tx * tan;
y += ty * tan;
x *= cos;
y *= cos; //y = ( y + (ty*tan) )*cos;
}
glEnd();
glLineWidth(WW_DEFAULT_LWIDTH); // reset LWidth
}
I also used these values
#define WW_SPLINE_ACCURACY 72 // 72 for extra smooth arcs/circles, 32 minimum
#define WW_BEZIER_ACCURACY 20
/* Math stuff */
#define DEG2RAD 3.14159/180
#define PI 3.1415926535897932384626433832795;
...
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glEnable (GL_LINE_SMOOTH);
glEnable (GL_BLEND);
//glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glEnable(GL_POLYGON_SMOOTH);
glClearColor(0.188f, 0.169f, 0.329f, 1.0f); //#302b54
I'm not allowed to release the full source since I wrote it for a company but sharing a part or two wont hurt anybody :D