I am working on soft body simulation. I am trying to do it with OpenGL in c++. However, I have some problems and I could not find anything on the internet. I am using the mass-spring method.
First, I did the simulation in 2d and it worked without a problem. There was a code available. However, when I directly applied it to 3d, it did not and I cannot find the problem. Is it UV sphere? People are using icosahedron sphere, I am aware, however, I cannot figure out how to initialize springs. Since the direction of the springs matter; when I changed the directions in 2d, it does not work. Or it may be the directions of the springs in the UV sphere. Also, I suspect force accumulation and Euler integrator. It may be normals, however, the simulation does not work in the first part where I apply pressure. So to be sure, I changed the normals as vectors from origin to the midpoint of the springs since the ball is located at the origin initially but it fails again. It's been a while since I took a physics course. I put the code below, I know it is not efficient and not well written, but I am interested in making the simulation work, but regardless I appreciate all comments. Anyways, thanks for reading thus far. I wish you all a wonderful day.
mass point initialization
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);
}
Springs initialization
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++;
}
}
volume of the ball
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);
}
force accumulator
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;
}
}
euler integrator
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;
}
}
if you are interested, whole code with shaders.
#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;
}