Skip to content

A high-performance, cross-platform C++ math library for game engines and 3D applications

License

Notifications You must be signed in to change notification settings

vertexnova/vnemath

Repository files navigation

VertexNova Math

VertexNova Math

A high-performance, cross-platform C++ math library for game engines and 3D applications

CI Coverage C++ Standard License


About

VertexNova Math (vnemath) is a comprehensive math library designed for real-time graphics applications, game engines, and 3D tools. It provides templated vector, matrix, and quaternion types along with a rich set of geometry primitives, intersection tests, and procedural generation utilities.

This library is part of VertexNova — a multi-backend game/graphics engine built from scratch.

Features

Core Types

  • Vectors: Vec2f, Vec3f, Vec4f (and double/int variants)
  • Matrices: Mat2f, Mat3f, Mat4f with full transformation support
  • Quaternions: Quatf, Quatd for rotation representation
  • Color: RGBA color with HSV/HSL conversions and gamma correction

Geometry Primitives

  • Basic: Ray, Plane, Line, LineSegment, Rect
  • Bounding Volumes: AABB, Sphere, OBB (Oriented Bounding Box), Capsule
  • Complex: Triangle, Frustum

Intersection Testing

  • Ray-Plane, Ray-Sphere, Ray-AABB, Ray-Triangle (Möller–Trumbore)
  • Frustum culling for visibility determination
  • Fast boolean intersection tests for culling

Interpolation & Animation

  • Easing Functions: smoothstep, smootherstep, and 30+ easing curves
  • Bezier Curves: Quadratic, Cubic with derivatives and arc length
  • Splines: Catmull-Rom (passes through points), Hermite (tangent control), B-spline
  • Spring Physics: Critical damping and exponential decay

Procedural Generation

  • Perlin Noise: 1D, 2D, 3D gradient noise
  • Simplex Noise: Faster, fewer artifacts
  • Fractal Brownian Motion: Multi-octave layered noise
  • Turbulence & Ridged Noise: For fire, smoke, mountains

Coordinate Spaces

  • Projection Utilities: project, unproject, screenToWorldRay
  • Transform Decomposition: Extract TRS from matrices, smooth interpolation
  • Multi-Backend Support: OpenGL, Vulkan, Metal, DirectX, WebGPU

Utilities

  • Angle normalization and interpolation (with wraparound handling)
  • Random number generation (Mersenne Twister based)
  • GPU-aligned types for shader uniform buffers
  • Statistics (running mean, variance, standard deviation)

Architecture: GLM Integration & Matrix Conventions

GLM as Compute Backend

VertexNova Math uses GLM (OpenGL Mathematics) as the optimized backend for expensive matrix operations while providing its own API layer:

┌─────────────────────────────────────────────────────────────┐
│                    VertexNova Math API                       │
│  Vec<T,N>, Mat<T,R,C>, Quatf, Color, geometry primitives    │
├─────────────────────────────────────────────────────────────┤
│                     GLM Backend                              │
│  Optimized: inverse, determinant, perspective, lookAt, etc. │
└─────────────────────────────────────────────────────────────┘

GLM is used for:

  • Matrix inverse, determinant, inverse-transpose
  • Projection matrices (perspective, orthographic)
  • View matrices (lookAt)
  • Transform matrices (translate, rotate, scale)
  • SIMD-optimized operations where available

VertexNova Math provides:

  • Unified type system with seamless GLM conversion
  • Multi-backend graphics API support
  • Geometry primitives and intersection tests
  • Easing, curves, noise, and other utilities
  • C++20 concepts and modern API design

Seamless GLM Interop

#include <vertexnova/math/core/core.h>
#include <glm/glm.hpp>

using namespace vne::math;

// Automatic conversion both ways
Mat4f vne_matrix = Mat4f::translate(Vec3f(1, 2, 3));
glm::mat4 glm_matrix = vne_matrix;  // Implicit conversion to GLM
Mat4f back = glm_matrix;             // Implicit conversion from GLM

