Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions 119. Coders
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
🧩 Project Description

This is a 3D Collision Detection Visualizer using JavaFX and an Octree for efficient spatial partitioning. It simulates moving 3D objects, each with an Axis-Aligned Bounding Box (AABB), and detects collisions in real-time.

Objects are rendered in blue (no collision) or red (collision). The Octree reduces collision checks by dividing 3D space into regions, improving performance over brute-force methods.

📚 Data Structures Used

Octree: Recursively divides space into 8 parts to group nearby objects.

Array / ArrayList: Store and manage objects and Octree nodes.

✨ Features

Real-time 3D rendering and animation

Efficient Octree-based collision detection

Color-coded visual feedback (Red = collision, Blue = safe)

VIDEO LINK: https://drive.google.com/file/d/1O3x9IcfQH3LUiAb3lu90aQele8Lq5sH_/view?usp=sharing
17 changes: 17 additions & 0 deletions AABB.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package buffer.core;

public class AABB {
public double minX, minY, minZ;
public double maxX, maxY, maxZ;

public AABB(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
this.minX = minX; this.minY = minY; this.minZ = minZ;
this.maxX = maxX; this.maxY = maxY; this.maxZ = maxZ;
}

public boolean intersects(AABB other) {
return (this.maxX >= other.minX && this.minX <= other.maxX) &&
(this.maxY >= other.minY && this.minY <= other.maxY) &&
(this.maxZ >= other.minZ && this.minZ <= other.maxZ);
}
}
82 changes: 82 additions & 0 deletions CollisionViewer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package buffer.visualization;
import java.util.List;
import buffer.core.*;//Imports GameObject, Octree, AABB classes.
import javafx.scene.*;//for rendering 3d objects
import javafx.scene.paint.*;//for colors
import javafx.scene.shape.*;//for shapes
import javafx.animation.AnimationTimer;//runs a loop that updates the simulation every frame 60fps

