使用质量弹簧方法模拟UV球的柔体不起作用?(Opengl C+;+;)

使用质量弹簧方法模拟UV球的柔体不起作用?(Opengl C+;+;),opengl,softbody,Opengl,Softbody,我正在进行软体模拟。我尝试用OpenGL在C++中做这件事。然而,我有一些问题,我在网上找不到任何东西。我使用的是质量弹簧法。 首先,我在2d中进行了模拟,它可以毫无问题地工作。有一个可用的代码。然而,当我直接将其应用于3d时,它没有,我也找不到问题。是紫外线球吗?人们正在使用二十面体球体,我知道,但是,我不知道如何初始化弹簧。因为弹簧的方向很重要;当我在2d中更改方向时,它不起作用。或者它可能是UV球体中弹簧的方向。此外,我怀疑力累积和欧拉积分。它可能是法线,但是,模拟在我施加压力的第一部分不

我正在进行软体模拟。我尝试用OpenGL在C++中做这件事。然而,我有一些问题,我在网上找不到任何东西。我使用的是质量弹簧法。
首先,我在2d中进行了模拟,它可以毫无问题地工作。有一个可用的代码。然而,当我直接将其应用于3d时,它没有,我也找不到问题。是紫外线球吗?人们正在使用二十面体球体,我知道,但是,我不知道如何初始化弹簧。因为弹簧的方向很重要;当我在2d中更改方向时,它不起作用。或者它可能是UV球体中弹簧的方向。此外,我怀疑力累积和欧拉积分。它可能是法线,但是,模拟在我施加压力的第一部分不起作用。所以可以肯定的是,我将法线作为向量从原点更改为弹簧的中点,因为球最初位于原点,但它再次失败。我有一段时间没上物理课了。我把代码放在下面,我知道它效率不高,写得不好,但我对使模拟工作感兴趣,但无论如何,我感谢所有的评论。无论如何,谢谢你阅读到目前为止。祝大家度过美好的一天

质点初始化

