I am currently working on a project involving procedurally generated underwater terrain using 3d Simplex noise and the marching cubes algorithm. Right now I have made my character model as well as generated the terrain mesh. Since the project is based in the water, I wanted to add fish and other entities to make it more realistic. I have read the basic on boids and have already created the program for entities to interact in a 3d space. However the problem I have been stuck on is having the entities interacting with obstacles. The method used in this video is by casting rays in a sphere around the entity and detecting whether or not a ray is intersecting with the obstacle. My idea is to check each point according to an interval along each ray until I detect a point that is intersecting a triangular face. I already have the code to check whether or not a 3d point is on a triangular face so my question is would I have to loop through each point along each ray in order calculate whether it is intersecting a triangle or is there a better way for me to do it?
Example code
for(Ray ray : rayList){
for(float j = 0; j<raylength; j+= rayinterval){
if(this.checkCollision(ray.getPos(raylenth))){
break;
}else if(j == raylenth-1){
return ray.getAngles();
}
}
}
public boolean checkCollision(Vector3f position){
if(terrain != null){
for(int i = 0; i<terrain.getVertices().length; i+=9){
Vector3f vertex1 = new Vector3f(terrain.getVertices()[i],terrain.getVertices()[i+1],terrain.getVertices()[i+2]);
Vector3f vertex2 = new Vector3f(terrain.getVertices()[i+3],terrain.getVertices()[i+4],terrain.getVertices()[i+5]);
Vector3f vertex3 = new Vector3f(terrain.getVertices()[i+6],terrain.getVertices()[i+7],terrain.getVertices()[i+8]);
if(inTriangle(position, vertex1, vertex2, vertex3)){
return true;
}
}
}
return false;
}
public UVList getUV(Vector3f a, Vector3f b, Vector3f c){
//First, calculate the unit normal vector (cross product).
Vector3f ba = b.subtract(a);
Vector3f ca = c.subtract(a);
Vector3f nn = ba.cross(ca);
float unitVector = (float) Math.sqrt(nn.x*nn.x+nn.y*nn.y+nn.z*nn.z);
Vector3f n = nn.divide(unitVector);
//Calculate the signed distance from origin (dot product).
float d = n.dot(a);
//Calculate the three possible divisors.
float div_xy = a.x*(c.y-b.y) + b.x*(a.y-c.y) + c.x*(b.y-a.y);
float div_xz = a.x*(c.z-b.z) + b.x*(a.z-c.z) + c.x*(b.z-a.z);
float div_yz = a.y*(c.z-b.z) + b.y*(a.z-c.z) + c.y*(b.z-a.z);
float abs_xy = Math.abs(div_xy);
float abs_xz = Math.abs(div_xz);
float abs_yz = Math.abs(div_yz);
Vector3f u,v;
float u0,v0;
if(abs_xy >= abs_xz && abs_xy >= abs_yz){
//d_xy has the largest absolute value; using xy plane
u = new Vector3f((a.y-c.y)/div_xy, (c.x-a.x)/div_xy, 0);
v = new Vector3f((b.y-a.y)/div_xy, (a.x-b.x)/div_xy, 0);
u0 = (a.x*c.y - a.y*c.x)/div_xy;
v0 = (a.y*b.x - a.x*b.y)/div_xy;
}else if( abs_xz >= abs_xy && abs_xz >= abs_yz){
//d_xz has the largest absolute value; using xz plane
u = new Vector3f((a.z-c.z)/div_xz, 0, (c.x-a.x)/div_xz);
v = new Vector3f((b.z-a.z)/div_xz, 0, (a.x-b.x)/div_xz);
u0 = (a.x*c.z - a.z*c.x)/div_xz;
v0 = (a.z*b.x - a.x*b.z)/div_xz;
}else{
//d_yz has the largest absolute value; using yz plane
u = new Vector3f(0, (a.z-c.z)/div_yz, (c.y-a.y)/div_yz);
v = new Vector3f(0, (b.z-a.z)/div_yz, (a.y-b.y)/div_yz);
u0 = (a.y*c.z - a.z*c.y)/div_yz;
v0 = (a.z*b.y - a.y*b.z)/div_yz;
}
return new UVList(u0,v0,u,v,d,n);
}
public class UVList{
Vector3f u,v,n;
float u0, v0,d;
public UVList(float u0, float v0, Vector3f u, Vector3f v,float d,Vector3f n){
this.u = u;
this.v = v;
this.u0 = u0;
this.v0 = v0;
this.d = d;
this.n = n;
}
public Vector3f getN(){
return n;
}
public Vector3f getU(){
return u;
}
public Vector3f getV(){
return v;
}
public float getU0(){
return u0;
}
public float getV0(){
return v0;
}
public float getD(){
return d;
}
}
public boolean inTriangle(Vector3f p, Vector3f v1, Vector3f v2, Vector3f v3){
float ellipse = 1.5f;
UVList uv = getUV(v1,v2,v3);
if(Math.abs(p.dot(uv.getN())-uv.getD()) >= ellipse){
return false;
}
float u = p.dot(uv.getU())+uv.getU0();
float v = p.dot(uv.getV())+uv.getV0();
if(u < 0 || u > 1){
return false;
}
if(v < 0 || v > 1){
return false;
}
if(u+v > 1){
return false;
}
return true;
}
2d diagram
And here is the terrain I want the entities to detect:
terrain
I am fairly new to 3d engines and collision so my code might not be the best.