0

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!

BenColeman
  • 106
  • 1
  • 7
  • You can transform the normal in the same way as you transform `intersect` (at least if your transform is only made up of rotations, translations, and uniform scalings). Just make sure that you have a w-component of 0 and normalize afterwards. – Nico Schertler Jun 03 '18 at 17:32
  • for vectors use only matrices with position set to `(0,0,0)`. Scaling is a big problem as it changes the vector size so in some cases you need to add `normalize`. Also different scales between axises could break relationship between vectors so some algorithms/equations could be wrong afterwards. I use all the objects in the same coordinate system (they are constructed from triangles and spheres) here [Reflection and refraction impossible without recursive ray tracing?](https://stackoverflow.com/a/45140313/2521214) is how I do it. – Spektre Jun 04 '18 at 08:04
  • Thanks I've managed to solve this now. Thanks for giving me a clue wasn't totally doing the wrong thing! – BenColeman Jun 05 '18 at 09:18

1 Answers1

0

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);
BenColeman
  • 106
  • 1
  • 7
  • I am a bit confused. Use inverse matrix for Ray(origin and direction). Use the model matrix for hit point, then use inverse matrix for hit normal. Am I on the correct path? – iaomw Apr 09 '20 at 20:41