void
InitPoints()
{
  float dxy = (360.0 * DegreesToRadians) /  CircleVertices;
  float dz  = (360.0 * DegreesToRadians) /  NumCirclesx2;
  points[0] = vec4( 0.0, 1.0, 0.0, 1.0);
  for(int j=1;j<NumCirclesx2/2;j++){
    for(int i=0;i<CircleVertices;i++){
      points[(j-1)*CircleVertices + i+1] = vec4(BALLRADIUS * sin(i * dxy)*sin(j*dz), BALLRADIUS *cos(j*dz), BALLRADIUS *cos(i * dxy)*sin(j*dz), 1.0);
    }
  }
  points[NumVertices-1] = vec4( 0.0, -1.0, 0.0, 1.0);
}
void
InitEdges(){
  int k = 0;
  for(int j=0;j<CircleVertices;j++){
    edges[4*j]   = points[1+j];
    edges[4*j+1] = points[0];

    spring[k].p1 = 0;
    spring[k].p2 = 1+j;
    spring[k].index = 4*j;
    spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
    k++;

    edges[4*j+2] = points[(1+j)];
    spring[k].p1 = 1+j;
    spring[k].index = 4*j+2;

    if(2+j == CircleVertices){
      edges[4*j+3] = points[(2+j)];
      spring[k].p2 = 2+j;
    } 
    else{
      edges[4*j+3] = points[(2+j)%(CircleVertices)];
      spring[k].p2 = (2+j)%(CircleVertices);
    }
    spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
    k++;
  }
  for(int i=1;i<NumCirclesx2/2-1;i++){
    for(int j=0;j<CircleVertices;j++){
      edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
      edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];

      spring[k].p1 = i*CircleVertices+1+j;
      spring[k].p2 = (i-1)*CircleVertices+1+j;
      spring[k].index = i*CircleVertices*4+4*j;
      spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
      k++;

      edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
      spring[k].p1 = i*CircleVertices+1+j;
      spring[k].index = i*CircleVertices*4+4*j+2;

      if(2+j == CircleVertices){
        edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
        spring[k].p2 = i*CircleVertices+(2+j);
      }
      else {
        edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
        spring[k].p2 = i*CircleVertices+(2+j)%CircleVertices;
      }
      spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
      k++;
    }
  }
  for(int j=0;j<CircleVertices;j++){
    edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j]   = points[NumVertices-1];
    edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
    spring[k].p1 = (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1;
    spring[k].p2 = NumVertices-1;
    spring[k].index = (NumCirclesx2/2-1)*CircleVertices*4+2*j;
    spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
    k++;
  }
}
void
InitPoints()
{
浮动dxy=(360.0*度/弧度)/圈;
浮动dz=(360.0*度/弧度)/NumCirclesx2;
点[0]=vec4(0.0,1.0,0.0,1.0);
对于(int j=1;j
float VolumeBall(){
  float minx = 100000,miny = 100000,minz = 100000, maxx = -100000, maxy = -100000, maxz = -100000;
  for(int i = 0; i<NumVertices; i++){
    if(points[i].x < minx) minx = points[i].x;
    if(points[i].y < miny) miny = points[i].y;
    if(points[i].z < minz) minz = points[i].z;
    if(points[i].x > maxx) maxx = points[i].x;
    if(points[i].y > maxy) maxy = points[i].y;
    if(points[i].z > maxz) maxz = points[i].z;
  }
  return (maxx - minx) * (maxz - minz) * (maxy - miny);
}
void AccumulateForces(){
  vec3 point1, point2,point3,point4;
  float r12;
  vec3 v12;
  float f;
  vec3 F;
  vec3 norm;
  bool flag = true;
  float volume=0;
  float pressurev;

  for(int i =0; i<NumVertices; i++){
    mass[i].f.x = 0;
    mass[i].f.z = 0;
    mass[i].f.y = 0;
    if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
  }
  for(int i=0; i<NumEdges/2; i++){
    point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
    point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
    r12 = distance(point1, point2);
    if(r12 != 0){
      v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
      f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
      F = (point1-point2)/r12 * f;
      mass[spring[i].p1].f -= F;
      mass[spring[i].p2].f += F;
    }
    spring[i].n = normalize(point1-point2);
  }
  volume = VolumeBall();
  for(int i=0;i<NumEdges/2;i++){
    point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
    point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
    r12 = distance(point1,point2);

    pressurev = r12 * Pressure * (1.0f/volume);
    mass[spring[i].p1].f += spring[i].n * pressurev;
    mass[spring[i].p2].f += spring[i].n * pressurev;
  }
}void AccumulateForces(){
  vec3 point1, point2,point3,point4;
  float r12;
  vec3 v12;
  float f;
  vec3 F;
  vec3 norm;
  bool flag = true;
  float volume=0;
  float pressurev;

  for(int i =0; i<NumVertices; i++){
    mass[i].f.x = 0;
    mass[i].f.z = 0;
    mass[i].f.y = 0;
    if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
  }
  for(int i=0; i<NumEdges/2; i++){
    point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
    point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
    r12 = distance(point1, point2);
    if(r12 != 0){
      v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
      f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
      F = (point1-point2)/r12 * f;
      mass[spring[i].p1].f -= F;
      mass[spring[i].p2].f += F;
    }
    spring[i].n = normalize(point1-point2);
  }
  volume = VolumeBall();
  for(int i=0;i<NumEdges/2;i++){
    point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
    point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
    r12 = distance(point1,point2);

    pressurev = r12 * Pressure * (1.0f/volume);
    mass[spring[i].p1].f += spring[i].n * pressurev;
    mass[spring[i].p2].f += spring[i].n * pressurev;
  }
}
void IntegrateEuler(){
  float dry,drx,drz;
  for(int i=0;i<NumVertices;i++){
    mass[i].v.x = mass[i].v.x + (mass[i].f.x/Mass) * DT;
    drx = mass[i].v.x * DT;
    if(points[i].x + drx < -SCRSIZE){
      drx = -SCRSIZE - points[i].x;
      mass[i].v.x = -0.1 * mass[i].v.x;
      mass[i].v.y = 0.95 * mass[i].v.y;
      mass[i].v.z = 0.95 * mass[i].v.z;
    }
    if(points[i].x + drx > SCRSIZE){
      drx = SCRSIZE - points[i].x;
      mass[i].v.x = -0.1 * mass[i].v.x;
      mass[i].v.y = 0.95 * mass[i].v.y;
      mass[i].v.z = 0.95 * mass[i].v.z;
    }
    points[i].x = points[i].x + drx;

    mass[i].v.y = mass[i].v.y + (mass[i].f.y/Mass) * DT;
    dry = mass[i].v.y * DT;
    if(points[i].y + dry < -SCRSIZE){
      dry = -SCRSIZE - points[i].y;
      mass[i].v.y = -0.1 * mass[i].v.y;
      mass[i].v.x = 0.95 * mass[i].v.x;
      mass[i].v.z = 0.95 * mass[i].v.z;
    }
    if(points[i].y + dry > SCRSIZE){
      dry = SCRSIZE - points[i].y;
      mass[i].v.y = -0.1 * mass[i].v.y;
      mass[i].v.x = 0.95 * mass[i].v.x;
      mass[i].v.z = 0.95 * mass[i].v.z;
    }
    points[i].y = points[i].y + dry;

    mass[i].v.z = mass[i].v.z + (mass[i].f.z/Mass) * DT;
    drz = mass[i].v.z * DT;
    if(points[i].z + drz < -SCRSIZE){
      drz = -SCRSIZE - points[i].z;
      mass[i].v.z = -0.1 * mass[i].v.z;
      mass[i].v.x = 0.95 * mass[i].v.x;
      mass[i].v.y = 0.95 * mass[i].v.y;
    }
    if(points[i].z + drz > SCRSIZE){
      drz = SCRSIZE - points[i].z;
      mass[i].v.z = -0.1 * mass[i].v.z;
      mass[i].v.x = 0.95 * mass[i].v.x;
      mass[i].v.y = 0.95 * mass[i].v.y;
    }
    points[i].z = points[i].z + drz;
    if(points[i].x > SCRSIZE)
      points[i].x = SCRSIZE;
    if(points[i].y > SCRSIZE)
      points[i].y = SCRSIZE;
    if(points[i].z > SCRSIZE)
      points[i].z = SCRSIZE;
    if(points[i].x < -SCRSIZE)
      points[i].x = -SCRSIZE;
    if(points[i].y < -SCRSIZE)
      points[i].y = -SCRSIZE;
    if(points[i].z < -SCRSIZE)
      points[i].z = -SCRSIZE;  
  }
}
#include "Angel.h"
#define Mass 1.0f
#define KS 1755.0f
#define KD 35.0f
#define GY -10.0f
#define BALLRADIUS 0.516f
#define DT 0.011f
#define FINAL_PRESSURE 85.0f
#define SCRSIZE 7

typedef Angel::vec4  color4;
typedef Angel::vec4  point4;

const int CircleVertices = 8;
const int NumCirclesx2 = 20;
const int NumVertices = CircleVertices * (NumCirclesx2/2-1) + 2;
const int NumEdges = (NumVertices-2)*4+CircleVertices*2;

point4 points[NumVertices];
GLfloat w = 512, h = 512;
//-----------------------------------------------------------------
float xLeft   = -2.0; 
float xRight  = 2.0;
float yBottom = -2.0;
float yTop    = 2.0;
float zNear   = -4.0;
float zFar    = 4.0;
float aspectx = 1;
float aspecty = 1;
//-----------------------------------------------------------------
GLuint vModel;
GLuint vProjection;
GLuint vView;
//------------------------------------------------------------------
typedef struct {
  vec3 v;
  vec3 f;
} PointMass;
typedef struct {
  int p1,p2;
  int index;
  float length;
  vec3 n;
} Spring;
PointMass mass[NumVertices];
Spring spring[NumEdges/2];
float Pressure = 0;
//------------------------------------------------------------------
point4 edges[NumEdges];
point4 b[5];
point4 c[5];
static int k = 0;

//view angle
const float  dr = 5.0 * DegreesToRadians;
float theta = 0;
float phi = 0;


float distance(vec4 a, vec4 b){
  return sqrt((a.x - b.x) * (a.x - b.x)+(a.y - b.y) * (a.y - b.y)+(a.z - b.z) * (a.z - b.z));
}
float distance(vec3 a, vec3 b){
  return sqrt((a.x - b.x) * (a.x - b.x)+(a.y - b.y) * (a.y - b.y)+(a.z - b.z) * (a.z - b.z));
}
float innerprod(vec3 a, vec3 b){
  vec3 c = a * b;
  return c.x+c.y+c.z;
}

void
InitPoints()
{
  float dxy = (360.0 * DegreesToRadians) /  CircleVertices;
  float dz  = (360.0 * DegreesToRadians) /  NumCirclesx2;
  points[0] = vec4( 0.0, 1.0, 0.0, 1.0);
  for(int j=1;j<NumCirclesx2/2;j++){
    for(int i=0;i<CircleVertices;i++){
      points[(j-1)*CircleVertices + i+1] = vec4(BALLRADIUS * sin(i * dxy)*sin(j*dz), BALLRADIUS *cos(j*dz), BALLRADIUS *cos(i * dxy)*sin(j*dz), 1.0);
    }
  }
  points[NumVertices-1] = vec4( 0.0, -1.0, 0.0, 1.0);
}

void
InitEdges(){
  int k = 0;
  for(int j=0;j<CircleVertices;j++){
    edges[4*j]   = points[1+j];
    edges[4*j+1] = points[0];

    spring[k].p1 = 0;
    spring[k].p2 = 1+j;
    spring[k].index = 4*j;
    spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
    k++;

    edges[4*j+2] = points[(1+j)];
    spring[k].p1 = 1+j;
    spring[k].index = 4*j+2;

    if(2+j == CircleVertices){
      edges[4*j+3] = points[(2+j)];
      spring[k].p2 = 2+j;
    } 
    else{
      edges[4*j+3] = points[(2+j)%(CircleVertices)];
      spring[k].p2 = (2+j)%(CircleVertices);
    }
    spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
    k++;
  }
  for(int i=1;i<NumCirclesx2/2-1;i++){
    for(int j=0;j<CircleVertices;j++){
      edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
      edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];

      spring[k].p1 = i*CircleVertices+1+j;
      spring[k].p2 = (i-1)*CircleVertices+1+j;
      spring[k].index = i*CircleVertices*4+4*j;
      spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
      k++;

      edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
      spring[k].p1 = i*CircleVertices+1+j;
      spring[k].index = i*CircleVertices*4+4*j+2;

      if(2+j == CircleVertices){
        edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
        spring[k].p2 = i*CircleVertices+(2+j);
      }
      else {
        edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
        spring[k].p2 = i*CircleVertices+(2+j)%CircleVertices;
      }
      spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
      k++;
    }
  }
  for(int j=0;j<CircleVertices;j++){
    edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j]   = points[NumVertices-1];
    edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
    spring[k].p1 = (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1;
    spring[k].p2 = NumVertices-1;
    spring[k].index = (NumCirclesx2/2-1)*CircleVertices*4+2*j;
    spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
    k++;
    cout << NumVertices-1 << " " << (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1 << endl;
  }
}

void updateEdge(){
  for(int j=0;j<CircleVertices;j++){
    edges[4*j]   = points[1+j];
    edges[4*j+1] = points[0];
    edges[4*j+2] = points[(1+j)];
    if(2+j == CircleVertices){
      edges[4*j+3] = points[(2+j)];
    } 
    else{
      edges[4*j+3] = points[(2+j)%(CircleVertices)];
    }
  }
  for(int i=1;i<NumCirclesx2/2-1;i++){
    for(int j=0;j<CircleVertices;j++){
      edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
      edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];
      edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
      if(2+j == CircleVertices){
        edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
      }
      else {
        edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
      }
    }
  }
  for(int j=0;j<CircleVertices;j++){
    edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j]   = points[NumVertices-1];
    edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
  } 
}

