jnsmalm / pixi3d

The 3D renderer for PixiJS. Seamless integration with 2D applications.
https://pixi3d.org
MIT License
759 stars 44 forks source link

How to detect collisions? #45

Closed jimmycrequer closed 3 years ago

jimmycrequer commented 3 years ago

Hello,

Thanks for providing this library, we're trying to migrate our game prototype from 2D to 3D and your library seems great for this purpose!

I was able to show some objects but I don't understand how I should do collision detection. With 2D we would use the object's position with its texture's width and height properties, but there is no texture in a Model object (I have limited knowledge in game dev so this might be an obvious thing).

const drone = stage.addChild(Model.from(resources["drone"]!.gltf));

drone.animations[0]?.play();

console.log(drone.width, drone.height) // => 0 0
console.log(drone.texture) // => undefined

What do you recommend to implement collision detection?

jnsmalm commented 3 years ago

Hello!

Pixi3D doesn't include a way to do the actual collision detection. Depending on how complex you need this to be you can either do it yourself using axis-aligned bounding box (AABB) or use spheres (simple check distance between objects). Or, if you need a more advanced physics you can check https://github.com/kripken/ammo.js/

But, right now it's not super simple reading the bounds of the model/mesh. Here is how I would do it.

let model = Model.from(resources["model.gltf"].gltf)

model.meshes.forEach(mesh => {
   for (let i=0; i<mesh.geometry.positions.length; i+=3) {
      // Here we read a single point in the mesh, we need to find the biggest/smallest x, y and z for all the points.
      let x = mesh.geometry.positions[i]
      let y = mesh.geometry.positions[i + 1]
      let z = mesh.geometry.positions[i + 2]
   }
})

After you have found all the smallest/biggest points, you can from that create a AABB, a sphere or use ammo.js. Hope this helps somewhat.

Also, models can include one or more meshes. Each mesh has a material which may have a texture. The size of the texture doesn't at all say how large the model/mesh is, it's completely unrelated :)

jimmycrequer commented 3 years ago

Thanks for the detailed answer. I'll compute the extreme points and try AABB, sphere and ammo.js with those to see which fits better to our needs.

Thank you!

djlastnight commented 3 years ago

I am using the same code for determing the AABB, I am sharing it here ready for use:

    public getModelBounds(): BoundingBox3D {
        let minX: number = Number.MAX_VALUE;
        let maxX: number = Number.MIN_VALUE;
        let minY: number = Number.MAX_VALUE;
        let maxY: number = Number.MIN_VALUE;
        let minZ: number = Number.MAX_VALUE;
        let maxZ: number = Number.MIN_VALUE;

        for (let i = 0; i < this.model.meshes.length; i++) {
            const mesh = this.model.meshes[i];
            for (let j = 0; j < mesh.geometry.positions.buffer.length; j += 3) {
                const x = mesh.geometry.positions.buffer[j];
                const y = mesh.geometry.positions.buffer[j + 1];
                const z = mesh.geometry.positions.buffer[j + 2];
                minX = Math.min(minX, x);
                maxX = Math.max(maxX, x);

                minY = Math.min(minY, y);
                maxY = Math.max(maxY, y);

                minZ = Math.min(minZ, z);
                maxZ = Math.max(maxZ, z);
            }
        }

        let min = new ObservablePoint3D(() => {}, this, minX, minY, minZ);
        let max = new ObservablePoint3D(() => {}, this, maxX, maxY, maxZ);
        return new BoundingBox3D(min, max);
    }

Here is the AABB class definition:

import { ObservablePoint3D } from "pixi3d";

export default class BoundingBox3D {
    readonly min: ObservablePoint3D;
    readonly max: ObservablePoint3D;

    constructor(min: ObservablePoint3D, max: ObservablePoint3D) {
        this.min = min;
        this.max = max;
    }
}