Hello everyone!
Right now I am writing my own physics engine in java for LWJGL3 3D game and I would like to consult my ideas with you guys. It's not about writing the actual code, but asking if my solution is good, and/or can it be better. And I would like to make it easy to refactor to much others render engine and "game-loop engine". So lets get started!
The base game architecture looks like this:
The Core holds just the information about the game itself, so whenever I decided to write some new game I would just have to edit this module.
The render engine holds just the information about rendering the models, however it only gets the material and mesh data from the model.
The Model module holds 4 basic information about model:
Models - basic Model that holds only information about ModelView, position, rotation and scale. Other types of models inherits it and add unique params (AnimatedModel adds Animation mesh data). ModelView is build of ModelPart which are build from TexturedMeshes (will be explained later).
Loaders - classes to load specific model type (i.e. Assimp loader for *.obj files) and process classes - to create necessary data to render model (ie. create Mesh which holds vboID, vertices/textures/normals arrays etc).
Components - every model can have some component, ie. moveable - which allows to move the object arround the world.
Materials - used together with Mesh to create TexturedMesh. Material holds information about diffuse, ambient, etc colors, diffuse, normal textures.
PhysicsEngine module has the core (initiation of physics world), collision detection, CollidableComponent (inherit from BaseComponent) and Shapes (i.e AABB, Sphere, Cylinder, MeshCollider). This is the part I would like to discuss with you guys (however if you have something to say about other parts - please go for it!).
Core: PhysicState - initiation of physics world, update methods, holds default data (i.e. Default narrow collision shape)
Collision: Broad Phase Collision Detection (BPCD) and Narrow Phase Collision Detection (NPCD)
CollidableComponent - component that can be added to model to make it collidable (in future I was planning to add other components such as: WindComponent for grass model - adds reaction to wind). Only models with CollidableComponent are checked in BPCD and NPCD, the rest are ignored. CollidableComponent has also a boolean isMoveable - i.e. Rock - it is collidable, but its never, ever gonna move. so it doesn't have to be checked with other non-moveable components at BPCD and NPCD.
Shapes - basic shapes and info about them (AABB - points min/max, Sphere - center, radius, etc.)
More info are shown below on diagram:
Right now it works like this:
I create a model and add a CollidableComponent to it like this:
public CollidableComponent(Model model, TypeOfShape typeOfShape, boolean isMoveable)
TypeOfShape declares the basic Broad Phase Collision Shape (AABB, Sphere, Cylinder, Mesh). The Shape is created from the raw data of the model and transformed to actual data (position, rotation*, scale).If I want to I can add the Narrow Phase Collision Shape MAP - which declares the CollisionShape for each Model Part inside the ModelView. In most cases for me it's going to be MeshCollider (since the game I'm planning to create is in Low Poly Style).
IDEA 1: When the CollidableComponent is created it is automatically added to BPCD map to check its collision. Of course it's just temporary, later on I would have to set limit to the map size (i.e. to 500) or split the world to smaller parts and add just the entities which are in this world's part to BPCD. So this is the part where you guys could give me some advice
IDEA 2: Collision Detection update:
Right now the update works like this:
public void update() {
narrowPhase.narrowPhaseCollisionMap.clear();
if (!broadPhaseCollisionMap.isEmpty()) {
for (Model model : broadPhaseCollisionMap.keySet()) {
if ((model.getComponent(CollidableComponent.class)).isMoveable()) {
for (Model model2 : broadPhaseCollisionMap.keySet()) {
if (!model.equals(model2)) {
CollisionShape cs1 = getCollisionShape(model);
CollisionShape cs2 = getCollisionShape(model2);
if (checkCollision(cs1, cs2)) {
narrowPhase.narrowPhaseCollisionMap.add(model);
narrowPhase.narrowPhaseCollisionMap.add(model2);
}
}
}
}
}
}
if (!narrowPhase.narrowPhaseCollisionMap.isEmpty()) {
narrowPhase.update();
}
}
so:
1. It checks if the BPC Map is not empty, and if its not it proceed, else nothing happens.
2. It loops through all the models inside the map and check if it's isMoveable - as I said, I ignore collision detection with objects that doesn't move
3. 2nd loop throught models and check the model from 1st loop isn't the model from the 2nd loop. If they are - lets ignore it.
4. If they are 2 different models it retrieve the BPC shapes from the models and if it is the moveable model it updates its CollisionShape data (by the current the position, rotation,* scale*)
5. Check the intersection between these 2 shapes, and if it true it's added to NPC List
6. After the BPCD loops if the NPC List is not empty it runs its update
The NPCD update is pretty similar to BPCD with just 2 exceptions:
1. It used the List<Models> instead of Map<Model,CollidableComponents> (from models I can retrieve the info about the CollidableComponent, so I might use the List in BPCD aswell instand of Map **)
2. It checks the collision intersection same as for BPCD but for each ModelPart of Model_1 with each ModelPart of Model_2, returns true and/or excact collision point, etc, and breaks this model-model loop check (so it doesn't check if other parts of the models collide with each other).
With my calculations for 50 objects - 27 is static and 23are movable with random position (but some collides): the NP
Took: 0.0ms for: 1224 collision checks and: 24 positive collisions for BPCD
Took: 10. ms for: 55776 collision checks and: 576 positive collisions for NPCD
Took: 11.0ms in total for BPCD and NPCD
I can see a huge space to improve the Collision Detection update methods, but I can't find them, so I hope you guys can help me out Maybe not all models has to be checked in NPCD, i.e. check how far from camera they are, and after some point just ignore NP since it won't be anyhow visible?
Well, that's all! Sorry for a bit long post, but I hope you at least enjoyed reading it
*Actually just forgot about adding it to calculation
**Just came to my head when I was writing this topic
↧