球体碰撞算法总体速度保持递增(C++,OpenGL)
Sphere Collision Algorithm-Overal Velocities Keep increacing (C++, OpenGL)
我的"装满球体粒子的盒子"项目遇到了问题。我创建了一个spheres[number_of_spheres][position,radius,velocity..]数组。边界框(与正交轴平行的边)。与长方体碰撞的球体的速度在碰撞的维度上反转。这还可以。对于球体到球体的碰撞,它非常简单,我通过比较距离和半径的总和来检测碰撞。现在我试图让它们简单地交换碰撞轴上的速度。但模拟运行了一段时间,然后速度不断增加,直到失控。
bool CollisionDetect(int i, int j)
{
if(i==j)
{
return false;
}
float xx = (spheres[i][0]-spheres[j][0])*(spheres[i][0]-spheres[j][0]);
float yy = (spheres[i][1]-spheres[j][1])*(spheres[i][1]-spheres[j][1]);
float zz = (spheres[i][2]-spheres[j][2])*(spheres[i][2]-spheres[j][2]);
if( (xx + yy + zz) <= (spheres[i][3] + spheres[j][3])*(spheres[i][3] + spheres[j][3]) )
{
return true;
}
else
{
return false;
}
}
void CollisionSolve(int i, int j)
{
float m1,m2,m21;
Vec3 vel1,vel2,pos1,pos2; //spheres info
Vec3 nv1n,nv1b,nv1t;
Vec3 nv2n,nv2b,nv2t;
Vec3 N,T,B,X,Y,Z; //collision plane and world orthonormal basis
X.x=1;
X.y=0;
X.z=0;
Y.x=0;
Y.y=1;
Y.z=0;
Z.x=0;
Z.y=0;
Z.z=1;
pos1.x = spheres[i][0];
pos2.x = spheres[j][0];
pos1.y = spheres[i][1];
pos2.y = spheres[j][1];
pos1.z = spheres[i][2];
pos2.z = spheres[j][2];
vel1.x = spheres[i][4];
vel2.x = spheres[j][4];
vel1.y = spheres[i][5];
vel2.y = spheres[j][5];
vel1.z = spheres[i][6];
vel2.z = spheres[j][6];
m1 = spheres[i][8];
m2 = spheres[j][8]; //mass (for later)
N = minus(pos2,pos1); //get N vector (connecting centers of spheres)
N = Normalize(N);
T=X;
B = crossProduct(N,T); //find first perpendicular axis to N
if (B.x==0 && B.y==0 && B.z==0) //then vector parallel to X axis -
{
T=Y; //try Y axis
B = crossProduct(N,T);
}
T = crossProduct(N,B); //find second perpendicular axis to N
T = Normalize(T);
B = Normalize(B);
if (simplespherecollision)
{
nv1n = projectUonV (vel1 , N);
nv2n = projectUonV (vel2 , N);
vel1 = minus (vel1,nv1n);
vel2 = minus (vel2,nv2n);
vel1 = plus (vel1,nv2n);
vel2 = plus (vel2,nv1n);
//simply switch speed (for test)
}
/*/---THIS IS COMMENTED OUT (FIRST METHOD USED - DIDNT WORK)--------------------------------------------
nv1n = projectUonV (vel1 , N);
nv2n = projectUonV (vel2 , N);
nv1t = projectUonV (vel1 , T);
nv2t = projectUonV (vel2 , T);
nv1b = projectUonV (vel1 , B);
nv2b = projectUonV (vel2 , B); //project velocities on new orthonormal basis
vel1 = plus(nv1t , plus(nv1b , nv2n)); //project velocities back to world basis
vel2 = plus(nv2t , plus( nv2b , nv1n)); //by adding the sub vectors with swiched Xn
/*/----------------------------------------------------------------------
spheres[i][4] = vel1.x;
spheres[i][5] = vel1.y;
spheres[i][6] = vel1.z;
spheres[j][4] = vel2.x;
spheres[j][5] = vel2.y;
spheres[j][6] = vel2.z; //reasign velocities to spheres
}
}
这是Vec3结构(以防万一)
struct Vec3
{
float x, y, z;
};
Vec3 crossProduct(const Vec3& v1, const Vec3& v2)
{
Vec3 r;
r.x = (v1.y*v2.z) - (v1.z*v2.y);
r.y = (v1.z*v2.x) - (v1.x*v2.z);
r.z = (v1.x*v2.y) - (v1.y*v2.x);
return r;
}
Vec3 minus(const Vec3& v1, const Vec3& v2)
{
Vec3 r;
r.x = v1.x - v2.x;
r.y = v1.y - v2.y;
r.z = v1.z - v2.z;
return r;
}
Vec3 plus(const Vec3& v1, const Vec3& v2)
{
Vec3 r;
r.x = v1.x + v2.x;
r.y = v1.y + v2.y;
r.z = v1.z + v2.z;
return r;
}
double dotProduct(const Vec3& v1, const Vec3& v2)
{
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
Vec3 scale(const Vec3& v, double a)
{
Vec3 r;
r.x = v.x * a;
r.y = v.y * a;
r.z = v.z * a;
return r;
}
Vec3 projectUonV(const Vec3& u, const Vec3& v)
{
Vec3 r;
r = scale(v,dotProduct(u,v));
return r;
}
int distanceSquared(const Vec3& v1, const Vec3& v2)
{
Vec3 delta = minus(v2, v1);
return dotProduct(delta, delta);
}
Vec3 Normalize (const Vec3& v)
{
Vec3 r;
r=v;
int mag = sqrt(dotProduct(v,v));
r.x = v.x/mag;
r.y = v.y/mag;
r.z = v.z/mag;
return r;
}
这是我的渲染函数,它绘制球体和边界框,并调用其他函数
void Render()
{
//CLEARS FRAME BUFFER ie COLOR BUFFER& DEPTH BUFFER (1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clean up the colour of the window
// and the depth buffer
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-MAX_X/2,-MAX_Y/2,-MAX_Z*4);
glTranslatef (dx,0,dz);
//------------------------------------------------------------------------------------------------
//-----------------------------BOUNDING BOX----------------------------------------------------
glPushMatrix();
glTranslatef(MAX_X/2,MAX_Y/2,MAX_Z/2);
glColor4f(0.9,0.6,0.8,0.3);
glScalef(MAX_X,MAX_Y,MAX_Z);
glutSolidCube(1);
glutWireCube(1);
glPopMatrix();
//-----------------------------WALL COLLISION DETECTION-----ALWAYS ON--------------------------------
for (int i = 0; i<PART_NUM; i++)
{
if(spheres[i][0] > (MAX_X - spheres[i][3]) && spheres[i][4] > 0)
{
spheres[i][4] = spheres[i][4]*-1;
wallcollcount++;
}
if(spheres[i][1] > (MAX_Y - spheres[i][3]) && spheres[i][5] > 0)
{
spheres[i][5] = spheres[i][5]*-1;
wallcollcount++;
}
if(spheres[i][2] > (MAX_Z - spheres[i][3]) && spheres[i][6] > 0)
{
spheres[i][6] = spheres[i][6]*-1;
wallcollcount++;
}
if(spheres[i][0] < spheres[i][3] && spheres[i][4] < 0)
{
spheres[i][4] = spheres[i][4]*-1;
wallcollcount++;
}
if(spheres[i][1] < spheres[i][3] && spheres[i][5] < 0)
{
spheres[i][5] = spheres[i][5]*-1;
wallcollcount++;
}
if(spheres[i][2] < spheres[i][3] && spheres[i][6] < 0)
{
spheres[i][6] = spheres[i][6]*-1;
wallcollcount++;
}
//--------------------------------------Sphere ColDit -------------------------
if (spherecollision || simplespherecollision)
{
for(int j=i+1; j<PART_NUM; j++)
{
if(CollisionDetect(i,j))
{
spherecollcount++;
CollisionSolve(i,j);
}
}
}
//-----------------------------------------------DRAW--------------------------------
glPushMatrix();
glTranslatef(spheres[i][0],spheres[i][1],spheres[i][2]);
glColor3f( (float) (i+1)/(PART_NUM) , 1-(float)(i+1)/(PART_NUM) , 0.5);
glutSolidSphere(spheres[i][3], 18,18);
glPopMatrix();
}
//---------------------------------------------------------------------------------------------------------------/
glutSwapBuffers(); // All drawing commands applied to the
// hidden buffer, so now, bring forward
// the hidden buffer and hide the visible one
}
在碰撞中有两件事是守恒的:
- 动量
和
- 能量
到目前为止,你的计算只考虑动量(简单的速度交换假设了所谓的中心碰撞和相同质量的球体)。如果计算机是无限精确的,这将是完美的。但计算机的精度有限,所以舍入误差会慢慢出现
该问题的简单解决方案是校正动量部分(即质量·速度)的能量偏差(1/2质量·速度²)。这是因为能量取决于速度的平方,所以所涉及的速度上的小偏差会产生大的能量偏差,可以用来校正计算。
即计算碰撞前和碰撞后的总能量。然后取比值sqrt(E_before/E_after),并用它来缩放计算后的速度。
如果你想真正精确,你可以做相对论动量和能量转移;)
相关文章:
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 了解 GLM- openGL 中的相机转换
- 如何在全屏模式下(在OpenGL中)使背景透明
- 为什么我不能使用 EGL 创建无头 OpenGl 上下文?
- OpenGL大的3D纹理(>2GB)非常慢
- OpenGl glm rotate
- C++atioglxx.pdb未加载错误glBufferData OpenGL
- OpenGL在启用深度测试时不会丢弃我的碎片
- OpenGL相机和相机空间转型的困惑
- OpenGL将纹理四边形渲染为(0,0)
- OpenGL 和 GLM 矩阵无法正确扩展,总是按比例缩小
- 发布旋转矩阵(openGL/glm)
- 如何在Visual Basic中使用矩形函数OpenGL绘制矩形
- 无法使用VAO和EBO(openGL)绘制多个对象
- 为什么我的点没有在 OpenGL 中绘制鼠标所在的位置?
- OpenGL 16 位模板缓冲区?
- 将QOpenGLWidget子类转换为使用Metal而不是OpenGL的子类是否可行?
- 在顶点着色器中使用 OpenGl 的未声明标识符,我在顶点着色器中绘制三角形时遇到问题
- 在 openGL 中多次绑定缓冲区
- opengl glBegin(GL_LINES) 和 glBegin(GL_POINT) 在 2D 中不可视化点矢量