public class CollisionViewer {//this class initialised 3d objects visualises gameObjects
// and collision using octree
private Group root = new Group();
//group is root node of 3d scene to which all the objects are added
private Octree octree = new Octree(new AABB(-50, -50, -50, 50, 50, 50));
//spatial tree that contains the simulation bounds
private GameObject[] objects = new GameObject[20];
//20 cubes stored in this array

public CollisionViewer() {//constructor
//each cube is being initialised randomly within a cube space
for (int i = 0; i < objects.length; i++) {
objects[i] = new GameObject(
Math.random() * 80 - 40,
Math.random() * 80 - 40,
Math.random() * 80 - 40,
1.0
);
}
}

public Parent createContent() {
//this method sets up and starts animation (render loop)
//returns node, which is the main scene node
// FIXED: Added FPS control to AnimationTimer
new AnimationTimer() {//animation timer is javafx class that lets you run code every frame
private long lastTime = 0;

@Override
public void handle(long now) {
if (now - lastTime < 16_666_666) return; // Strict 60 FPS
update();
lastTime = now;
}
}.start();

return root;
}

private void update() {
//this is the main loop
//this update positions ,check the collisions , and renders cubes
root.getChildren().clear();
//clears previous cubes from the scene so that we can see current positions
octree = new Octree(new AABB(-50, -50, -50, 50, 50, 50));
//resets octree every frame

// Update and check collisions
for (GameObject obj : objects) {
obj.update();
octree.insert(obj);

List<GameObject> candidates = octree.query(obj.bounds);
//Returns a short list of potential colliders
obj.isColliding = false;
for (GameObject other : candidates) {
if (obj != other && obj.bounds.intersects(other.bounds)) {
obj.isColliding = true;
break;
}
}
}

// Render objects
for (GameObject obj : objects) {
Box box = new Box(2, 2, 2);
box.setTranslateX(obj.x);
box.setTranslateY(obj.y);
box.setTranslateZ(obj.z);
box.setMaterial(new PhongMaterial(obj.isColliding ? Color.RED : Color.BLUE));
root.getChildren().add(box);
}
}
}
35 changes: 35 additions & 0 deletions GameObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package buffer.core;
import java.lang.Math;
public class GameObject {
public double x, y, z;
public AABB bounds;
public boolean isColliding = false;

public GameObject(double x, double y, double z, double size) {
this.x = x; this.y = y; this.z = z;
this.bounds = new AABB(x - size, y - size, z - size, x + size, y + size, z + size);
}

// public void update() {
// // Simple random movement (replace with physics later)
// x += Math.random() * 0.1 - 0.05;
// y += Math.random() * 0.1 - 0.05;
// z += Math.random() * 0.1 - 0.05;

// // Update bounding box
// double size = 1.0;
// bounds = new AABB(x - size, y - size, z - size, x + size, y + size, z + size);
// }
public void update() {
x += (Math.random() * 2 - 1); // Increased from 0.1 to 1
y += (Math.random() * 2 - 1);
z += (Math.random() * 2 - 1);

// Keep within bounds
x = Math.max(-40, Math.min(40, x));
y = Math.max(-40, Math.min(40, y));
z = Math.max(-40, Math.min(40, z));

bounds = new AABB(x-1, y-1, z-1, x+1, y+1, z+1);
}
}
33 changes: 33 additions & 0 deletions MainApp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package buffer.visualization;

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class MainApp extends Application {
public static void main(String[] args) {
launch(args);
// The main() method launches the app. i.e starts javafx 3d application
}


@Override
public void start(Stage stage) {
try {
CollisionViewer viewer = new CollisionViewer();
Scene scene = new Scene(viewer.createContent(), 800, 600, true);
PerspectiveCamera camera = new PerspectiveCamera(true);
//Makes objects look 3D (not flat).
camera.setTranslateZ(-50);
//moves camera back so we can see the scene(like zooming out)
scene.setCamera(camera);
stage.setScene(scene);
//displaying everything
stage.show();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
63 changes: 63 additions & 0 deletions Octree.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package buffer.core;

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

public class Octree {
private AABB bounds;
private List<GameObject> objects; //stores the blue boxes
private Octree[] children;//subdivisions of transparent outer box
private boolean isDivided = false;//flag which checks if the bound is subdivided

public Octree(AABB bounds) {
this.bounds = bounds;
this.objects = new ArrayList<>();
}

public void insert(GameObject obj) {
if (!bounds.intersects(obj.bounds)) return;

if (!isDivided && objects.size() < 4) {
objects.add(obj);
} else {
if (!isDivided) subdivide();
for (Octree child : children) child.insert(obj);
}
}

private void subdivide() { //divides space into octant when no of boxes in particular
// octant are more than 4
double midX = (bounds.minX + bounds.maxX) / 2;//calculating centre of the cube (com)
double midY = (bounds.minY + bounds.maxY) / 2;
double midZ = (bounds.minZ + bounds.maxZ) / 2;

children = new Octree[8];
// Initialize ALL 8 children
children[0] = new Octree(new AABB(bounds.minX, bounds.minY, bounds.minZ, midX, midY, midZ));
children[1] = new Octree(new AABB(midX, bounds.minY, bounds.minZ, bounds.maxX, midY, midZ));
children[2] = new Octree(new AABB(bounds.minX, midY, bounds.minZ, midX, bounds.maxY, midZ));
children[3] = new Octree(new AABB(midX, midY, bounds.minZ, bounds.maxX, bounds.maxY, midZ));
children[4] = new Octree(new AABB(bounds.minX, bounds.minY, midZ, midX, midY, bounds.maxZ));
children[5] = new Octree(new AABB(midX, bounds.minY, midZ, bounds.maxX, midY, bounds.maxZ));
children[6] = new Octree(new AABB(bounds.minX, midY, midZ, midX, bounds.maxY, bounds.maxZ));
children[7] = new Octree(new AABB(midX, midY, midZ, bounds.maxX, bounds.maxY, bounds.maxZ));

isDivided = true;//flag that stores if particular octant was subdivided or not
}

public List<GameObject> query(AABB range) {
List<GameObject> found = new ArrayList<>();
if (!bounds.intersects(range)) return found;

for (GameObject obj : objects) {
if (range.intersects(obj.bounds)) found.add(obj);
}

if (isDivided) {
for (Octree child : children) {
found.addAll(child.query(range));
}
}
return found;
}
}
30 changes: 24 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
# Buffer-6.0
Group no.119

The themes for Buffer 6.0 are -
Group name: Coders

1. FinTech
Theme: Custom Datastructure

2. Women Safety
Project Name:3D Collision Detection Visualiser

3. Next-Gen Academic Solutions
🧩 Project Description

4. Custom Data Structure
This is a 3D Collision Detection Visualizer using JavaFX and an Octree for efficient spatial partitioning. It simulates moving 3D objects, each with an Axis-Aligned Bounding Box (AABB), and detects collisions in real-time.

Objects are rendered in blue (no collision) or red (collision). The Octree reduces collision checks by dividing 3D space into regions, improving performance over brute-force methods.

📚 Data Structures Used

Octree: Recursively divides space into 8 parts to group nearby objects.

Array / ArrayList: Store and manage objects and Octree nodes.

✨ Features

Real-time 3D rendering and animation

Efficient Octree-based collision detection

Color-coded visual feedback (Red = collision, Blue = safe)

VIDEO LINK: https://drive.google.com/file/d/1O3x9IcfQH3LUiAb3lu90aQele8Lq5sH_/view?usp=sharing