Skip to content

Ray-tracing 3D rendering engine in Java. Implements geometric intersections, lighting models, shadows, and reflections using design patterns and TDD.

Notifications You must be signed in to change notification settings

Noammandelbaum/Advanced-3D-Graphics-Rendering-Engine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

22 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

3D Ray Tracing Engine with Anti-Aliasing

Java JUnit OOP

Ray Tracer Engine - Realistic Piano Scene

Complex algorithms, clean architecture, photorealistic results

View Project Journey β€’ Technical Architecture β€’ Anti-Aliasing


🎯 The Story Behind the Code

The Question: How do computers generate realistic 3D images? How does a sphere "know" it should look round? How does light "know" how to bounce?

This project started as an academic assignment in Introduction to Software Engineering. But somewhere between calculating ray-sphere intersections and debugging reflection vectors, it became something more: a deep dive into algorithmic thinking and software architecture.

The Challenge

"Build a system where math, physics, and code come together to create something beautiful."

When you're rendering photorealistic images, precision is everything:

  • Mathematical precision – one misplaced sign and your shadows point the wrong way
  • Architectural clarity – 10+ geometry types, 4 light sources, recursive reflections... all working together
  • Rigorous testing – every feature needs tests, because visual bugs are expensive to debug

✨ What It Does

A full-featured 3D rendering engine that traces light rays through a virtual scene to generate photorealistic images:

Scene scene = new Scene("My First Render");

// Build the world
scene.geometries.add(
    new Sphere(50, new Point(0, 0, -200))
        .setEmission(new Color(100, 50, 50))
        .setMaterial(new Material()
            .setKD(0.5).setKS(0.5).setShininess(100)
            .setKR(0.3))  // 30% reflective
);

// Add lights
scene.lights.add(
    new SpotLight(new Color(400, 240, 0), new Point(60, 50, 0),
                  new Vector(-1, -1, -2))
        .setKL(0.00001).setKQ(0.000005)
);

// Render with anti-aliasing
Camera camera = Camera.getBuilder()
    .setLocation(new Point(0, 0, 1000))
    .setDirection(new Vector(0, 0, -1), new Vector(0, 1, 0))
    .setVPDistance(1000).setVPSize(200, 200)
    .setImageWriter(new ImageWriter("myRender", 800, 800))
    .setRayTracer(new SimpleRayTracer(scene))
    .setSamplingConfig(new SamplingConfig()
        .enableAntiAliasing(81, 1.0, SamplingPattern.JITTERED))
    .build();

camera.generateRenderedImage().writeToImage();

Result: A photorealistic image with smooth edges, realistic lighting, and reflections.

Complete Scene Render

A complete scene showcasing the engine's capabilities: spheres with reflections, transparent triangles, realistic shadows, and multiple light sources working together.


πŸ† Key Achievement: Super-Sampling Anti-Aliasing

Visual Comparison

No Anti-Aliasing

No Anti-Aliasing
❌ Jagged edges
❌ Pixelated curves
1 ray per pixel

Standard AA - 81 samples

Standard AA (81 samples)
βœ… Smooth edges
βœ… Natural curves
~40Γ— slower, excellent quality

High Quality AA - 324 samples

High Quality (324 samples)
βœ… Professional quality
βœ… Production-ready
~160Γ— slower, outstanding

Notice how the edges become progressively smoother as we increase the number of sample rays per pixel. This is the power of super-sampling anti-aliasing.

The Implementation

File: src/renderer/superSampling/

The anti-aliasing system uses Jittered Sampling (a bonus feature):

// Generate 81 rays around the intersection point
List<Ray> rays = antiAliasingSampler.generateSampleRays(
    intersection.point, primaryRay);

// Trace each ray and average the colors
List<Color> colors = new ArrayList<>();
for (Ray ray : rays) {
    GeoPoint intersection = findClosestIntersection(ray);
    colors.add(intersection == null ? scene.background :
               traceSimpleRay(ray, intersection));
}

return calculateAverageColor(colors);

