3D碰撞网格(更有效的碰撞计算)

时间:2016-10-18 06:01:19

标签: java 3d collision-detection mesh

在将此标记为重复之前。我希望它知道是的,有类似措辞的标题有一些问题...但是,我已经阅读了它们,它们是截然不同的。

我最近完成了一个完整的系统,用于检测从最小到最复杂的三维网格中的任何位置的碰撞。问题在于它在我的引擎中的游戏体验非常低效且成本非常高。作为旁注,我已经完全编写了这个代码,没有参考,只是为了看看我是否可以自己处理这样的碰撞。对不起这是一团糟。所以不用多说,这是重要的代码。

package nope;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.lwjgl.util.vector.Vector3f;

import net.aionstudios.nightfall.entities.Entity;
import net.aionstudios.nightfall.renderEngine.model.TexturedModel;

public class ColliderEntity extends Entity {

private List<CollisionMesh> entityBounds = new ArrayList<CollisionMesh>();
private boolean alertCollisions = false;

public ColliderEntity(TexturedModel model, Vector3f position, float rotX, float rotY, float rotZ, float scale, BoundingBox entityBounds) {
    super(model, position, rotX, rotY, rotZ, scale);
    this.entityBounds.add(entityBounds);
}

public List<ColliderEntity> detectImpact(List<ColliderEntity> colliders){
    List<ColliderEntity> colE = new ArrayList<ColliderEntity>();
    colE.clear();
    for (ColliderEntity ce : colliders) {
        if(ce != this) {
            Vector3f boundsOffsets = new Vector3f(difference(this.getPosition().x, ce.getPosition().x), difference(this.getPosition().y, ce.getPosition().y), difference(this.getPosition().z, ce.getPosition().z));
            boolean xCollide = false;
            boolean yCollide = false;
            boolean zCollide = false;
            for (CollisionMesh b1 : this.getEntityBounds()){
                for(MeshPoint mp : b1.getPoints()){
                    List<Vector3f> points = mp.getConnectionsAndPoint();
                    for (CollisionMesh b2 : ce.getEntityBounds()) {
                        for(MeshPoint mp2 : b2.getPoints()){
                            List<Vector3f> points2 = mp2.getConnectionsAndPoint();
                            for (Vector3f pt : points2){
                                pt = new Vector3f(pt.x-boundsOffsets.x, pt.y-boundsOffsets.y, pt.z-boundsOffsets.z);
                                for (int i = 1; i < points.size(); i++){
                                    if(!xCollide || !yCollide || !zCollide){
                                        if(points.get(i-1).x > pt.x && pt.x > points.get(i).x) {
                                            xCollide = true;
                                        }
                                        if(points.get(i-1).y > pt.y && pt.y > points.get(i).y) {
                                            yCollide = true;
                                        }
                                        if(points.get(i-1).z > pt.z && pt.z > points.get(i).z) {
                                            zCollide = true;
                                        }
                                    }
                                }
                            }
                            if(!!xCollide || !yCollide || !zCollide){
                                for (Vector3f pts : points){
                                    pts = new Vector3f(pts.x-boundsOffsets.x, pts.y-boundsOffsets.y, pts.z-boundsOffsets.z);
                                    for (int i = 1; i < points2.size(); i++){
                                        if(!xCollide || !yCollide || !zCollide){
                                            if(points2.get(i-1).x > pts.x && pts.x > points2.get(i).x) {
                                                xCollide = true;
                                            }
                                            if(points2.get(i-1).y > pts.y && pts.y > points2.get(i).y) {
                                                yCollide = true;
                                            }
                                            if(points2.get(i-1).z > pts.z && pts.z > points2.get(i).z) {
                                                zCollide = true;
                                            }
                                        }
                                    }
                                }
                            }
                            if(xCollide && yCollide && zCollide){
                                colE.add(ce);
                                if(alertCollisions) {
                                    System.out.println("Collision on Entity "+this.toString()+" at: "+this.getPosition().x+" "+this.getPosition().y+" "+this.getPosition().z+"  with Entity "+ce.toString()+" at: "+ce.getPosition().x+" "+ce.getPosition().y+" "+ce.getPosition().z);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return colE;
}

private float difference(float x, float x1){
    float dx = x - x1;

    return (float) Math.sqrt(dx * dx);
}

public boolean isAlertCollisions() {
    return alertCollisions;
}

public void setAlertCollisions(boolean alertCollisions) {
    this.alertCollisions = alertCollisions;
}

public List<CollisionMesh> getEntityBounds() {
    return entityBounds;
}

public void addEntityBounds(BoundingBox b){
    this.entityBounds.add(b);
}

public void removeEntityBounds(BoundingBox b){
    this.entityBounds.remove(entityBounds);
}

}

这个类只是一个也有碰撞网格的实体......以及影响检测。为了理解这里发生了什么,你需要更多的洞察力。

package nope;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.lwjgl.util.vector.Vector3f;

public class CollisionMesh {

private List<MeshPoint> points = new ArrayList<MeshPoint>();

public CollisionMesh(MeshPoint[] points){
    for(MeshPoint p : points){
        this.points.add(p);
    }
}

public List<MeshPoint> getPoints() {
    return points;
}

public void addMeshPoint(MeshPoint point){
    for (MeshPoint p : points){
        if(point == p){
            return;
        }
    }
    points.add(point);
}

public void removeMeshPoint(MeshPoint point){
    for(MeshPoint p : points){
        if(p == point){
            points.remove(point);
            return;
        }
    }
    cleanupMeshPoints();
}

public void cleanupMeshPoints(){
    for(MeshPoint p : points){
        for(Vector3f pi : p.getConnections()){
            boolean connected = false;
            for(MeshPoint p2 : points){
                if(p2.getPoint() == pi){
                    connected = true;
                }
            }
            if(!connected){
                p.getConnections().remove(pi);
            }
        }
    }
}

}

这是给予可碰撞实体的碰撞网格,它由也存储连接的各个网格点组成。这是班级:

package nope;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.lwjgl.util.vector.Vector3f;

public class MeshPoint {

private Vector3f point;
private List<Vector3f> connections = new ArrayList<Vector3f>();

public MeshPoint(Vector3f point, Vector3f[] connections){
    this.point = point;
    for(Vector3f connection : connections){
        this.connections.add(connection);
    }
}

public Vector3f getPoint() {
    return point;
}

public void setPoint(Vector3f point) {
    this.point = point;
}

public List<Vector3f> getConnections() {
    return connections;
}

public List<Vector3f> getConnectionsAndPoint() {
    List<Vector3f> cp = connections;
    cp.add(this.point);
    return cp;
}

public void addConnection(Vector3f connection){
    for (Vector3f c : connections){
        if(c.x == connection.x && c.y == connection.y && c.z == connection.z){
            return;
        }
    }
    connections.add(connection);
}

public void removeConnection(Vector3f connection){
    for (Vector3f c : connections){
        if(c.x == connection.x && c.y == connection.y && c.z == connection.z){
            connections.remove(connection);
            return;
        }
    }
}

}

网格连接,我认为,实际上是在扼杀游戏的帧速率。当2个框的简单对象启用了冲突时,从120的框架上下降到通常大约3个。虽然我能够识别出几个问题,但我认为无法使这个代码比现在更简单。非常感谢任何帮助。

我知道这样的问题通常不会很受欢迎,很多来这里的人都会寻找一个最小的完整的例子...但是真的没有什么可以做的。使它比它小。

1 个答案:

答案 0 :(得分:1)

建议:

  1. detectImpact不少于6个嵌套周期。难怪性能会受到影响。是否可以减少嵌套数量?如果没有,您是否可以至少预先考虑在这些周期中考虑的数据? (例如,不要考虑所有顶点,只考虑边界框内的那些顶点重叠;并希望边界框交叉点包含大部分顶点 - 如果它们是你的碰撞检测没有在对象变得如此“交织”之前,在前几个阶段做适当的工作。

  2. detectImpact最里面的周期是for (int i = 1; i < points.size(); i++)的形式。 size()在周期中是否会发生变化?如果没有,那么调用泛型接口的(虚拟)方法有什么意义呢?建议:创建一个本地var来存储size并使用它。更好的是,尝试使用foreach / for-in形式,它有better performance than the "iterating by index"(是的,我注意到内部循环从1开始,只是跳过循环内的第一步)。因为这是最里面的循环,所以每个位都有效。

  3. 由于网格的顶点/边/面很少在构造后进行修改,因此请考虑使用数组而不是列表。是的,拥有自动调节容器的灵活性是很好的,但是...没有像免费午餐这样的东西,性能是你为它付钱的钱包。
    也许你可以改进一个将网格对象的生命周期划分为两个不同的阶段:构造(当你向网格添加顶点/边缘时 - 自调整集合在这里很方便)和“冻结/后构建阶段”(当你使用数组而不是容器)。您将获得灵活性和性能,并且您将从“代码复杂性”帐户中付款。