// Same for vectors
Vec3f vne_vec(1, 2, 3);
glm::vec3 glm_vec = static_cast<glm::vec3>(vne_vec);

Matrix Storage: Column-Major

VertexNova Math uses column-major storage (same as GLM, OpenGL, and Vulkan):

// Mat4f internal layout:
// columns[0] = first column  (X-axis / right vector)
// columns[1] = second column (Y-axis / up vector)
// columns[2] = third column  (Z-axis / forward vector)
// columns[3] = fourth column (translation / position)

Mat4f transform = Mat4f::translate(Vec3f(10, 20, 30));

// Access translation (4th column)
Vec3f position = transform.getColumn(3).xyz();  // (10, 20, 30)
Vec3f position2 = transform.translation();       // Same, convenience method

// Access basis vectors
Vec3f right = transform.xAxis();    // Column 0
Vec3f up = transform.yAxis();       // Column 1
Vec3f forward = transform.zAxis();  // Column 2

Memory layout (16 floats contiguous):

Memory: [m00 m10 m20 m30 | m01 m11 m21 m31 | m02 m12 m22 m32 | m03 m13 m23 m33]
        └── Column 0 ───┘ └── Column 1 ───┘ └── Column 2 ───┘ └── Column 3 ───┘

Multi-Backend Graphics API Support

Different graphics APIs have different conventions. VertexNova Math handles this transparently:

API Depth Range NDC Y-Axis Screen Origin Projection Y-Flip
OpenGL [-1, 1] +Y up Bottom-left No
Vulkan [0, 1] +Y down Top-left Yes
Metal [0, 1] +Y up Top-left No
DirectX [0, 1] +Y up Top-left No
WebGPU [0, 1] +Y up Top-left No

NDC Coordinate Systems:

OpenGL/Metal/DX/WebGPU:        Vulkan (without Y-flip):
      +Y ↑                            -Y ↑
         |                               |
    -----+-----> +X                 -----+-----> +X
         |                               |
      -Y ↓                            +Y ↓

With needsProjectionYFlip(), Vulkan projection matrices are adjusted
so that the resulting NDC behaves like OpenGL/Metal/DX/WebGPU (+Y up).

Key distinction: NDC Y-axis direction (used in projection matrices) is different from framebuffer/screen origin (used in viewport/rasterization). Only Vulkan has NDC Y-down and requires a projection matrix Y-flip. Metal/DirectX/WebGPU have NDC Y-up like OpenGL; their top-left screen origin is handled by the viewport, not the projection matrix.

Usage:

// Perspective projection for different APIs
Mat4f proj_vulkan = Mat4f::perspective(fov, aspect, near, far, GraphicsApi::eVulkan);
Mat4f proj_opengl = Mat4f::perspective(fov, aspect, near, far, GraphicsApi::eOpenGL);
Mat4f proj_metal = Mat4f::perspective(fov, aspect, near, far, GraphicsApi::eMetal);

// Orthographic projection
Mat4f ortho = Mat4f::ortho(left, right, bottom, top, near, far, GraphicsApi::eVulkan);

// View matrices (handedness-aware)
Mat4f view_rh = Mat4f::lookAtRH(eye, center, up);  // OpenGL, Vulkan, WebGPU
Mat4f view_lh = Mat4f::lookAtLH(eye, center, up);  // Metal, DirectX

Compile-time traits:

// Query API conventions at compile time
using VulkanTraits = GraphicsApiTraits<GraphicsApi::eVulkan>;
VNE_STATIC_ASSERT(VulkanTraits::kDepth == ClipSpaceDepth::eZeroToOne, "Vulkan uses [0,1] depth");
VNE_STATIC_ASSERT(VulkanTraits::kProjectionYFlip == true, "Vulkan needs projection Y flip");
VNE_STATIC_ASSERT(VulkanTraits::kScreenOriginTopLeft == true, "Vulkan uses top-left origin");

