Google Groups Home Help | Sign in
Mini ray tracer
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  Messages 1 - 25 of 48 - Collapse all   Newer >
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
Jon Harrop  
View profile
 More options 8 May 2005, 02:27
Newsgroups: comp.graphics.rendering.raytracing
From: Jon Harrop <use...@jdh30.plus.com>
Date: Sun, 08 May 2005 02:27:06 +0100
Local: Sun 8 May 2005 02:27
Subject: Mini ray tracer

I recently tried my hand at writing a ray tracer (something I haven't done
for 15 years!) and, in particular, I to write the shortest possible ray
tracer which was still comprehensible and interesting. The initial result
was a 222-line OCaml program which incrementally renders a sphere-flake via
OpenGL:

  http://www.ffconsultancy.com/free/ray_tracer/index.html

I then cut this program down to a 66-line OCaml program and ported it into a
97-line C++ program. These programs are compared on this page:

  http://www.ffconsultancy.com/free/ray_tracer/comparison.html

The cut-down versions don't do reflections, color or such a pretty
sphere-flake and output a greyscale PGM but they do still use hierarchical
spherical bounding volumes to accelerate rendering enough that they can
render scenes containing millions of spheres.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
asamard...@matf.bg.ac.yu  
View profile
 More options 8 May 2005, 12:48
Newsgroups: comp.graphics.rendering.raytracing
From: asamard...@matf.bg.ac.yu
Date: 8 May 2005 04:48:11 -0700
Local: Sun 8 May 2005 12:48
Subject: Re: Mini ray tracer
Great work.  What is default floating point type used by OCaml
compiler?  I got running time of about 36s for scene level 3 on
Pentium3 machine and running time of about 25s when all references to
"double" type in C++ code changed to "float" (and float is usually
"good enough" for ray tracing)...

Regards,
Alex


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
tbp...@gmail.com  
View profile
 More options 9 May 2005, 18:51
Newsgroups: comp.graphics.rendering.raytracing
From: tbp...@gmail.com
Date: 9 May 2005 10:51:28 -0700
Local: Mon 9 May 2005 18:51
Subject: Re: Mini ray tracer
Jon Harrop wrote:
> I then cut this program down to a 66-line OCaml program and ported it
into a
> 97-line C++ program. These programs are compared on this page:

>   http://www.ffconsultancy.com/free/ray_tracer/comparison.html

Is that comparison supposed to be fair in any way whatsoever?

Somewhere on an opteron 146 running debian64:
# g++ -g -O3 ray.cpp -o ray
# time ./ray >tt

real    0m13.959s
user    0m13.946s
sys     0m0.009s

