Skip to content

Octahedron normals #12

@CptPotato

Description

@CptPotato

Hey there!

Have you considered encoding normals using octahedron mapping? It's a neat way to map a direction vector into two components and it has a more uniform distribution than storing (angle, z).

I haven't profiled it against the current implementation, but here's some sample code:

code
use glam::{Vec2, Vec3};

/// Encode a 3d direction vector to a 2d vector using octahedron mapping.
/// The output vector is in the range [-1..1]. The input vector doesn't have to be normalized.
pub fn encode_oct(dir: Vec3) -> Vec2 {
    let norm = dir.x.abs() + dir.y.abs() + dir.z.abs();
    let nx = dir.x / norm;
    let ny = dir.y / norm;
    if dir.z.is_sign_positive() {
        Vec2::new(nx, ny)
    } else {
        // fold over negative z
        Vec2::new(
            (1.0 - ny.abs()) * nx.signum(),
            (1.0 - nx.abs()) * ny.signum(),
        )
    }
}

/// Decode an octahedron mapped direction vector back to the original one.
/// The output is normalized.
pub fn decode_oct(mut oct: Vec2) -> Vec3 {
    let z = 1.0 - oct.x.abs() - oct.y.abs();
    oct += oct.signum() * z.min(0.0);
    Vec3::new(oct.x, oct.y, z).normalize()
}

If you want to, I could open a PR to compare it to the current impl.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions