OpenGL ES 简单的物理检测AABBBOX

首先讲一下AABB BOX的缺陷,AABB BOX 是以正方形的包围盒为基准,包围的范围 即是 一个模型的所有顶点中 x y z 最大值,最小值 ,所以在一个旋转后的物体,可能偏差会比较大,因为AABB BOX 只能计算平行的 碰撞检测

这是一个吧AABBOX 画出现况来的实践,可以明显看出,AABB BOX,永远都是平行的,因为这是简单的判断,碰撞的检测也十分粗略。

OpenGL ES 简单的物理检测AABBBOX_第1张图片
以下是AABBBOX的代码,主要是来自书 OpenGL ES 2.0游戏开发下卷

findMinAndMax, 是对 所有的顶点遍历,找出 AABBBOX的
而GetCurrentAABBbox,则是计算旋转后的,移动后的真实AABBBOX,可以看到这里多了个 currOrientation . orientationData  ,是这样的,计算顶点移动后的位置,自然需要用到 矩阵,所以这里采用的是 直接把 顶点左乘旋转矩阵,获得旋转后的坐标点。

     
     
     
     
package com.bn.Sample5_2;
import android.opengl.Matrix;
public class AABBBox
{
float minX;//x轴最小位置
float maxX;//x轴最大位置
float minY;//y轴最小位置
float maxY;//y轴最大位置
float minZ;//z轴最小位置
float maxZ;//z轴最大位置
public AABBBox(float[] vertices)
{
float[] data=findMinAndMax(vertices);
minX=data[0];maxX=data[1];
minY=data[2];maxY=data[3];
minZ=data[4];maxZ=data[5];
}
public AABBBox(float minX,float maxX,float minY,float maxY,float minZ,float maxZ)
{
this.minX=minX;
this.maxX=maxX;
this.minY=minY;
this.maxY=maxY;
this.minZ=minZ;
this.maxZ=maxZ;
}
//初始化最大最小
public void init(float[] data)
{
data[0]=Float.POSITIVE_INFINITY;
data[1]=Float.NEGATIVE_INFINITY;
data[2]=Float.POSITIVE_INFINITY;
data[3]=Float.NEGATIVE_INFINITY;
data[4]=Float.POSITIVE_INFINITY;
data[5]=Float.NEGATIVE_INFINITY;
}
 
//每个顶点中找出 x y z的最大 最小值,作为AABB BOX
public float[] findMinAndMax(float[] vertices)
{
float[] result=new float[6];
init(result);
for(int i=0;i<vertices.length/3;i++)
{
//判断X轴的最小和最大位置
if(vertices[i*3]<result[0])
{
result[0]=vertices[i*3];
}
if(vertices[i*3]>result[1])
{
result[1]=vertices[i*3];
}
//判断Y轴的最小和最大位置
if(vertices[i*3+1]<result[2])
{
result[2]=vertices[i*3+1];
}
if(vertices[i*3+1]>result[3])
{
result[3]=vertices[i*3+1];
}
//判断Z轴的最小和最大位置
if(vertices[i*3+2]<result[4])
{
result[4]=vertices[i*3+2];
}
if(vertices[i*3+2]>result[5])
{
result[5]=vertices[i*3+2];
}
}
return result;
}
public AABBBox getCurrAABBBox(Vector3f currPosition,Orientation currOrientation)
{
//先计算旋转后的包围盒
Vector3f[] va=
{
new Vector3f(minX,minY,minZ),
new Vector3f(minX,maxY,minZ),
new Vector3f(maxX,minY,minZ),
new Vector3f(maxX,maxY,minZ),
new Vector3f(minX,minY,maxZ),
new Vector3f(minX,maxY,maxZ),
new Vector3f(maxX,minY,maxZ),
new Vector3f(maxX,maxY,maxZ),
};
float[] boxVertices=new float[24];
int count=0;
for(int i=0;i<va.length;i++)
{
float[] result=new float[4];
float[] dot=new float[]{va[i].x,va[i].y,va[i].z,1};
Matrix.multiplyMV(result, 0, currOrientation.orientationData,0,dot, 0);
boxVertices[count++]=result[0];
boxVertices[count++]=result[1];
boxVertices[count++]=result[2];
}
//获取旋转后的包围盒的包围盒!
float[] data=findMinAndMax(boxVertices);
//再计算移动后的包围盒
AABBBox result=new AABBBox
(
data[0]+currPosition.x,
data[1]+currPosition.x,
data[2]+currPosition.y,
data[3]+currPosition.y,
data[4]+currPosition.z,
data[5]+currPosition.z
);
return result;
}
}