Why Jittered? Combines the benefits of grid sampling (even coverage) with random sampling (avoids repetitive artifacts).

Performance Comparison

Configuration Samples/Pixel Render Time Quality Use Case
No AA 1 Baseline Standard Debugging
Standard AA 81 (9Γ—9) ~40Γ— slower Excellent Demo images
High Quality 324 (18Γ—18) ~160Γ— slower Outstanding Final renders

πŸ› οΈ Technical Architecture

Design Patterns Implemented

The codebase showcases 7 design patterns, demonstrating architectural maturity:

Pattern Location Purpose
Builder Camera.Builder Fluent API for developer empathy and robust validation
Strategy SamplingPattern enum Pluggable sampling algorithms (JITTERED, RANDOM)
Composite Geometries class Treat single/multiple geometries uniformly
Template Method RayTracerBase Define ray tracing skeleton
Null Object AmbientLight.NONE Eliminate null checks
Factory Method SamplingPattern.generate() Create sample points by pattern
Flyweight Point.ZERO, Color.BLACK Share immutable objects

Package Structure

src/
β”œβ”€β”€ primitives/         # Math foundation
β”‚   β”œβ”€β”€ Point.java
β”‚   β”œβ”€β”€ Vector.java     ← createPerpendicular() for sampling
β”‚   β”œβ”€β”€ Ray.java
β”‚   β”œβ”€β”€ Color.java
β”‚   └── Material.java
β”œβ”€β”€ geometries/         # 3D shapes
β”‚   β”œβ”€β”€ Sphere.java
β”‚   β”œβ”€β”€ Triangle.java
β”‚   β”œβ”€β”€ Plane.java
β”‚   β”œβ”€β”€ Cylinder.java
β”‚   └── Geometries.java (Composite)
β”œβ”€β”€ lighting/           # Light sources
β”‚   β”œβ”€β”€ AmbientLight.java
β”‚   β”œβ”€β”€ DirectionalLight.java
β”‚   β”œβ”€β”€ PointLight.java
β”‚   └── SpotLight.java
β”œβ”€β”€ renderer/           # Core rendering
β”‚   β”œβ”€β”€ Camera.java     ← Builder Pattern
β”‚   β”œβ”€β”€ SimpleRayTracer.java
β”‚   └── superSampling/  ← β˜… Anti-Aliasing System β˜…
β”‚       β”œβ”€β”€ SuperSampling.java
β”‚       β”œβ”€β”€ SamplingPattern.java (Strategy)
β”‚       β”œβ”€β”€ SamplingConfig.java
β”‚       └── TargetArea.java
└── scene/
    └── Scene.java      (Plain Data Structure)

πŸ§ͺ Quality Assurance

Test-Driven Development

100+ unit tests written using JUnit 5:

unitTests/
β”œβ”€β”€ primitives/          # Point, Vector, Ray tests
β”œβ”€β”€ geometries/          # Intersection accuracy tests
β”œβ”€β”€ renderer/
β”‚   β”œβ”€β”€ CameraTests.java
β”‚   β”œβ”€β”€ ShadowTests.java
β”‚   β”œβ”€β”€ ReflectionRefractionTests.java
β”‚   └── superSampling/
β”‚       β”œβ”€β”€ AntiAliasingTest.java          ← 3-way comparison
β”‚       β”œβ”€β”€ SuperSamplingTests.java
β”‚       └── SamplingPatternTests.java
└── bigScenes/
    β”œβ”€β”€ RealisticPianoFinal.java           ← 30 samples
    β”œβ”€β”€ CoffeeCupScene.java
    β”œβ”€β”€ HouseScene.java
    └── SunflowerScene.java

Example: Anti-Aliasing Test (AntiAliasingTest.java)

@Test
public void runCompleteAntiAliasingTest() {
    // Render 3 versions of the same scene
    long noAATime = renderWithoutAntiAliasing();
    long standardAATime = renderWithStandardAntiAliasing();  // 81 samples
    long highAATime = renderWithHighQualityAntiAliasing();    // 324 samples

    // Output performance comparison
    printPerformanceSummary(noAATime, standardAATime, highAATime);
}

