我目前正在从事一个项目,该项目涉及使用 3d Simplex 噪声和行进立方体算法以程序方式生成的水下地形。现在我已经制作了我的角色模型并生成了地形网格。由于该项目以水中为基础,因此我想添加鱼和其他实体以使其更加逼真。我已经阅读了关于boids的基础知识,并且已经为实体创建了在 3d 空间中交互的程序。然而,我一直坚持的问题是实体与障碍物交互。本视频中使用的方法是通过在实体周围的球体中投射光线并检测光线是否与障碍物相交。我的想法是根据沿每条射线的间隔检查每个点,直到检测到与三角形面相交的点。我已经有了检查 3d 点是否在三角形面上的代码,所以我的问题是我是否必须沿着每条射线遍历每个点才能计算它是否与三角形相交或者是否有更好的方法对我来说去做吧?
示例代码
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;
}
二维图
这是我希望实体检测的地形: