cones
Henry Cejtin
henry@sourcelight.com
Thu, 5 Oct 2000 02:52:58 -0500
Well, I fixed part of the cone problem. First I noticed that my code was a
bit silly in computing the normal vector to the surface of the cone, but not
incorrect. The code to compute the normal should be
fun normal () =
let val Point.T = { x, y, z } = here ()
in Vec.unitize (Vec.T { x = x, y = ~ y, z = z })
end
instead of
fun normal () =
let val Point.T = { x, y, z } = here ()
in Vec.unitize (Vec.T (if y >= 0.0
then { x = x / y,
y = ~ 1.0,
z = z / y }
else { x = ~ x / y,
y = 1.0,
z = ~ z / y }))
end
Note, they really do compute the same thing, the second one is just being
stupid (except when y = 0, which is a singularity any way).
The actual problem I fixed was caused by, of course, floating point
arithmetic.
Actually, there are two problems I think. The first problem has to do with
the connection between an incoming and outgoing intersection and the fact dot
product between the direction you are going and the normal. You should only
be leaving (going out) if the dot product is positive. I'm sure that this
was not correct because the floating point computation of x^2 + z^2 - y^2
having roundoff errors. The next problem, which again only happens if you
start very close to the surface of the cylinder, is that sometimes that first
intersection should be skipped because you are on the other side of it.
I.e., if I compute the illumination of a point on the cone, I am going to
start from the surface of the cone, and that ray had better not intersect the
same cone on that same side (thinking it is coming out).
The grotesque hack I put to handle these two cases is
local
fun fixup (surface, ray) =
let val res as T { startsInside, meets } =
coneInf (surface, ray)
in case meets of
[] => res
| Meet.T { normal, scale, ... }::rest =>
let val Ray.T { dir, ... } = ray
val startsInside' = Vec.dot (normal (), dir) > 0.0
in if scale < 0.000001
then T { startsInside = not startsInside',
meet = rest }
else T { startsInside = startsInside',
meets = meets }
end
end
in val coneInf = fixup
end
(Note the 10^-6 epsilon.) With this tweak, all of the `surface acne' went
away, but the reflections in the cone surfaces still are not correct. It
almost looks as if you are seeing reflections of the intersecting half-
spaces. I didn't look at the intersection code at all, but my guess is that
the remaining bug is something there. I'll think tonight for a cleaner
solution to this problem then the 10^-6 epsilon.
Note, with this fix in, if you get rid of all the specular reflections, it
looks fine, but if you use only specular ones, it definitely seems wrong.