Nicholas Harris
Nicholas Harris

Reputation: 103

Java 3D LWJGL collision

I am making a 3D Java game with the LWJGL library, and I was wondering how to add collision detection, so that the player does not go through models.

I am using OBJ models. Here is the OBJLoader class, which loads the models:

package renderEngine;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

import models.RawModel;

import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;

public class OBJLoader {


    public static RawModel loadObjModel(String fileName, Loader loader){
        FileReader fr = null;
        try {
            fr = new FileReader(new File("res/"+fileName+".obj"));
        } catch (FileNotFoundException e) {
            System.err.println("Couldn't load file!");
            e.printStackTrace();
        }
        BufferedReader reader = new BufferedReader(fr);
        String line;
        List<Vector3f> vertices = new ArrayList<Vector3f>();
        List<Vector2f> textures = new ArrayList<Vector2f>();
        List<Vector3f> normals = new ArrayList<Vector3f>();
        List<Integer> indices = new ArrayList<Integer>();
        float[] verticesArray = null;
        float[] normalsArray = null;
        float[] textureArray = null;
        int[] indicesArray = null;
        try{
            while(true){
                line = reader.readLine();
                String[] currentLine = line.split(" ");
                if(line.startsWith("v ")){
                    Vector3f vertex = new Vector3f(Float.parseFloat(currentLine[1]), 
                            Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3]));
                    vertices.add(vertex);
                }else if(line.startsWith("vt ")){
                    Vector2f texture = new Vector2f(Float.parseFloat(currentLine[1]), 
                            Float.parseFloat(currentLine[2]));
                    textures.add(texture);
                }else if(line.startsWith("vn ")){
                    Vector3f normal = new Vector3f(Float.parseFloat(currentLine[1]), 
                            Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3]));
                    normals.add(normal);
                }else if(line.startsWith("f ")){
                    textureArray = new float[vertices.size() * 2];
                    normalsArray = new float[vertices.size() * 3];
                    break;
                }
            }

            while(line != null){
                if(!line.startsWith("f ")){
                    line = reader.readLine();
                    continue;
                }
                String[] currentLine = line.split(" ");
                String[] vertex1 = currentLine[1].split("/");
                String[] vertex2 = currentLine[2].split("/");
                String[] vertex3 = currentLine[3].split("/");

                processVertex(vertex1, indices, textures, normals, textureArray, normalsArray);
                processVertex(vertex2, indices, textures, normals, textureArray, normalsArray);
                processVertex(vertex3, indices, textures, normals, textureArray, normalsArray);
                line = reader.readLine();
            }

            reader.close();
        }catch(Exception e){
            e.printStackTrace();
        }
        verticesArray = new float[vertices.size()*3];
        indicesArray = new int[indices.size()];


        int vertexPointer = 0;
        for(Vector3f vertex:vertices){
            verticesArray[vertexPointer++] = vertex.x;
            verticesArray[vertexPointer++] = vertex.y;
            verticesArray[vertexPointer++] = vertex.z;
        }
        for(int i=0;i<indices.size(); i++){
            indicesArray[i] = indices.get(i);
        }
        return loader.loadToVAO(verticesArray, textureArray, normalsArray, indicesArray);
    }

    private static void processVertex(String[] vertexData, List<Integer> indices, 
            List<Vector2f> textures, 
            List<Vector3f> normals, float[] textureArray, float[] normalsArray){

        int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1;
        indices.add(currentVertexPointer);
        Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1);
        textureArray[currentVertexPointer*2] = currentTex.x;
        textureArray[currentVertexPointer*2+1] = 1 - currentTex.y;
        Vector3f currentNorm = normals.get(Integer.parseInt(vertexData[2])-1);
        normalsArray[currentVertexPointer*3] = currentNorm.x;
        normalsArray[currentVertexPointer*3+1] = currentNorm.y;
        normalsArray[currentVertexPointer*3+2] = currentNorm.z;
    }

}

Thanks!

Upvotes: 4

Views: 2507

Answers (2)

Nick Clark
Nick Clark

Reputation: 1446

I am also in the process of making a game via LWJGL. I use a fairly simple process for determining collisions. First, I find all entities within a certain distance of the focal entity. I use a method like this:

public static float getDistance(Vector3f pointOne, Vector3f pointTwo) {
    float distance = 0;

    float x1 = pointOne.x;
    float y1 = pointOne.y;
    float z1 = pointOne.z;

    float x2 = pointTwo.x;
    float y2 = pointTwo.y;
    float z2 = pointTwo.z;

    distance = (float) Math.pow((Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + Math.pow(z1 - z2, 2)), .5f);

    return distance;
}

Next, I call the method and determine which entities are within a certain radii of the focal entity, and add them to a list.

List<Entity> possibleCollision;
if(distance < radius) {
    possibleCollision.add(entity);
}

Finally, I determine the coordinates of each of the vertices in two different lists. One list is used to store coordinates of the focal entity and the other is to store coordinates of all other entities in the range of possible collision.

List<Vector3f> focal_vertices = new ArrayList<Vector3f>();
//Get Vertices for Focal Entity
focal_verticies.add(vertex);

List<Vector3f> entity_vertices = new ArrayList<Vector3f>();
//Get Vertices for Focal Entity
entity_vertices.add(vertex);

Finally, I run a loop to check the lists contain duplicate entries. This is the most simple part of the system.

for(int i = 0; i < entity_vertices.size() - 1; i++) {

    if(player_vertices.contains(entity_vertices.get(i))) {

        //Collision Detected

    }

}

This works for every OBJ file I have ever tested it with. Hope this helps.

Upvotes: 2

Jode
Jode

Reputation: 92

You have a few options here. The easiest is to simply create an axis-aligned bounding box (AABB) around the object; this can be done algorithmically by simply finding the minimum and maximum values for each axis. For some applications this will work fine, but this obviously isn't very precise. It's worth noting, though, that if two AABBs do not intersect, then the objects themselves definitely don't intersect either; you can use this fact as an early-exit for your collision-checking algorithm.

In addition to bounding boxes, some game engines employ other basic types of bounding volumes, such as bounding spheres. Detecting if a point is in a sphere is as simple as checking if the distance between the center of the sphere and the point is less than or equal to the radius of the sphere. Investigate the bounding volume Wikipedia page for other types. You can often approximate the true boundaries of your object by creating compound bounding volumes -- that is, bounding volumes composed of several simpler volumes, like spheres, boxes, cylinders, etc. This is how the Unity game engine handles collision detection.

You might also want to investigate 2D collision detection algorithms, like the separating axis theorem example (see further reading section). These algorithms can almost always be scaled to higher dimensions.

If all this seems too complicated, I'd recommend picking up a prebaked solution, such as Bullet (Java port). Google around a bit; you'll probably find something that fits your use case. Don't feel bad if you feel overwhelmed; collision detection is a complicated subject backed by decades of research.

Further reading:

Upvotes: 4

Related Questions