float VolumeBall(){
  float minx = 100000,miny = 100000,minz = 100000, maxx = -100000, maxy = -100000, maxz = -100000;
  for(int i = 0; i<NumVertices; i++){
    if(points[i].x < minx) minx = points[i].x;
    if(points[i].y < miny) miny = points[i].y;
    if(points[i].z < minz) minz = points[i].z;
    if(points[i].x > maxx) maxx = points[i].x;
    if(points[i].y > maxy) maxy = points[i].y;
    if(points[i].z > maxz) maxz = points[i].z;
  }
  return (maxx - minx) * (maxz - minz) * (maxy - miny);
}

void AccumulateForces(){
  vec3 point1, point2,point3,point4;
  float r12;
  vec3 v12;
  float f;
  vec3 F;
  vec3 norm;
  bool flag = true;
  float volume=0;
  float pressurev;

  for(int i =0; i<NumVertices; i++){
    mass[i].f.x = 0;
    mass[i].f.z = 0;
    mass[i].f.y = 0;
    if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
  }
  for(int i=0; i<NumEdges/2; i++){
    point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
    point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
    r12 = distance(point1, point2);
    if(r12 != 0){
      v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
      f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
      F = (point1-point2)/r12 * f;
      mass[spring[i].p1].f -= F;
      mass[spring[i].p2].f += F;
    }
    spring[i].n = normalize(point1-point2);
    // if(flag){
    //   point3 = vec3(points[spring[i+1].p1].x,points[spring[i+1].p1].y,points[spring[i+1].p1].z);
    //   point4 = vec3(points[spring[i+1].p2].x,points[spring[i+1].p2].y,points[spring[i+1].p2].z);
    //   norm = cross(point1-point2, point3-point4);
    //   norm = normalize(norm);
    //   spring[i].n = norm;
    //   flag = false;
    // }
    // else{
    //   spring[i].n = norm;
    //   flag = true;
    // }
  }
  // for(int i=0; i< NumEdges/2; i++){
  //   point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
  //   point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
  //   r12 = distance(point1, point2);
  //   volume += 0.5 * abs(point1.x-point2.x) * abs(spring[i].n.x) * r12;
  // }
  volume = VolumeBall();
  for(int i=0;i<NumEdges/2;i++){
    point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
    point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
    r12 = distance(point1,point2);

    pressurev = r12 * Pressure * (1.0f/volume);
    mass[spring[i].p1].f += spring[i].n * pressurev;
    mass[spring[i].p2].f += spring[i].n * pressurev;
  }
}
void IntegrateEuler(){
  float dry,drx,drz;
  for(int i=0;i<NumVertices;i++){
    mass[i].v.x = mass[i].v.x + (mass[i].f.x/Mass) * DT;
    drx = mass[i].v.x * DT;
    if(points[i].x + drx < -SCRSIZE){
      drx = -SCRSIZE - points[i].x;
      mass[i].v.x = -0.1 * mass[i].v.x;
      mass[i].v.y = 0.95 * mass[i].v.y;
      mass[i].v.z = 0.95 * mass[i].v.z;
    }
    if(points[i].x + drx > SCRSIZE){
      drx = SCRSIZE - points[i].x;
      mass[i].v.x = -0.1 * mass[i].v.x;
      mass[i].v.y = 0.95 * mass[i].v.y;
      mass[i].v.z = 0.95 * mass[i].v.z;
    }
    points[i].x = points[i].x + drx;

    mass[i].v.y = mass[i].v.y + (mass[i].f.y/Mass) * DT;
    dry = mass[i].v.y * DT;
    if(points[i].y + dry < -SCRSIZE){
      dry = -SCRSIZE - points[i].y;
      mass[i].v.y = -0.1 * mass[i].v.y;
      mass[i].v.x = 0.95 * mass[i].v.x;
      mass[i].v.z = 0.95 * mass[i].v.z;
    }
    if(points[i].y + dry > SCRSIZE){
      dry = SCRSIZE - points[i].y;
      mass[i].v.y = -0.1 * mass[i].v.y;
      mass[i].v.x = 0.95 * mass[i].v.x;
      mass[i].v.z = 0.95 * mass[i].v.z;
    }
    points[i].y = points[i].y + dry;

    mass[i].v.z = mass[i].v.z + (mass[i].f.z/Mass) * DT;
    drz = mass[i].v.z * DT;
    if(points[i].z + drz < -SCRSIZE){
      drz = -SCRSIZE - points[i].z;
      mass[i].v.z = -0.1 * mass[i].v.z;
      mass[i].v.x = 0.95 * mass[i].v.x;
      mass[i].v.y = 0.95 * mass[i].v.y;
    }
    if(points[i].z + drz > SCRSIZE){
      drz = SCRSIZE - points[i].z;
      mass[i].v.z = -0.1 * mass[i].v.z;
      mass[i].v.x = 0.95 * mass[i].v.x;
      mass[i].v.y = 0.95 * mass[i].v.y;
    }
    points[i].z = points[i].z + drz;
    if(points[i].x > SCRSIZE)
      points[i].x = SCRSIZE;
    if(points[i].y > SCRSIZE)
      points[i].y = SCRSIZE;
    if(points[i].z > SCRSIZE)
      points[i].z = SCRSIZE;
    if(points[i].x < -SCRSIZE)
      points[i].x = -SCRSIZE;
    if(points[i].y < -SCRSIZE)
      points[i].y = -SCRSIZE;
    if(points[i].z < -SCRSIZE)
      points[i].z = -SCRSIZE;  
  }
}