Output:

====================================
        PERFORMANCE SUMMARY
====================================
No Anti-Aliasing:       1,203 ms
Standard AA (81):      48,560 ms (40.4x slower)
High Quality AA (324): 194,832 ms (162.0x slower)

MP1 Requirements fulfilled:
βœ“ 10+ geometric bodies
βœ“ 3 different light sources
βœ“ Anti-aliasing ON/OFF capability
βœ“ 50+ sample rays
βœ“ Performance timing measurements
====================================

🎨 Features

Rendering Capabilities

  • Ray-Geometry Intersections – Sphere, Plane, Triangle, Polygon, Cylinder, Tube
  • Phong Lighting Model – Ambient + Diffuse + Specular components
  • Multiple Light Sources – Ambient, Directional, Point, Spot lights with attenuation
  • Shadows – Shadow ray casting with transparency support
  • Recursive Ray Tracing – Reflections (kR) and refractions (kT) up to 10 levels
  • Material Properties – kD (diffuse), kS (specular), nShininess, kR (reflection), kT (transparency)
  • Super-Sampling Anti-Aliasing – JITTERED and RANDOM patterns
  • Camera Builder – Fluent API with validation
  • Scene Composition – Multiple geometries and lights with Composite pattern
  • Image Export – PNG output with customizable resolution

Code Quality

  • 7 Design Patterns – Builder, Strategy, Composite, Template Method, Null Object, Factory, Flyweight
  • SOLID Principles – Single Responsibility, Open/Closed, Liskov Substitution, Dependency Inversion
  • Defensive Programming – Input validation on every public method
  • Comprehensive JavaDoc – All classes and methods documented
  • 100+ Unit Tests – JUnit 5 with EP/BVA testing strategies
  • Immutable Primitives – Thread-safe Point, Vector, Ray, Color. No side effects, easier testing

πŸ“Έ Demo Images

Lighting Techniques

Rainbow Lighting Effect

Multiple colored lights create a rainbow effect on a reflective sphere

Complex Multi-Light Scene

Three light sources (blue, yellow, white) illuminate geometric shapes

Shadow Progression

Shadow Initial

Base configuration

Shadow Move 1

Light position adjusted

Shadow Move 2

Dynamic shadow casting

Demonstrating how shadows change realistically as light sources move through the scene.


πŸš€ Getting Started

Prerequisites

  • Java 17 or higher
  • JUnit 5 (included in project)

Running the Examples

  1. Clone the repository

    git clone https://github.com/Noammandelbaum/ISE5784_1674.git
    cd ISE5784_1674
  2. Compile the project

    javac -d out src/**/*.java
  3. Run a demo scene

    java -cp out bigScenes.RealisticPianoFinal
  4. Run tests

    # From your IDE (IntelliJ IDEA / Eclipse):
    # Right-click on unitTests folder β†’ Run All Tests
  5. View generated images

    # Images are saved to the images/ directory
    open images/antiAliasing/with_antialiasing_81_samples.png

πŸ“š What I Learned

Technical Depth

  • Linear Algebra in Practice – Dot products, cross products, vector normalization aren't just theory
  • Floating-Point Precision – Why alignZero() is critical for numerical stability
  • Recursive Algorithms – Balancing depth vs. performance (MAX_LEVEL = 10, MIN_K = 0.001)
  • Performance Optimization – Understanding the cost of each ray (81Γ— slowdown = need for optimization)

Software Engineering

  • TDD Discipline – Writing tests first prevents expensive visual debugging
  • Builder Pattern Value – Compare new Camera(8 params) vs. fluent API
  • Strategy Pattern Flexibility – Added JITTERED pattern without changing existing code
  • Defensive Programming – Input validation prevents silent failures

Quality Mindset

"The best code isn't the cleverest – it's the code you can trust in 6 months."

