hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

3D RayTracer in F#

Last post 11-22-2006, 12:09 by jdh30. 4 replies.
Sort Posts: Previous Next
  •  08-28-2006, 12:37 570

    3D RayTracer in F#

    At the link below you will find an implementation of RayTracing techniques using F#, created by myself in my spare time this summer. By a RayTracer, I mean  a program that takes an XML-specified collection of 3D objects (using CSG - combinations of primitives stretched, translated etc) and produces a 2D image of the above objects from any camera location and with user-specified light sources. This program supports the standard Phong illumination model. (Note, all of this is easily acessible from DirectX I imagine, but I just did it "from scratch" as an exercise in F# and implementing some of the ideas in my Graphics course from last year. Throughout all of this the only graphics operations that are used are setpixel and saveimage.) Also note that the implementation is entirely functional (even though it is object-orientated - immutable objects. The only point at which it is not functional is the top level interface (common dialogues, saving to bitmap) and the progress-handling mechanism via events.) I was suprised at the speed the examples are running given the amount of calculations that are going on (for each pixel, calcuate intersection of ray from that pixel with each surface, some of which are quadratic...) although to be fair all of the examples use at most 4 primitives. In the zip file you will find

    • Executables
    • Source Code
    • Examples
    • Documentation

    And it should be quite easy to figure out what is going on from all of the above.

    The project uses an XMLParsing technique described in my My Thoughts on F#: Developments post, although not quite in the ideal form specified there as I did this first.

    To run, run RayTracer.exe and select an XML file in the format specified in Documentation.txt, such as one of the many examples given.

    Have fun!

    http://myweb.tiscali.co.uk/dchurchill/RayTracer.zip

     

  •  09-08-2006, 23:07 604 in reply to 570

    Re: 3D RayTracer in F#

    Hi Martin,

    This is a great sample!  I can run the binary in the sample, but have a few questions

    • I'm trying to work out why you need to ship copies of fslib.dll and mllib.dll.  Generally people either statically link these libaries (especially when delivering small demonstration samples). 
    • I tried a static link (with "--standalone --static-link Eval.dll") but got some refelection errors, I think related to your XML parsing technique.
    • I also tried deleting fslib.dll and mllib.dll and recompiling with a newer F# distribution, and also ran into problems.  The build commands I used were:

    fsc -r Eval.dll -O3 -g --no-warn 20 --no-warn 44 -a Source\XMLParserFS.fs

    fsc -O3 -g --no-warn 20 --no-warn 25 --no-warn 44 -a -r Eval.dll -r XMLParserFS.dll Source\RayTracer.fs

    BTW is the implementation of Eval.dll missing?

    Some small commments on the code:

    • Comments might be good for F# beginners :-)
    • The CSG class and its extensions are excellent. Is there any reason you didn't define CSG as an interface? (apart from the fact that you wanted the .LMC member defined using a dot-notation?)
    • This would look great with #light
    • 1 space indentation makes it pretty hard to read.  I'd recommend 4 space (we're now recommending this as the "standard" for F# code, especially with #light code, despite the fact that much of the compiler source code uses 2 space)
    • You've used a lot of lists - if you need performance improvements then using tuples, arrays of Math.Types.Vector should help a lot here.
    • A few comments might be good for F# beginners :-)

    Cheers!

    don

  •  09-11-2006, 1:59 617 in reply to 604

    Re: 3D RayTracer in F#

    The source of problems come from my hacked together method of quickly creating an XMLParser as described in my My Thoughts on F# post.

    XMLParserFS works by using an XMLTextReader to read through a file and create a "construction string" based on the XML file of what object to create. It then "runs" this "construction string" in the style of the java "eval" command. Obviously the way to do this is through reflection - I haven't yet used Reflection really before, and at the time just wanted a quick and dirty way of doing it. Hence I had a little search and found this: http://www.codeproject.com/dotnet/evaluator.asp. This was basically the source code for an eval function string -> object as I required. I decided to use this, and compiled it in the Eval dll. I should have included a note to this effect in there crediting it and posting a link, but this is the reason I didn't include the source code for this binary there - because it wasn't mine.

    The evaluator above works by creating a binary in C# from the source code (of the creation string) and then running that binary. Since this binary created needs to be able to access the classes inside RayTracer.fs - in order to be able to construct instances of them to return - I couldn't compile it as a standalone exe, as this prevents external access to your classes (or at least I believe it did at the time of writing.) This explains why I did not take the approach of the first bullet point and why the second bullet point did not work. The third bullet point failed as when eval dynamically creates the code it looks for the fslib and mllib dlls in the location of the other binaries to link the dynamically created binary to.

    The source of all the problems here is the method of converting the constructor-string created by the XMLParser into an actual object. The eval dll creates a binary from this source (using CodeCom etc) and then runs it. I haven't yet looked into Reflection to see if there is a better way of doing this (it is on my My Thoughts in F#: Developments list,) but I can still imagine that the classes need to be public for it to work, which prevents standalone linkage. Is it definately the case that standalone static linkage prevents publicly exposing the classes? Does anyone here with a greater understanding of Reflection know of a better way of doing this string-to-object conversion? I will look into it myself at some point.

    Thanks for the comments on the code Don :-) I agree that indeed comments for it would be good, as would #light and more intendation, and shall try to do this soon and update the link. It is indeed precisely the .LMC method that prevented me using an interface for CSG. Also I do use lots of lists, but each particular list generally isn't that long so I felt that the linear look-up time wouldn't be that much of an issue (lists of three points for vectors, lists of intervals, lists of objects etc all in general would contain a reasonably small number of elements.) But of course this would be a way of improving performance (as of course would using more compiler optimisation which I didn't do but I see you have above.)

     

     

  •  11-22-2006, 5:56 920 in reply to 617

    Re: 3D RayTracer in F#

    As informed by Don Syme's blog, Flying Frogs Consultancy have recently published this sample of beautiful F# code, which uses this kind of technique to RayTrace a specific scene, described in a very simple manner with recursive nesting of spheres. It also uses shadowing and reflection (recursive raytracing) which are couple of techniques I didn't quite get to in my generic raytracer here.

    http://www.ffconsultancy.com/dotnet/fsharp/raytracer/index.html

  •  11-22-2006, 12:09 923 in reply to 920

    Re: 3D RayTracer in F#

    I'm happy that my programs are being appreciated. They are mostly derived from the OCaml side of my site (under "freebies"). I'll be porting more in the future and am writing up a minimal Direct X right now...

    Cheers,

    Jon.

     

View as RSS news feed in XML
Powered by Community Server, by Telligent Systems