// OpenGL initialization
void
init()
{
  InitPoints();
  InitEdges();
  GLuint vao;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);

  // Create and initialize a buffer object put all of the object in the same buffer to speed things up
  GLuint buffer;
  glGenBuffers(1, &buffer);
  glBindBuffer(GL_ARRAY_BUFFER, buffer);
  glBufferData(GL_ARRAY_BUFFER, sizeof(edges), NULL, GL_STATIC_DRAW);
  glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(edges), edges);

  // Load shaders and use the resulting shader program
  GLuint program = InitShader("vshader.glsl", "fshader.glsl");
  glUseProgram(program);

  // set up vertex arrays
  GLuint vPosition = glGetAttribLocation(program, "vPosition");
  glEnableVertexAttribArray(vPosition);
  glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0,
    BUFFER_OFFSET(0));

  // uniform variables in the shader
  GLuint vColor = glGetUniformLocation(program, "vColor");
  glUniform4fv(vColor, 1, color4(1.0,0.0,0.0,1.0));
  vView = glGetUniformLocation(program, "vView");
  vProjection = glGetUniformLocation(program, "vProjection");

  //glEnable(GL_DEPTH_TEST);
  glDisable(GL_DEPTH_TEST); 
  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  glClearColor(0.0, 0.0, 0.0, 0.0);
}