// Runtime queries
ClipSpaceDepth depth = getClipSpaceDepth(GraphicsApi::eOpenGL);      // eNegativeOneToOne
bool projFlip = needsProjectionYFlip(GraphicsApi::eVulkan);          // true (only Vulkan)
bool screenFlip = screenOriginIsTopLeft(GraphicsApi::eMetal);        // true
bool screenFlipGL = screenOriginIsTopLeft(GraphicsApi::eOpenGL);     // false

Note on Handedness: While the traits include default handedness values per API, handedness is best treated as an engine/world convention, not an API property. Choose one handedness (right-handed recommended) for your engine and use it consistently across all backends.

GPU Buffer Alignment (std140/std430)

For shader uniform buffers, use the GPU-aligned types:

#include <vertexnova/math/gpu_types.h>

// std140-compatible struct
struct alignas(16) MyUniform {
    GpuVec3 position;   // 16 bytes (padded)
    float padding1;
    GpuVec4 color;      // 16 bytes
    GpuMat4 transform;  // 64 bytes
};

// Validation
VNE_STATIC_ASSERT(isStd140Compatible<MyUniform>(), "MyUniform must be std140 compatible");

Requirements

  • C++20 compatible compiler
  • CMake 3.16+

Dependencies (Git Submodules)

Category Dependency Version Description
External GLM 1.1.0 OpenGL Mathematics library
External Google Test 1.17.0 Unit testing framework
Libs VertexNova Common 1.0.0 Common utilities and macros
Libs VertexNova Logging 1.0.0 Logging library

Initializing Submodules

git submodule update --init --recursive

Supported Platforms

Platform Status Compiler
macOS Tested Clang, Apple Clang
Linux Tested GCC 9+, Clang 10+
Windows Tested MSVC 2019+
iOS Supported Xcode toolchain
Android Supported NDK r21+
Web Supported Emscripten

Building

Quick Start

# Clone with submodules
git clone --recursive https://github.com/vertexnova/vnemath.git
cd vnemath

# Build
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build

# Run tests
./build/bin/TestVneMath

Build Options

Option Default Description
BUILD_TESTS ON Build the test suite
BUILD_EXAMPLES OFF Build example programs
ENABLE_COVERAGE OFF Enable code coverage
ENABLE_CPPCHECK OFF Enable cppcheck analysis
ENABLE_CLANG_TIDY OFF Enable clang-tidy analysis

Build Examples

cmake -B build -DBUILD_EXAMPLES=ON
cmake --build build
./build/bin/examples/example_01_hello_math

Quick Start Examples

Vectors and Matrices

#include <vertexnova/math/math.h>
using namespace vne::math;

// Vectors
Vec3f position(10.0f, 20.0f, 30.0f);
Vec3f direction = Vec3f::forward();
float length = position.length();
Vec3f normalized = position.normalized();

// Matrices
Mat4f transform = Mat4f::translate(position) 
                * Mat4f::rotateY(degToRad(45.0f))
                * Mat4f::scale(Vec3f(2.0f));

Vec3f transformed = transform.transformPoint(Vec3f::zero());

// Quaternions
Quatf rotation = Quatf::fromAxisAngle(Vec3f::yAxis(), degToRad(90.0f));
Vec3f rotated = rotation.rotate(Vec3f::forward());

Geometry and Intersection

#include <vertexnova/math/geometry/geometry.h>

// Ray casting
Ray ray(camera_pos, ray_direction);
Sphere sphere(center, radius);

RayHit hit = intersect(ray, sphere);
if (hit.valid()) {
    Vec3f hit_point = hit.point;
    Vec3f hit_normal = hit.normal;
}

// Frustum culling
Frustum frustum = Frustum::fromMatrix(view_proj);
if (frustum.contains(aabb)) {
    // Object is visible
}

Curves and Animation

#include <vertexnova/math/curves.h>

// Cubic Bezier curve
Vec3f p0(0, 0, 0), p1(1, 2, 0), p2(3, 2, 0), p3(4, 0, 0);
Vec3f point = bezierCubic(p0, p1, p2, p3, t);
Vec3f tangent = bezierCubicDerivative(p0, p1, p2, p3, t);