配合RIgidBody作简单的物理碰撞,当检测到了碰撞即反向运动。
     
     
     
     
package com.bn.Sample5_2;
import java.util.ArrayList;
 
public class RigidBody
{
LoadedObjectVertexNormal renderObject;//渲染者
AABBBox collObject;//碰撞者
boolean isStatic;
Vector3f currLocation;
Vector3f currV;
Orientation currOrientation;
Wireframe wireframe;
MySurfaceView mv;
public RigidBody(MySurfaceView mv,LoadedObjectVertexNormal renderObject,boolean isStatic,Vector3f currLocation,Vector3f currV,Orientation currOrientation)
{
this.mv = mv;
this.renderObject=renderObject;
collObject=new AABBBox(renderObject.vertices);
this.isStatic=isStatic;
this.currLocation=currLocation;
this.currV=currV;
this.currOrientation=currOrientation;
 
wireframe = new Wireframe(collObject,this.mv);
}
public void drawSelf()
{
MatrixState.pushMatrix();
wireframe.InitVertex(collObject.getCurrAABBBox(currLocation,currOrientation));
wireframe.drawSelf();
//因为旋转后的AABB BOX大小会不一致,所以不能只是简单的跟随位移
MatrixState.translate(currLocation.x, currLocation.y, currLocation.z);
MatrixState.insertSelfMatrix(currOrientation.orientationData);
renderObject.drawSelf();
MatrixState.popMatrix();
}
public void go(ArrayList<RigidBody> al)
{
if(isStatic) return;
currLocation.add(currV);
for(int i=0;i<al.size();i++)
{
RigidBody rb=al.get(i);
if(rb!=this)
{
if(check(this,rb))//检验碰撞
{
this.currV.x=-this.currV.x;//哪个方向的有速度,该方向上的速度置反
}
}
}
}
final float V_UNIT=0.02f;
public boolean check(RigidBody ra,RigidBody rb)//true为撞上
{
float[] over=calOverTotal
(
ra.collObject.getCurrAABBBox(ra.currLocation,ra.currOrientation),
rb.collObject.getCurrAABBBox(rb.currLocation,rb.currOrientation)
);
return over[0]>V_UNIT&&over[1]>V_UNIT&&over[2]>V_UNIT;
}
public float[] calOverTotal(AABBBox a,AABBBox b)
{
float xOver=calOverOne(a.maxX,a.minX,b.maxX,b.minX);
float yOver=calOverOne(a.maxY,a.minY,b.maxY,b.minY);
float zOver=calOverOne(a.maxZ,a.minZ,b.maxZ,b.minZ);
return new float[]{xOver,yOver,zOver};
}
 
//单独判断 一个轴的 左右方向
public float calOverOne(float amax,float amin,float bmax,float bmin)
{
float minMax=0;
float maxMin=0;
if(amax<bmax)//a物体在b物体左侧
{
minMax=amax;
maxMin=bmin;
}
else //a物体在b物体右侧
{
minMax=bmax;
maxMin=amin;
}
if(minMax>maxMin)
{
return minMax-maxMin;
}
else
{
return 0;
}
}
}

物理碰撞,位移(非绘制的位移) ,一般都是要在另外一个逻辑线程中操作的,这不贴出书本上的代码。
逻辑线程与 渲染线程共存时,一定要注意  锁 的问题!

你可能感兴趣的:(OpenGL,ES)