//----------------------------------------------------------------------------

void
display(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  point4 at( 0.0, 0.0, 0.0, 1.0 );
  point4 eye( 0.5*sin(theta)*cos(phi), 0.5*sin(phi), -cos(theta)*0.5*cos(phi), 1.0 );
  vec4   up( 0.0, 1.0, 0.0, 0.0 );
  updateEdge();
  glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(edges), edges);
  mat4 view = LookAt( eye, at, up );
  glUniformMatrix4fv(vView, 1, GL_TRUE, view);
  glUniformMatrix4fv(vProjection, 1, GL_TRUE,
  Ortho( -SCRSIZE, SCRSIZE, -SCRSIZE, SCRSIZE, zNear, zFar )); 
    // Ortho( aspectx*xLeft, aspectx*xRight, aspecty*yBottom, aspecty*yTop, zNear, zFar ));
  glDrawArrays(GL_LINES, 0, NumEdges);
  glutSwapBuffers();
}

//----------------------------------------------------------------------------

void
keyboard(unsigned char key, int x, int y)
{
  switch (key) {
  case 'i':
  case 'I': aspectx=aspectx*0.9;aspecty=aspecty*0.9;break;
  case 'o':
  case 'O': aspectx=aspectx*1.1;aspecty=aspecty*1.1;break;
  case 033: // Escape Key
  // 'q' exits
  case 'q': case 'Q': exit(EXIT_SUCCESS);            break;
  }
}