This principle guided every decision:

  • Named variables clearly (pixelColumnIndex not j)
  • Validated inputs explicitly (throw IllegalArgumentException with clear messages)
  • Tested edge cases obsessively (colinear points, zero vectors, parallel rays)
  • Documented intent with JavaDoc (not just "what" but "why")

Build quality in from the start – don't patch it later.


🎬 Project Journey: From Primitives to Photorealism

Exercise 1-2: Foundation - Geometries & Ray Intersections

Basic Geometries

First successful render: Basic sphere, plane, and triangle with simple color emission. This proved the core ray-intersection math was correct.

Exercise 5-6: Adding Realism - Lighting Models

Directional Light

Directional Light

Point Light

Point Light with Attenuation

Spot Light

Spot Light with Direction

Implemented the Phong reflection model with three types of light sources. Each light type required different attenuation calculations.

Exercise 7: Shadows - Adding Depth

Hard Shadows

Hard shadows with opaque objects

Soft Shadows

Soft shadows through transparent objects

Shadow rays revealed which objects block light. Transparent materials (kT > 0) create soft, realistic shadows.

Exercise 7: Reflections & Refractions - Recursive Ray Tracing

Reflections

Mirror-like reflections (kR = 0.9)

Refractions

Glass-like transparency (kT = 0.8)

Recursive ray tracing up to 10 levels. Each reflection/refraction spawns a new ray, creating stunning realism but requiring careful performance management.

Exercise 8 (Mini-Project 1): Anti-Aliasing - The Finishing Touch

See the Anti-Aliasing section above for the full before/after comparison.

Final Achievement: Complex Scenes

Realistic Piano

Realistic Upright Piano
50+ primitives, reflection materials, realistic lighting and shadows

House Scene

Architectural Scene
Multiple geometries, complex lighting, shadows

From a single sphere to photorealistic scenes - 8 exercises, countless tests, one powerful engine.


πŸ”— Clean Code Principles in Practice

Developer-Friendly API Design

Builder Pattern for Complex Objects:

// Bad: Constructor with 8 parameters - easy to mix up
Camera camera = new Camera(p0, vTo, vUp, width, height, distance, imageWriter, rayTracer);

// Good: Builder with validation - clear and safe
Camera camera = Camera.getBuilder()
    .setLocation(new Point(0, 0, 0))
    .setDirection(new Vector(0, 0, -1), new Vector(0, 1, 0))
    .setVPSize(200, 200)
    .build();  // Validates all required fields

Defensive Programming

Clear Error Messages:

if (numSamples < 1) {
    throw new IllegalArgumentException("Number of samples must be at least 1");
}

Performance Awareness

Transparent Benchmarking:

System.out.println("Standard AA (81): 48,560 ms (40.4x slower)");

Real performance data helps make informed tradeoffs between quality and speed.

Code Quality Highlights

  • 100+ unit tests – Comprehensive coverage
  • Immutable primitives – No side effects, thread-safe
  • Defensive validation – Fail fast with clear messages
  • Continuous optimization – First render: 2 min β†’ After optimization: 45 sec

πŸ“– Documentation

  • JavaDoc: All classes and public methods fully documented
  • Code Comments: Explain "why" not "what" (algorithms, edge cases, optimizations)
  • Test Documentation: Each test describes expected behavior
  • README: You're reading it! 😊

πŸ™ Acknowledgments

  • Course: Introduction to Software Engineering, Jerusalem College of Technology
  • Concepts Inspired By: Peter Shirley's "Ray Tracing in One Weekend"
  • Pattern Reference: Gang of Four Design Patterns

πŸ“¬ Contact

I'm always excited to discuss this project, ray tracing techniques, or software development opportunities.

LinkedIn Email GitHub


Built with precision, tested with discipline, designed for clarity.

A journey through algorithms, architecture, and the art of turning math into visuals

About

Ray-tracing 3D rendering engine in Java. Implements geometric intersections, lighting models, shadows, and reflections using design patterns and TDD.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages