Reputation: 106
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
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! ^^
Upvotes: 0
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