// Catmull-Rom spline (passes through control points)
Vec3f waypoint = catmullRom(prev, start, end, next, t);

// Easing functions
float eased = ease(EaseType::eQuadInOut, t);
float smooth = smoothstep(0.0f, 1.0f, t);

Procedural Noise

#include <vertexnova/math/noise.h>

// Perlin noise
float height = perlin(x * 0.1f, z * 0.1f);

// Fractal Brownian Motion
float terrain = fbm(Vec2f(x, z) * 0.01f, 6);  // 6 octaves

// Ridged noise for mountains
float mountain = ridged(Vec2f(x, z) * 0.02f, 4);

Transform Decomposition

#include <vertexnova/math/transform_utils.h>

// Compose matrix from TRS
Mat4f matrix = compose(translation, rotation, scale);

// Decompose matrix to TRS
TransformComponents tc = decompose(matrix);
Vec3f pos = tc.translation;
Quatf rot = tc.rotation;
Vec3f scl = tc.scale;

// Smooth transform interpolation
Mat4f blended = lerpTransform(matrix_a, matrix_b, 0.5f);

Color Utilities

#include <vertexnova/math/color.h>

// Create from HSV/HSL
Color sunset = Color::fromHSV(30.0f, 0.8f, 1.0f);  // Orange
Color sky = Color::fromHSL(200.0f, 0.6f, 0.7f);    // Light blue

// Gamma correction
Color linear = srgb_color.toLinear();   // For lighting calculations
Color display = linear.toSRGB();         // For display

// Luminance and grayscale
float brightness = color.luminance();
Color gray = color.grayscale();

Examples

Example Description
01_hello_math Basic vectors, matrices, quaternions
02_multibackend_projection Graphics API-specific projections
03_camera_controller FPS and orbital cameras
04_frustum_culling Visibility testing
05_scene_graph Hierarchical transforms
06_ray_intersection Ray casting with geometry
07_color_utilities Color manipulation
08_gpu_buffer_alignment Shader-compatible types
09_easing_intersection Easing and ray tests
10_curves_animation Bezier and spline curves
11_noise_generation Procedural noise
12_transform_decomposition Matrix TRS decomposition

CMake Integration

As Subdirectory

add_subdirectory(external/vnemath)
target_link_libraries(your_target PRIVATE vne::math)

With FetchContent

include(FetchContent)
FetchContent_Declare(
    vnemath
    GIT_REPOSITORY https://github.com/vertexnova/vnemath.git
    GIT_TAG main
)
FetchContent_MakeAvailable(vnemath)
target_link_libraries(your_target PRIVATE vne::math)

With find_package

find_package(VneMath REQUIRED)
target_link_libraries(your_target PRIVATE vne::math)

Project Structure

vnemath/
├── include/vertexnova/math/
│   ├── core/                    # Vec, Mat, Quat, types
│   ├── geometry/                # Primitives and intersection
│   ├── color.h                  # RGBA with HSV/HSL/gamma
│   ├── easing.h                 # Smoothstep and easing curves
│   ├── curves.h                 # Bezier and splines
│   ├── noise.h                  # Perlin, Simplex, fBm
│   ├── projection_utils.h       # Screen/world conversions
│   ├── transform_utils.h        # TRS decomposition
│   └── math.h                   # Main include
├── src/                         # Implementation files
├── tests/                       # Unit tests (695 tests)
├── examples/                    # Example programs (12 examples)
└── cmake/                       # CMake modules

Running Tests

# Build and run all tests
cmake --build build --target TestVneMath
./build/bin/TestVneMath

# Run specific test suite
./build/bin/TestVneMath --gtest_filter="NoiseTest.*"

License

Apache License 2.0 — See LICENSE for details.

Author

Ajeet Singh Yadav (yadav.ajeetsingh2020@gmail.com)


Part of the VertexNova project

About

A high-performance, cross-platform C++ math library for game engines and 3D applications

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published