# objdump -x ray
[2mn later]
# diff ray_orig.cpp ray.cpp
12,16c12,18
< Vec operator+(Vec a, Vec b) { return Vec(a.x + b.x, a.y + b.y, a.z +
b.z); }
< Vec operator-(Vec a, Vec b) { return Vec(a.x - b.x, a.y - b.y, a.z -
b.z); }
< Vec operator*(double a, Vec b) { return Vec(a * b.x, a * b.y, a *
b.z); }
< double dot(Vec a, Vec b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
< Vec unitise(Vec a) { return (1 / sqrt(dot(a, a))) * a; }
---

> inline Vec operator+(const Vec &a, const Vec &b) { return Vec(a.x +

b.x, a.y + b.y, a.z + b.z); }
> inline Vec operator-(const Vec &a, const Vec &b) { return Vec(a.x -

b.x, a.y - b.y, a.z - b.z); }
> inline Vec operator*(const double a, const Vec &b) { return Vec(a *

b.x, a * b.y, a * b.z); }
> inline double dot(const Vec &a, const Vec &b) { return a.x*b.x +

a.y*b.y + a.z*b.z; }
> inline Vec unitise(const Vec &a) { return (1 / sqrt(dot(a, a))) * a;
}

# g++ -g -O3 ray.cpp -o ray
# time ./ray >tt

real    0m10.493s
user    0m10.483s
sys     0m0.005s

If your point was to show how to write unbelievably inneficient code in
C++, you've succeeded.
Can't wait for a C++ vs Java comparison.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Matt Pharr  
View profile
 More options 9 May 2005, 19:37
Newsgroups: comp.graphics.rendering.raytracing
From: Matt Pharr <m...@pharr.org>
Date: Mon, 09 May 2005 18:37:59 GMT
Local: Mon 9 May 2005 19:37
Subject: Re: Mini ray tracer

tbp...@gmail.com writes:
> Jon Harrop wrote:
>> I then cut this program down to a 66-line OCaml program and ported it
> into a
>> 97-line C++ program. These programs are compared on this page:

>>   http://www.ffconsultancy.com/free/ray_tracer/comparison.html
> Is that comparison supposed to be fair in any way whatsoever?

> [demonstration that "inline" vector math makes C++ programs faster
> elided]

> If your point was to show how to write unbelievably inneficient code in
> C++, you've succeeded.

I think the point was to have some fun and to make a little demo that shows
how a functional language like OCaml can give rise to nice short expressive
programs while still delivering competitive performance.  And for those
goals, the OP succeeded!

Note also that he mentions on his web page that he's doing this for "the
computer language shootout benchmarks", http://shootout.alioth.debian.org/.
That page clearly points out all the caveats around benchmarks like these
(to the point that they can be effectively meaningless in  the real world.)

Specifically:

>> about The Language Shootout Benchmarks

>>Our goals are to learn about programming languages, compare their
>>performance in various (possibly meaningless) ways and, most importantly,
>>have some fun!

I've at least had some fun looking at his implementation!

-matt
--
Matt Pharr    m...@pharr.org    <URL:http://graphics.stanford.edu/~mmp>
=======================================================================
In a cruel and evil world, being cynical can allow you to get some
entertainment out of it. --Daniel Waters


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
tbp  
View profile
 More options 9 May 2005, 23:51
Newsgroups: comp.graphics.rendering.raytracing
From: "tbp" <tbp...@gmail.com>
Date: 9 May 2005 15:51:11 -0700
Local: Mon 9 May 2005 23:51
Subject: Re: Mini ray tracer
Matt Pharr wrote:
> > [demonstration that "inline" vector math makes C++ programs faster
> > elided]

You've missed the point.
a) he's telling the OCaml compiler to inline everything it can while
not giving its c++ counterpart opportunities to do so; fairness?
b) more importantly he's passing large structures by _value_ and i've
turned them into _references_.

In fact if you do the same for other hotpath functions as in:
19c21
<   virtual void intersect(double &, Vec &, Ray) = 0;
---

>   virtual void intersect(double &, Vec &, const Ray &) = 0;

