Question

All,

I am writing a rather non conventional ray tracer to calculate heat transfer properties of various objects in a scene. In this ray tracer random rays are shot from the surface of my primitive objects into a scene to check for intersections.

This particular algorithm requires each ray to be developed in primitive space then affine transformed by the source object into world space then subsequently affine transformed back into the primitive space of other objects in the scene to check for intersection.

All is good until I do a anisotropic scale for example scaling a object by [2 2 1] (isotropic scales are fine). This leads me to believe I am not transforming the directional component of the ray correctly. Currently I transform the ray direction from primitive space to world space by multiplying the directional component by the transpose of the source objects inverse transformation matrix and then I transform the ray from world space to each primitive space by multiplying by the transpose of the destination objects transformation matrix.

I have also tried multiplying by the source primitive's transformation matrix to go from primitive to world space and multiplying by the the destinations inverse transformation to go from world space to primitive space but this was unsuccessful.

I believe a ray launched from the surface of a primitive object (at a random point and in a random direction) should be transformed in the same manner as a surface normal in 'regular' ray tracing however I am not certain.

Any of the experts out there know what the flaw in my methodology is? Feel free to ask if more information is required.


The basic algorithm for this ray tracer is as follows:

For each object, i, in scene
{
    for each ray, r, in number of rays per object
    {
        determine random ray from primitive i
        convert ray from primitive space of i to world space

        for each object, j, in scene
        {
            convert ray to primitive space of object j
            check for intersection with object j
        }
    }
}

Hopefully to clear up the question lets look at an example. Lets assume I have a cylinder extending along the z-axis (unit radius and height) and an annulus lying in the x-y plane with inner diameter 7 and outer diameter 8. I want the scale the cylinder by a factor 6 in the x and y directions (but not the z direction) so my affine transformation matrix are as follows:

M(cylinder) = |2 0 0 0|        M^-1(cylinder) = | .5 0. 0. 0. |
              |0 2 0 0|                         | 0. .5 0. 0. |
              |0 0 1 0|                         | 0. 0. 1. 0. |
              |0 0 0 1|                         | 0. 0. 0. 1. |

M(annulus) =  |1 0 0 0|        M^-1(annulus) =  |1 0 0 0|
              |0 1 0 0|                         |0 1 0 0|
              |0 0 1 0|                         |0 0 1 0|
              |0 0 0 1|                         |0 0 0 1|

Now assume I have a ray which has a random starting point on the surface of the cylinder s and a random direction away from the surface of the cylinder c giving the ray r(os) = s + ct.

I want to transform this ray from primitive (object) space to world space and then test for intersection with the other objects in the scene (the annulus).

The first question is what is the correct way to transform the ray, r(os), to world space, r(ws), using M(cylinder) or M^-1(cylinder).

The second question is what is the correct way to then transform the ray, r(ws), from world space to object space to check for intersection with the other objects using M(annulus) and M^-1(annulus).


Some additional background information:

This application is for calculating radiative heat transfer between N objects. The ray is launched from a random point on the object with its direction being randomly selected to lie within a hemispherical distribution orientated with the surface normal at the random point.


Here is some visualisation of my problem. The ray directional distribution when it is first generated: Initial ray directional distribution

If I apply the transformation to world co-ordinates using the transformation matrix M: Direction transformed by M

If I apply the transformation to world co-ordinates using the inversetransformation matrix M^-1 Direction transformed by M^-1

Was it helpful?

Solution

This just came up the other day in This question

One of the answers links to a Ray Tracing News article discussing the use of the transpose of the inverse transform for normals.

I have to agree with JCooper in asking "what is actually going wrong?". My first thought is that you seem to be simulating radiated heat transfer, and you have to be careful will non-uniform scaling of objects. If you have a uniform distribution of "photons" on an objects surface being emitted, and then you apply a non-uniform scaling of that object, you will then have a non-uniform distribution of photons leaving the surface. This is one possible pitfall, but since you don't indicate what's going wrong it's hard to say if this is your problem.

To answer your questions about the correct way to do the transformations, follow This link to Ray Tracing News

OTHER TIPS

The inverse transpose transformation matrix keeps the rotation component constant, but inverts the scaling. That means that the scaling is still there. This is correct for normals: Consider, in 2d, a line segment from (0,0) to (.707,.707). The normal is (-.707,.707). If we scale by (s,1), we get a segment from (0,0) to (s*.707,.707). In the limit, as s grows large, we essentially have a flat line parallel to the x axis. That means that the normal should point along the y axis. So we get a normal of (-.707/s,.707). It should be clear from this example, however, that the transformed vector is no longer unit length. Perhaps you need to normalize the directional component?

If we start by using the property that a transformation matrix can be represented as a scaling sandwiched between two rotations (a la SVD), we get your outbound transformation matrix looks like so: R2out*Sout^-1*R1out and then your inbound transformation matrix looks like so: R1in^-1*Sin*R2in^-1 (how I wish SO used Mathjax...). This seems like the right thing, as long as you re-normalize your vectors.


Edit:

Thinking about this overnight, I decided that the inverse-transpose thing might only be valid for the normals case. Consider the example above. If s=2, then the slope of the line-segment, originally 1, turns into 1/2. Likewise, the slope of the normal turns from -1 into -2. There's still a 90 degree angle between the line segment and the ray. So far so good. Now... what if the vector under consideration is actually parallel to the line segment. We get a slope of 2, no longer parallel.

So, I guess I have two questions at this point. What is actually going wrong in your program/What makes you think it's not correct? And what is the correct behavior? Perhaps you can make a 2D plot.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top