POV-Ray : Newsgroups : povray.documentation.inbuilt : SOR documentation : Re: SOR documentation Server Time
10 Oct 2025 20:15:24 EDT (-0400)
  Re: SOR documentation  
From: Bald Eagle
Date: 3 Oct 2025 13:50:00
Message: <web.68e00c29251da1bce2c47eda25979125@news.povray.org>
"Bald Eagle" <cre### [at] netscapenet> wrote:

> bool Sor::Intersect, line 239 in sor.cpp
>
> Line 276 has the interesting expression:  r0 = P[X] * D[Z] - P[Z] * D[X];

>  /* Get distance of the ray from rotation axis (= y axis). */
....
> Apparently it's a sort of 2D cross-product, or "perp-product"
....
>     #if ((a = Dx * D.x + D.z * D.z) > 0.0)
>             #local r0 = r0/sqrt(a);
>     #end

OK, so r0 gets calculated by taking the vector cross product of
the PROJECTIONS of the ray origin and the ray direction (after they have been
translated into "object space")
[still hunting down how that Trans gets calculated, but I have an idea]

So, since they are projections onto the xz plane, y=0 for both vectors.
that means that two of the 2x2 determinants drop out due to multiplication by 0,
leaving only the one determinant to multiply by the y basis vector,
giving a y vector that is parallel to the 2 projected vectors.

Thus the shortened form P[X] * D[Z] - P[Z] * D[X]

However, in working this out, I had my vectors in different places in the
matrix, and so I got P[Z] * D[X] - P[X] * D[Z] which should just be the opposite
sign of the calculation in code.  Not really a worry, since it's just a vector
cross product.

The potential problem that I see is the test that uses this value:

    /* Test if ray misses object's bounds. */

    #if (r0 > Radius2)                      // Radius2 is xmax of the sor CP's
        #local Result = false;
    #else

If the sign of the vector cross product is negative, then that rejection test
will always fail, and the ray will always move on to have the intersection
tested.   Which, if I'm interpreting all of this correctly, means that all of
the rays on one side of the sor always get fully evaluated for intersections,
this potentially making rendering slower than it needs to be.

Shouldn't we be using at least abs (r0) to account for P-cross-D AND D-cross-P?



In more detail:

First we translate and then normalize the ray direction vector.

Then we test the ray to see if it is above or below the sor
as well as to the left or right of the sor

starting at line 266
    if (((D[Y] >= 0.0) && (P[Y] >  Height2)) ||
        ((D[Y] <= 0.0) && (P[Y] <  Height1)) ||
        ((D[X] >= 0.0) && (P[X] >  Radius2)) ||
        ((D[X] <= 0.0) && (P[X] < -Radius2)))
    {
        return(false);
    }

Line 266 checks if the ray direction is flat or points up, and the ray origin is
higher than the highest sor control point (Height2 = ymax)
So it will never intersect the rotated sor spline
This is OK

Line 267 checks if the ray direction is flat or points down, and the ray origin
is lower than the lowest sor control point (Height1 = ymin)
So it will never intersect the rotated sor spline
This is OK

Line 268 checks if the ray direction is straight or points right, and the ray
origin is to the right of the rightmost sor control point (Radius2 = xmax)
So it will never intersect the rotated sor spline
This is OK

Line 269 checks if the ray direction is straight or points left, and the ray
origin is to the left of the leftmost (rotated) sor control point (-Radius2 =
-xmax)
So it will never intersect the rotated sor spline
This is OK

BW: since this is before we do any projection, and we're only testing height and
width, can't we have a slanted ray that WOULD intersect the sor spline once it
got rotated around the y-axis?

Then we are doing a calculation that purports to be the DISTANCE between the ray
and the y-axis.

Working that out from first principles, it is the geometric problem of
determining the perpendicular distance (the shortest distance) between a point
and a line.
We simplify this by projecting onto 2D since the vertical angle of the ray makes
no difference at this point.
The vector cross product of 2 vectors gives us the area of the parallelogram
defined by those 2 vectors (just use those 2 vectors to make the remaining 2
sides)
The area is also equal to the base times the height of the parallelogram, and so
we solve for the height (H), which is the perpendicular - and therefore the
shortest distance between the point (y-axis in the xz plane, <0, 0, 0>) and the
line (the ray composed of origin and unit directional vector)
That gives us LENGTH (P-cross-D) = H times LENGTH (D)
Rearranging gives us H = LENGTH (P-cross-D) / LENGTH (D)

Now, in code, we have
r0 = P.x * D.z - P.z * D.x;
and that is only multiplied by the y unit basis vector,
so since there are no other dimensional units, this directly evaluates to the
length of the perpendicular y vector, and we don't have to do the expensive
square root of the sum of the squares.

a is the squared length of the direction vector
which, if non-zero, the vector cross product length gets divided by,
which should be the shortest, perpendicular length.

A few minor problems.
The ray direction vector already gets normalized at the beginning of
Sor_Intersect, so why are we calculating it's length again, and then checking if
it's more than zero, when at this point it should always be ONE.
Which bring up the potential divide-by-zero error when the normalization
calculation is done - and there is NO checking THERE!
And then there is the vector cross product sign issue.

So, after this gets rigorously checked, I'd suggest that
1. the ray direction vector length check gets moved to earlier in the code
2. we can do away with recalculating the length, checking for non-zero length,
and dividing the vector cross product length by a ray length which should
already always be 1.
3. Line 276 r0 = P[X] * D[Z] - P[Z] * D[X];
should be r0 = fabs(P[X] * D[Z] - P[Z] * D[X]);
so that the "length" is always positive.

- BE


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.