26c28
<   double ray_sphere(Ray ray) { // Intersection of a ray with a sphere
---
>   double ray_sphere(const Ray &ray) { // Intersection of a ray with a

sphere
35c37
<   void intersect(double &lambda, Vec &normal, Ray ray) {
---
>   void intersect(double &lambda, Vec &normal, const Ray &ray) {

50c52
<   void intersect(double &lambda, Vec &normal, Ray ray) {
---

>   void intersect(double &lambda, Vec &normal, const Ray &ray) {

then the c++ version becomes 50% faster than originally (and in fact,
unconditionally faster than the OCaml version), without adding a single
line.

You'll notice i haven't even fixed the gratitious use of virtual
functions, and other details that force standard compliant c++
compilers to pessimize a lot when facing such... hmm.. source.

I'm sure OCaml is a wonderful & expressive language, but crafting such
a fishy c++ equivalent to make it shine (because you have an agenda) is
a despicable practice.

> > If your point was to show how to write unbelievably inneficient
code in
> > C++, you've succeeded.

> I think the point was to have some fun and to make a little demo that
shows
> how a functional language like OCaml can give rise to nice short
expressive
> programs while still delivering competitive performance.  And for
those
> goals, the OP succeeded!

> Note also that he mentions on his web page that he's doing this for
"the
> computer language shootout benchmarks",

http://shootout.alioth.debian.org/.
> That page clearly points out all the caveats around benchmarks like
these
> (to the point that they can be effectively meaningless in  the real

world.)
I have nothing against such benchmarks when they are not clearly
rigged.

But i guess the main point of the whole operation wasn't fair
benchmarking, education, or fun but selling books: "This program has
demonstrated some of the ways that OCaml improves upon C++. For a
thorough introduction to OCaml, read our book "Objective CAML for
Scientists".

Or put another way, that's a sad PR stunt.

Have a nice day.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jon Harrop  
View profile
 More options 10 May 2005, 04:33
Newsgroups: comp.graphics.rendering.raytracing
From: Jon Harrop <use...@jdh30.plus.com>
Date: Tue, 10 May 2005 04:33:46 +0100
Local: Tues 10 May 2005 04:33
Subject: Re: Mini ray tracer

tbp wrote:
> Matt Pharr wrote:
>> > [demonstration that "inline" vector math makes C++ programs faster
>> > elided]
> You've missed the point.

My post is more about clarity and less about performance. Your proposed
alterations make the C++ implementation significantly longer and more
obfuscated and your littering of the source code with "inline" actually
slows the program down on my Athlon t-bird.

Moreover, your choices of initial optimisation are decidedly suboptimal. I'd
have gone for:

1. Terminating the intersection of shadow rays when the first intersection
is found (instead of finding the closest intersection).

2. Use an implicit scene, to avoid storing it explicitly.

3. Use single-precision storage (or no storage at all).

Both of these optimisations will give much bigger performance improvements
when averaged over different platforms and architectures.

As it happens, I had already implemented all of your optimisations and all
of these optimisations to both implementations before I made my original
post. None of them add anything new. Sometimes C++ is faster, sometimes
OCaml is faster. OCaml is always much more succinct. You can keep doing
this until you are blue in the face but I don't think you'll learn much of
interest.

> a) he's telling the OCaml compiler to inline everything it can while
> not giving its c++ counterpart opportunities to do so; fairness?

Both ocamlopt and g++ were allowed to inline code.

As OCaml is for symbolic use, it performs no inlining by default (unlike
g++) so it is common to ask OCaml to do some inlining on numerical code.
Thus, specifying "-inline 100" actually makes for a fairer comparison.

> b) more importantly he's passing large structures by _value_ and i've
> turned them into _references_.

Both implementations use pass by value as this is clearer, shorter and (as a
consequence) more common in real code.

> In fact if you do the same for other hotpath functions as in:
> ...
> then the c++ version becomes 50% faster than originally

If you want a fair comparison then you should also make equivalent changes
to the OCaml implementation.

> (and in fact, unconditionally faster than the OCaml version),

You are trying to compare optimised C++ against unoptimised OCaml, which
would be unfair. More worryingly, you seem to have skipped the part of the
experiment where you actually measure something.

> without adding a single line.

When restricted to 80 columns, your optimisations add several lines. Indeed,
they push the C++ program over 100 LOC limit imposed by the creators of the
shootout.

In fact, I'd already implemented your optimisations (and many more effective
optimisations) and had to throw them out because of this limit. Note that
the OCaml has 30 more lines with which to optimise. My optimised <100 LOC
OCaml program is much faster than my optimised <100 LOC C++ on all
platforms.

> You'll notice i haven't even fixed the gratitious use of virtual
> functions,

What would you recommend instead?

I chose an inheritance hierarchy because this is the closest C++ equivalent
to a variant type which I see in typical C++ programs.

Another optimisation that I made was to replace inheritance with a single
Scene struct which represented a group of child scenes or a sphere when it
had no children. I threw this out as well because it is not a fair
equivalent to OCaml's variant type. For example, you could not specify a
colour for each sphere without also specifying colours for all bounding
volumes.

> and other details

Can you elaborate on these other "details"?

> that force standard compliant c++  
> compilers to pessimize a lot when facing such... hmm.. source.

Manually implementing pass constant by reference is both obfuscating and
error-prone whilst being theoretically unnecessary. The fact that the OCaml
compiler does this optimisation for you when the GNU C++ compiler does not
might interest some people.

> I'm sure OCaml is a wonderful & expressive language, but crafting such
> a fishy c++ equivalent to make it shine (because you have an agenda) is
> a despicable practice.

Everyone will be free to contribute to the shootout version of the ray
tracer. Perhaps you would like to contribute a less "fishy" C++
implementation?

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jon Harrop  
View profile
 More options 10 May 2005, 04:52
Newsgroups: comp.graphics.rendering.raytracing
From: Jon Harrop <use...@jdh30.plus.com>
Date: Tue, 10 May 2005 04:52:38 +0100
Local: Tues 10 May 2005 04:52
Subject: Re: Mini ray tracer

asamard...@matf.bg.ac.yu wrote:
> Great work.  What is default floating point type used by OCaml
> compiler?

Double precision.

> I got running time of about 36s for scene level 3 on
> Pentium3 machine and running time of about 25s when all references to
> "double" type in C++ code changed to "float" (and float is usually
> "good enough" for ray tracing)...

I agree that single precision is usually good enough for ray tracing.
However, when I tried the same optimisation I found that it made the
program much faster on 32-bit x86 and much slower on 64-bit AMD64. I assume
this is a float alignment issue.

Also, it generates (numerically) different results, which makes it trickier
to validate against the OCaml.

--
Dr Jon D Harrop, Flying Frog Consultancy
http://www.ffconsultancy.com


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Warp  
View profile
 More options 10 May 2005, 09:20
Newsgroups: comp.graphics.rendering.raytracing
From: Warp <w...@cs.tut.fi>
Date: Tue, 10 May 2005 08:20:17 +0000 (UTC)
Local: Tues 10 May 2005 09:20
Subject: Re: Mini ray tracer

Jon Harrop <use...@jdh30.plus.com> wrote:
> My post is more about clarity and less about performance. Your proposed
> alterations make the C++ implementation significantly longer and more
> obfuscated and your littering of the source code with "inline" actually
> slows the program down on my Athlon t-bird.

  Then your compiler is stupid. Get a better one.

  The keyword 'inline' is not a command for the compiler that says it must
inline the function or else it will be deleted immediately. And the other
way around, the lack of 'inline' keyword by no means stops the compiler
from inlining the function if it can and it estimates it would be useful.

  In *theory* 'inline' is a hint to the compiler. In practice it has nothing
to do with inlining. Most of the modern compilers will simply ignore that
keyword when they are estimating whether a function should be inlined or
not. In this context 'inline' is a no-op. It's like the 'register'
keyword which is nowadays obsolete and a no-op.

  What 'inline' *does* have some effect on is the linker. If a function
with an identical declaration is implemented in more than one place
then in normal circumstances the linker will give an error (because it
can't know which one of them it should use). However, if the functions
were declared 'inline', then the compiler will tell the linker that
all of those functions are actually one and the same, and then the linker
will just use one of them.

  And by the way, if you are afraid of "litter" in C++ code, then you
should switch to another programming language.
  That "litter", as you call it, is not useless junk as you seem to imply.
It has a reason and a significance.

> > b) more importantly he's passing large structures by _value_ and i've
> > turned them into _references_.
> Both implementations use pass by value as this is clearer, shorter and (as a
> consequence) more common in real code.

  I hope you are not passing megabyte-sized vectors by value...

  If your opinion of "clearer" and "shorter" is that the & symbol should
not be used, then you might want to either check your priorities or
change your programming language (because C++ is not for you).

> If you want a fair comparison then you should also make equivalent changes
> to the OCaml implementation.

  You want to compare which programming language runs inefficient code
faster?

> > You'll notice i haven't even fixed the gratitious use of virtual
> > functions,
> What would you recommend instead?
> I chose an inheritance hierarchy because this is the closest C++ equivalent
> to a variant type which I see in typical C++ programs.

  Inheritance has no overhead in C++. Dynamic binding has.
  While virtual function calls are pretty fast they are still slightly
slower than regular function calls. If you want maximum speed you should
not make time-critical functions virtual unless you are really forced to.

> Another optimisation that I made was to replace inheritance with a single
> Scene struct which represented a group of child scenes or a sphere when it
> had no children.

  Inheritance causes no overhead. That kind of optimization is useless.

--
                                                          - Warp


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
tbp  
View profile
 More options 10 May 2005, 11:36
Newsgroups: comp.graphics.rendering.raytracing
From: "tbp" <tbp...@gmail.com>
Date: 10 May 2005 03:36:54 -0700
Local: Tues 10 May 2005 11:36
Subject: Re: Mini ray tracer
Jon Harrop wrote:
> tbp wrote:
> My post is more about clarity and less about performance. Your

proposed
Oh? Silly me, i thought it was a benchmark.

> alterations make the C++ implementation significantly longer and more
> obfuscated and your littering of the source code with "inline"
actually
> slows the program down on my Athlon t-bird.

I've put explicit inlines because, ie for Vec operators, you've put
them outside of the class scope, hence screwing the common heuristic
saying that a member function declared & defined within the class body
should be inlined (and that's a much stronger hint than using an
'inline' directive).
Anyway, that's decoration compared to other issues in your source.

> Moreover, your choices of initial optimisation are decidedly
suboptimal. I'd
> have gone for:

Hmm? I tinker with a handful of lines, cut the runtime in half and
that's suboptimal?
Interesting.

> 1. Terminating the intersection of shadow rays when the first
intersection
> is found (instead of finding the closest intersection).

> 2. Use an implicit scene, to avoid storing it explicitly.

> 3. Use single-precision storage (or no storage at all).

> Both of these optimisations will give much bigger performance
improvements
> when averaged over different platforms and architectures.

Your aproach & space partition (as presented) will never give runtime
performance worth the time it takes to implement efficiently.
Such a sphere flake should render in a blink of the eye on modern
platforms, see the SPD for reference.
Or this: http://www.uni-koblenz.de/~cg/publikationen/cp_raytrace.pdf
I've merely fixed the most glaring flaws in your implementation.
Period.

> As it happens, I had already implemented all of your optimisations
and all
> of these optimisations to both implementations before I made my
original
> post. None of them add anything new. Sometimes C++ is faster,
sometimes
> OCaml is faster. OCaml is always much more succinct. You can keep
doing
> this until you are blue in the face but I don't think you'll learn
much of
> interest.

I've never contested that OCaml is more succint, expressive or elegant.
I'm just saying that, given the horrible c++ implementation you've
presented, you have absolutely no authority or qualification to say
anything about the relative merit of c++ & OCaml performance wise.

> Both ocamlopt and g++ were allowed to inline code.

It's all about exposing oportunities to do so.

> As OCaml is for symbolic use, it performs no inlining by default
(unlike
> g++) so it is common to ask OCaml to do some inlining on numerical
code.
> Thus, specifying "-inline 100" actually makes for a fairer

comparison.
No. You've used none of the c++ idiom that actually helps a c++
compiler to guess what to inline or not.
Know your compiler (or in that case, your language).

> Both implementations use pass by value as this is clearer, shorter
and (as a
> consequence) more common in real code.

Absolute non sense.
I can't beleive you really think that, but if that's the case, then you
should get back to your homework.

> If you want a fair comparison then you should also make equivalent
changes
> to the OCaml implementation.

You're the one trying to sell books about OCaml...

> You are trying to compare optimised C++ against unoptimised OCaml,
which
> would be unfair. More worryingly, you seem to have skipped the part
of the
> experiment where you actually measure something.

I've provided patches. See for yourself.

> When restricted to 80 columns, your optimisations add several lines.
Indeed,
> they push the C++ program over 100 LOC limit imposed by the creators
of the
> shootout.

You want to fit in those artificial constraints? Shorten names or
define some macros.
What was the fuss about already?

> In fact, I'd already implemented your optimisations (and many more
effective
> optimisations) and had to throw them out because of this limit. Note
that
> the OCaml has 30 more lines with which to optimise. My optimised <100
LOC
> OCaml program is much faster than my optimised <100 LOC C++ on all
> platforms.

Sure. I mean you've shown such a level of C++ wizardry that we're
supposed to take your word for it?

> > You'll notice i haven't even fixed the gratitious use of virtual
> > functions,

> What would you recommend instead?

Not using virtual functions in the hotpath.
Primo, that's uncalled for as your "hierarchy" doesn't mix types at a
given level, each object's type is known upfront.
Secundo, virtual functions are expensive because they forbid inlining
and are implemented as indirect branches , like:
  401c83:       callq  *0x8(%rax)
It doesn't make sense to use an expensive feature in the hotpath if you
can avoid it.
And you definitely can.

> I chose an inheritance hierarchy because this is the closest C++
equivalent
> to a variant type which I see in typical C++ programs.

> Another optimisation that I made was to replace inheritance with a
single
> Scene struct which represented a group of child scenes or a sphere
when it
> had no children. I threw this out as well because it is not a fair
> equivalent to OCaml's variant type. For example, you could not
specify a
> colour for each sphere without also specifying colours for all
bounding
> volumes.

That's totally orthogonal.
Please do yourself a favor and read a good book about C++.

> > and other details
> Can you elaborate on these other "details"?

Strictly speaking of your implementation details (and not algorithm or
anything), you've also failed the const correctness test for example.
But i suppose you're going to say say that it's cruft or obfuscation.

> > that force standard compliant c++
> > compilers to pessimize a lot when facing such... hmm.. source.

> Manually implementing pass constant by reference is both obfuscating
and
> error-prone whilst being theoretically unnecessary. The fact that the
OCaml
> compiler does this optimisation for you when the GNU C++ compiler
does not
> might interest some people.

I think you've just discovered that OCaml & C++ are two different
language that require the programmer to express things in a totally
different way.
And before you propose ways to improve C++ you should learn the
language first.

> Everyone will be free to contribute to the shootout version of the
ray
> tracer. Perhaps you would like to contribute a less "fishy" C++
> implementation?

I don't have books to sell.
If/When i write a raytracer, i choose a path that at least has some
chances to perform decently.
See Wald & Havran.

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message, you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jon Harrop  
View profile
 More options 10 May 2005, 16:17
Newsgroups: comp.graphics.rendering.raytracing
From: Jon Harrop <use...@jdh30.plus.com>
Date: Tue, 10 May 2005 16:17:23 +0100
Local: Tues 10 May 2005 16:17
Subject: Re: Mini ray tracer