Color shade(Hit hit) { // if no scObject was hit, return background color if (hit.scObject == null) return background; Color color = new Color(0,0,0); for(int i=0; i<numLights; i++){ // convenience for cleaner code Vector liPos = lights[i].position; // ambient reflection color = color + hit.scObject.ambient * lights[i].ambient; Vector p = hit.HitPoint(); Vector v = eye - p; Vector s = liPos - p; Vector m = hit.scObject.Normal(p); // make sure light hits the front face if (Vector.Dot(s, m) < 0) continue; // cast a "shadow feeler" and find its closest hit position to light source Hit feeler = intersect(liPos, p - liPos); Vector feelerHit = feeler.HitPoint(); // check that point is less 90 degrees therefore it is on the same side of light source as displayed point float dotLiFeel_LiPoint = Vector.Dot((liPos - feelerHit), liPos - p); bool correctLightSide = dotLiFeel_LiPoint >= 0; // check that the point is not the same point as the displayed point // and if it is closer to light source or further away float squaredLen_LiFeel = Vector.Dot((liPos - feelerHit), liPos - feelerHit); bool beforeObj = Math.Abs(dotLiFeel_LiPoint - squaredLen_LiFeel) < 0.0001; //0.0001 to stop float round error for <= //if there is a collision and it is closer than the displayed scObject and it is on the same side of light as scObject if( (feeler.t<=0) || ((beforeObj) && (correctLightSide)) ){ //diffuse reflection color = color + ( (hit.scObject.diffuse * lights[i].diffuse) * ( Vector.Dot(s, m) / Convert.ToSingle( (Math.Sqrt(Vector.Dot(s, s))*Math.Sqrt(Vector.Dot(m, m))) ) )); //specular reflection //h = normalized(normalized(s) + normalized(v)) Vector h = s.Normalize() + v.Normalize(); h = h.Normalize(); color = color + ( (hit.scObject.specular * lights[i].specular) * Convert.ToSingle( (Math.Pow(( Vector.Dot(h, m) / (Math.Sqrt(Vector.Dot(h, h))*Math.Sqrt(Vector.Dot(m, m))) ), hit.scObject.shininess) ) )); } } return color; }
Hit intersect(Vector source, Vector d) { // initially hit scObject==NULL (no hit) Hit hit = new Hit(source, d, -1f, null); // for every scObject, check if ray hits it for(int i=0; i<numObjects; i++) { float t = sceneObjects[i].Intersect(source, d); // 1. only use hits visible for the camera // 2. only overwrite hit if either there is // no hit yet, or the hit is closer if(t>0.00001 && (hit.scObject==null || t<hit.t)) hit = new Hit(source, d, t, sceneObjects[i]); } return hit; }