????C#?汾
using System;
using System.IO;
namespace smallpt_cs {
struct Vec {        // Usage: time ./smallpt 5000 && xv image.ppm
public double x??y??z;                 // position??also color (r??g??b)
public Vec(double x_??double y_??double z_) {x=x_;y=y_;z=z_;}
public static Vec operator +(Vec a??Vec b) {return new Vec(a.x+b.x??a.y+b.y??a.z+b.z);}
public static Vec operator -(Vec a??Vec b) {return new Vec(a.x-b.x??a.y-b.y??a.z-b.z);}
public static Vec operator *(Vec a??double b) {return new Vec(a.x*b??a.y*b??a.z*b);}
public Vec mult(Vec b) { return new Vec(x*b.x??y*b.y??z*b.z);}
public Vec norm() { return this=this*(1/Math.Sqrt(x*x+y*y+z*z));}
public double dot(Vec b) { return x*b.x+y*b.y+z*b.z;}//cross:
public static Vec operator %(Vec a??Vec b) { return new Vec(a.y*b.z-a.z*b.y??a.z*b.x-a.x*b.z??a.x*b.y-a.y*b.x);}
}
enum Refl_t { DIFF??SPEC??REFR }; // material types??used in radiance()
struct Ray { public Vec o??d;public Ray(Vec o_??Vec d_) { o=o_;d=d_;} }
class Sphere {
public double rad;      // radius
public Vec p??e??c;     // position??emission??color
public Refl_t refl;     // reflection type (DIFFuse??SPECular??REFRactive)
public Sphere(double rad_??Vec p_??Vec e_??Vec c_??Refl_t refl_) {
rad=rad_;p=p_;e=e_;c=c_;refl=refl_;
}
public double intersect(Ray r)
{ // returns distance??0 if nohit
Vec op=p-r.o;// Solve t^2*d.d+2*t*(o-p).d+(o-p).(o-p)-R^2=0
double t??eps=1e-4??b=op.dot(r.d)??det=b*b-op.dot(op)+rad*rad;
if (det<0) return 0;else det=Math.Sqrt(det);
return (t=b-det) > eps?t : ((t=b+det) > eps?t : 0);
}
};
class smallpt {
static Random random=new Random();
static double erand48() { return random.NextDouble();}
static Sphere[] spheres={//Scene: radius??position??emission??color??material
new Sphere(1e5??new Vec( 1e5+1??40.8??81.6)?? new Vec()??new Vec(.75??.25??.25)??Refl_t.DIFF)??//Left
new Sphere(1e5??new Vec(-1e5+99??40.8??81.6)??new Vec()??new Vec(.25??.25??.75)??Refl_t.DIFF)??//Rght
new Sphere(1e5??new Vec(50??40.8??1e5)??      new Vec()??new Vec(.75??.75??.75)??Refl_t.DIFF)??//Back
new Sphere(1e5??new Vec(50??40.8??-1e5+170)?? new Vec()??new Vec()??           Refl_t.DIFF)??//Frnt
new Sphere(1e5??new Vec(50??1e5??81.6)??      new Vec()??new Vec(.75??.75??.75)??Refl_t.DIFF)??//Botm
new Sphere(1e5??new Vec(50??-1e5+81.6??81.6)??new Vec()??new Vec(.75??.75??.75)??Refl_t.DIFF)??//Top
new Sphere(16.5??new Vec(27??16.5??47)??      new Vec()??new Vec(1??1??1)*.999?? Refl_t.SPEC)??//Mirr
new Sphere(16.5??new Vec(73??16.5??78)??      new Vec()??new Vec(1??1??1)*.999?? Refl_t.REFR)??//Glas
new Sphere(600??new Vec(50??681.6-.27??81.6)??new Vec(12??12??12)?? new Vec()??  Refl_t.DIFF) //Lite
};
static double clamp(double x) { return x<0?0 : x > 1?1 : x;}
static int toInt(double x) { return (int)(Math.Pow(clamp(x)??1 / 2.2)*255+.5);}
static bool intersect(Ray r??ref double t??ref int id) {
double d??inf=t=1e20;
for (int i=spheres.Length-1;i >= 0;i--)
if ((d=spheres[i].intersect(r)) != 0 && d<t) { t=d;id=i;}
return t<inf;
}
static Vec radiance(Ray r??int depth) {
double t=0;                              // distance to intersection
int id=0;                              // id of intersected object
if (!intersect(r??ref t??ref id)) return new Vec();// if miss??return black
Sphere obj=spheres[id];       // the hit object
Vec x=r.o+r.d*t??n=(x-obj.p).norm()??nl=n.dot(r.d)<0?n:n*-1??f=obj.c;
double p=f.x>f.y&&f.x>f.z?f.x:f.y>f.z?f.y:f.z;//max refl
if (++depth > 5) if (erand48()<p) f=f*(1 / p);else return obj.e;//R.R.
if (depth > 100) return obj.e;
if (obj.refl == Refl_t.DIFF) {                  // Ideal DIFFUSE reflection
double r1=2*Math.PI*erand48()??r2=erand48()??r2s=Math.Sqrt(r2);
Vec w=nl??u=((Math.Abs(w.x)>.1?new Vec(0??1??0):new Vec(1??0??0))%w).norm()??v=w%u;
Vec d=(u*Math.Cos(r1)*r2s+v*Math.Sin(r1)*r2s+w*Math.Sqrt(1-r2)).norm();
return obj.e+f.mult(radiance(new Ray(x??d)??depth));
}
else if (obj.refl == Refl_t.SPEC)            // Ideal SPECULAR reflection
return obj.e+f.mult(radiance(new Ray(x??r.d-n*2*n.dot(r.d))??depth));
Ray reflRay=new Ray(x??r.d-n*2*n.dot(r.d));//IdealdielectricREFRACTION
bool into=n.dot(nl) > 0;               // Ray from outside going in?
double nc=1??nt=1.5??nnt=into?nc / nt : nt / nc??ddn=r.d.dot(nl)??cos2t;
if ((cos2t=1-nnt*nnt*(1-ddn*ddn))<0)    //Total internal reflection
return obj.e+f.mult(radiance(reflRay??depth));
Vec tdir=(r.d*nnt-n*((into?1:-1)*(ddn*nnt+Math.Sqrt(cos2t)))).norm();
double a=nt-nc??b=nt+nc??R0=a*a/(b*b)??c=1-(into?-ddn:tdir.dot(n));
double Re=R0+(1-R0)*c*c*c*c*c??Tr=1-Re??P=.25+.5*Re??RP=Re/P??TP=Tr/(1-P);
return obj.e+f.mult(depth > 2?(erand48()<P?  // Russian roulette
radiance(reflRay??depth)*RP:radiance(new Ray(x??tdir)??depth)*TP):
radiance(reflRay??depth)*Re+radiance(new Ray(x??tdir)??depth)*Tr);
}
public static void Main(string[] args) {
DateTime start=DateTime.Now;
int w=256??h=256??samps=args.Length==2?int.Parse(args[1])/4:25;// # samples
Ray cam=new Ray(new Vec(50??52??295.6)??new Vec(0??-0.042612??-1).norm());//cam pos??dir
Vec cx=new Vec(w*.5135/h??0??0)??cy=(cx%cam.d).norm()*.5135??r;Vec[] c=new Vec[w*h];
for (int y=0;y<h;y++) {                        // Loop over image rows
Console.Write(" Rendering ({0}spp) {1:F2}%"??samps*4??100.0*y/(h-1));
for (int x=0;x<w;x++)   // Loop cols
for (int sy=0??i=(h-y-1)*w+x;sy<2;sy++)     // 2x2 subpixel rows
for (int sx=0;sx<2;sx++) {               // 2x2 subpixel cols
r=new Vec();
for (int s=0;s<samps;s++) {
double r1=2*erand48()??dx=r1<1?Math.Sqrt(r1)-1:1-Math.Sqrt(2-r1);
double r2=2*erand48()??dy=r2<1?Math.Sqrt(r2)-1:1-Math.Sqrt(2-r2);
Vec d=cx*(((sx+.5+dx)/2+x)/w-.5)+
cy*(((sy+.5+dy)/2+y)/h-.5)+cam.d;
r=r+radiance(new Ray(cam.o+d*140??d.norm())??0)*(1.0/samps);
} // Camera rays are pushed ^^^^^ forward to start in interior
c[i]=c[i]+new Vec(clamp(r.x)??clamp(r.y)??clamp(r.z))*.25;
}
}
Console.WriteLine(" {0} sec"??(DateTime.Now-start).TotalSeconds);
using (StreamWriter sw=new StreamWriter("image.ppm")) {
sw.Write("P3 {0} {1} {2} "??w??h??255);
for (int i=0;i<w*h;i++)
sw.Write("{0} {1} {2} "??toInt(c[i].x)??toInt(c[i].y)??toInt(c[i].z));
sw.Close();
}
}
}
}
????Vec??Ray?????????????в???????????????????struct??struct??C#?????????(value type)??ibpp???????Ч????????????????GC????????Sphere??????????????class???????????(reference type)??????????????
??????????????
??????黷????Visual Studio 2008/.Net Framework 3.5????Intel I7 920 (4????????)?????512x512???????????100???????????????:
????????汾 ???(??)
????(a) C++ 45.548
????(b) C# 61.044
????(c) C++ SIMD 20.500
????(d) C++(OpenMP) 7.397
????(e) C++ SIMD(OpenMP) 3.470
????(f)* C++ LCG 17.365
????(g)* C# LCG 59.623
????(h)* C++ LCG (OpenMP) 3.427
????*2010/6/23 ????(f)(g)(h)???????1
??????????????(a)??(b)??????????????? C++?汾?????C#?汾????34%??????????????????C#/.Net?????????????JIT????????????????????????????????
????????SIMD??C++?汾(c)???????δ???????????????????SIMD??汾??122%????C#?汾????????????????????SIMD????????????????????????????????ο???
????????OpenMP?????i7??8?????????????OpenMP???SIMD(d)??SIMD(e)?汾??????????OpenMP??汾(a)??(c)????????6.16????5.9??????????????????8??????????????????CPU?????????OpenMP??????????????????1???????#pragma???????????С?
????????
?????????????????????????????????????????????Щ??????C#/.Net???????????????C++?????С?????????????
???????????????????????в??????????????????????????????????????????????????????Java???????????
???????????????????????????????????????????????????????????????????????????????????????????????????????????????????