//----------------------------------------------------------------------------
//special keyboard function catches special keyboard inputs such as arrow keys.
void SpecialKeyboard(int key, int x, int y)
{
  switch (key)
  {
    case GLUT_KEY_LEFT: theta += dr; break;
    case   GLUT_KEY_RIGHT: theta -= dr; break;
    case GLUT_KEY_UP: phi += dr; break;
    case   GLUT_KEY_DOWN: phi -= dr; break;
  }
  glutPostRedisplay();
}

//----------------------------------------------------------------------------
void timer(int)
{
  AccumulateForces();
  IntegrateEuler();
  if(Pressure < FINAL_PRESSURE)
  {
  Pressure += FINAL_PRESSURE/100.0f;
    printf("Pressure = %4.4f\n",Pressure);
  } 
  glutPostRedisplay();
  glutTimerFunc(1000, timer, 0);
}
// void
// idle(void)
// {
//   AccumulateForces();
//   IntegrateEuler();
//   if(Pressure < FINAL_PRESSURE)
//   {
//   Pressure += FINAL_PRESSURE/100.0f;
//     printf("Pressure = %4.4f\n",Pressure);
//   } 
//   glutPostRedisplay();
// }
//----------------------------------------------------------------------------
void reshape(GLsizei ww, GLsizei hh)
{
    glViewport( 0, 0, ww, hh );
    aspectx = (GLfloat)ww/w;
    aspecty = (GLfloat)hh/h;
    w = ww;
    h = hh;
}

int
main(int argc, char **argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
  glutInitWindowSize(512, 512);
  glutInitContextVersion(3, 2);
  glutInitContextProfile(GLUT_CORE_PROFILE);
  glutCreateWindow("Free Fall");

  glewExperimental = GL_TRUE;
  glewInit();

  init();

  glutDisplayFunc(display);
  glutKeyboardFunc(keyboard);
  glutSpecialFunc(SpecialKeyboard);
  glutTimerFunc(1000.0/60.0, timer, 0);
  // glutIdleFunc(idle);
  glutReshapeFunc(reshape);

  glutMainLoop();
  return 0;
}

#version 150

in  vec4 vPosition;
uniform  vec4 vColor;
uniform mat4 vView;
uniform mat4 vProjection;
out vec4 color;

void main() 
{
  gl_Position = vProjection*vView*vPosition;
  color = vColor;
} 

#version 150

in  vec4 color;
out vec4 fColor;

void main() 
{ 
    fColor = color;

}