BenColeman
BenColeman

Reputation: 106

Ray Tracing in object space, transforming normals

I've got a working ray tracer (written in Node using gl-matrix) It's working great with spheres but now I'm adding general purpose matrix transforms (translate, rotate, scale) in order to support other object types.

I have two transformation matrices per object, an inverse one for world to object called trans and one back again transFwd, set up with fromRotationTranslationScale

// Here pos is center of sphere and r is radius
mat4.fromRotationTranslationScale(this.transFwd, rotation, [pos[0], pos[1], pos[2]], [r, r, r]);
mat4.invert(this.trans, this.transFwd);

I'm transforming all rays using the trans transform into object space calculating my ray-object intersection (value of t) about the origin, with spheres of radius of 1.

The challenge is after calculating t, working with my intersection & normals. When I add any sort of rotation to my transform they all get distorted

// ray has already been transformed to object space
// getPoint simply returns ray.pos + t * ray.dir
let intersect: vec4 = ray.getPoint(t);

let normal: vec4 = vec4.sub(vec4.create(), i, [0, 0, 0, 1]);
vec4.normalize(n, n);

// move intersect back to world space
vec4.transformMat4(intersect, intersect, this.transFwd);

What is the correct way to deal with normals when using transformation matrixes for your objects? I've tried transforming back to world space afterwards, I've tried calculating the normal after moving intersection back, but nothing works!

Upvotes: 0

Views: 1639

Answers (2)

Astranged T'fyer
Astranged T'fyer

Reputation: 63

You may also want to transpose your inverted matrix to preserve scaling when you transform your normal from object to world coordinates! Otherwise, it might give you wonky results, especially in your lighting! ^^ The Ray Tracer Challenge by Jamis Buck

Upvotes: 0

BenColeman
BenColeman

Reputation: 106

I have managed to solve this. I was on the right path just I wasn't transforming both my normals and reflected rays so it was still looking strange. The difficult thing with ray tracing is the only testing you can do is by "visual inspection"

Here's a summary of my working intersection code for a sphere in object space

// Intersection in object space
let intersect: vec4 = ray.getPoint(t);

// Normal is pointing from center of sphere (0,0,0) to intersect (i)
// Divide by sphere radius 
vec4.div(normal, intersect, [radius, radius, radius, 1]);
n[3] = 0;

// Move i back to world space
vec4.transformMat4(intersect, intersect, transFwd);

// Reflected ray about the normal, & move to world
let reflect: vec4 = ray.reflect(normal);
vec4.transformMat4(reflect, r, transFwd);
vec4.normalize(reflect, reflect);   

// Move normal into world & normalize
vec4.transformMat4(normal, normal, transFwd);
vec4.normalize(normal, normal);

Upvotes: 0

Related Questions