PixelBuff::Pixel Engine::RayTrace(const Ray &a,int dpt) const { //initialization PixelBuff::Pixel result; result.depth=FLT_MAX; float multiplier=1; Ray current=a; for(int i=0;i<dpt&&multiplier!=0;++i) { Scene::Intersection intersection; if(!scene->ClosestInt(current,intersection)) return result; //there was no intersection, so end tracing if(result.depth==FLT_MAX) //depth hasn't been set yet so do it result.depth=intersection.dst; Vector3 point=current.PointAtLen(intersection.dst); //here is the intersection point scene->SetSeenLights(point); //check which lights can be seen from point const Light* t; while((t=scene->NextLight())!=NULL) //for each light do: { Vector3 lightDir=t->GetLightDirAt(point); Color lightColor=t->GetLightColorAt(point); //add calculated color, multiplied by multiplier, to result.color result.color+=intersection.o->CalculateColorAt(lightColor,lightDir,current.Dir(),point)*multiplier; } //calculate reflected ray Vector3 normal=-intersection.o->GetNormalAt(point); current=Ray(point,a.Dir()-2*normal*Vector3::Dot(current.Dir(),normal)); multiplier*=intersection.o->GetReflectanceAt(point); //multiply by reflectance } return result; }
bool Plane::Intersects(const Ray& r,float& result) const { float VD=Vector3::Dot(normal,r.Dir()); if(VD==0) return false; float V0=-(Vector3::Dot(normal,r.Origin())+distance); result=V0/VD; if(result<EPSILON) //role of EPSILON is explained in "common.h" return false; return true; }
//------------------------------------------------------------- float Sphere :: Intersect( Ray& r ) { //------------------------------------------------------------- Vector dist = r.Start() - center; float b = (dist * r.Dir()) * 2.0; float a = (r.Dir() * r.Dir()); float c = (dist * dist) - radius * radius; float discr = b * b - 4.0 * a * c; if ( discr < 0 ) return -1; float sqrt_discr = sqrt( discr ); float t1 = (-b + sqrt_discr)/2.0/a; float t2 = (-b - sqrt_discr)/2.0/a; if (t1 < EPSILON) t1 = -EPSILON; if (t2 < EPSILON) t2 = -EPSILON; if (t1 < 0 && t2 < 0) return -1; float t; if ( t1 < 0 && t2 >= 0 ) t = t2; else if ( t2 < 0 && t1 >= 0 ) t = t1; else if (t1 < t2) t = t1; else t = t2; return t; }
//------------------------------------------------------------- SColor Scene :: IntersectShadow( Ray r, float maxt ) { //------------------------------------------------------------- SColor att = SColor(1); Primitive3D * p; while( (p = world.NextPrimitive( )) != NULL ) { float t = p -> Intersect( r ); if ( t > EPSILON && t < maxt) { Point x = r.Start() + r.Dir() * t; att *= p -> kt( x ); } } return att; }
//------------------------------------------------------------- SColor Scene :: Trace(Ray r, int d) { //------------------------------------------------------------- if (d > maxdepth) return La; Point x; Primitive3D * q = Intersect(r, x); if (q == NULL) return La; Vector normal = q -> Normal(x); bool out = TRUE; if ( normal * (-r.Dir()) < 0) { normal = -normal; out = FALSE; } SColor c = DirectLightsource(q, -r.Dir(), normal, x); if ( q->kr(x) != 0 ) { Vector reflectdir; q -> ReflectionDir(reflectdir, normal, -r.Dir(), x); c += q->kr(x) * Trace( Ray(x, reflectdir), d+1); } if ( q->kt(x) != 0 ) { Vector refractdir; if (q -> RefractionDir(refractdir, normal, -r.Dir(), x, out)) { c += q->kt(x) * Trace( Ray(x, refractdir), d+1); } } return c; }