@Override public Spectrum shade(HitRecord hit, Light light) { Spectrum spectrum = new Spectrum(0.f, 0.f, 0.f); Vector3f hitPoint = hit.getIntersectionPoint(); Vector3f normal = hit.getNormal(); normal.normalize(); Spectrum cl = light.getCl(hitPoint); Vector3f L = light.getL(hitPoint); Vector3f rayDir = hit.getRayDir(); rayDir.normalize(); // Diffuse reflectance term float nDotL = normal.dot(L); if (nDotL >= 0) { spectrum.append(cl.multipliedBy(diffuse).multipliedBy(nDotL)); // Specular reflectance term Vector3f h = new Vector3f(L); h.sub(rayDir); h.normalize(); float hDotN = (float) Math.pow(h.dot(normal), shininess); spectrum.append(specular.multipliedBy(cl).multipliedBy(hDotN)); } // Ambient reflectance term cl = light.getCl(hitPoint); Spectrum amb = ambient.multipliedBy(cl); spectrum.append(amb); spectrum.clampMax(1.f); spectrum.clampMin(0.f); return spectrum; }
// Display checker board background MaterialCell checkerBackgroundHit(Ray r, HitRecord hit) { // Find the t value where z = scene.camera.far hit.t = -scene.camera.far / r.dir.z; if (hit.t < 0) // Only put it on the background, not behind the camera too return black; hit.hitP = r.pointAtParameter(hit.t); hit.normal = new Double3D(0, 0, 1); hit.hitP.x = (hit.hitP.x > 0) ? hit.hitP.x : -hit.hitP.x + checkerFreq / 2; hit.hitP.y = (hit.hitP.y > 0) ? hit.hitP.y : -hit.hitP.y + checkerFreq / 2; if (hit.hitP.x % checkerFreq < checkerFreq / 2) // && p.x < scene.camera.windowRight) if (hit.hitP.y % checkerFreq < checkerFreq / 2) // && p.y < scene.camera.windowTop) return white; else return black; else if (hit.hitP.y % checkerFreq < checkerFreq / 2) // && p.y < scene.camera.windowTop) return black; else return white; }
// All rays we deal with here are in world coordinates. // Should take the refractive index of the material it is currently in. DoubleColor trace(Ray ray) { DoubleColor color = new DoubleColor(0.0, 0.0, 0.0, 1.0); HitRecord hit = new HitRecord(); if (depth > Math.max(DEBUG_recursion, scene.maxRecursiveDepth)) return color; double tMin = 0.0001; double tMax = 10000000; // Spheres only for now for (int i = 0; i < numObjects; i++) // Did I hit the bounding sphere for an object? if (spheres[i].hit(ray, tMin, tMax, 0, hit)) if (scene.spheresOnly) { for (PMesh.SurfCell s = shapes[i].surfHead; s != null; s = s.next) for (PMesh.PolyCell poly = s.polyHead; poly != null; poly = poly.next) // Triangles only for now if (poly.numVerts == 3) { Double3D v[] = new Double3D[3]; int j = 0; for (PMesh.VertListCell vert = poly.vert; vert != null; vert = vert.next) v[j++] = shapes[i].vertArray.get(vert.vert).viewPos; // Increment j in the line post access // Check for a hit on this polygon if (Triangle.hit(v[0], v[1], v[2], ray, tMin, tMax, 0, hit)) { tMax = hit.t; hit.normal = poly.viewNorm; hit.matIndex = s.material; hit.index = i; } } else System.out.println( "Need to intersect polygon with " + poly.numVerts + " vertices."); } else { tMax = hit.t; hit.matIndex = i; // May cause an error if object 10 and it only has 3 materials. hit.index = i; } if (hit.index >= 0) // If it intersects then multi-sample { if (!sampled && depth == 0) { // Only sample once per ray from the main loop sampled = true; Double3D dir = ray.dir; DoubleColor antiAlias = trace(ray); for (int i = 0; i < samples; i++) { // Double3D sample = new Double3D(dir.x + imageSamples[i].x, dir.y + imageSamples[i].y, // dir.z).getUnit(); // ray.dir = sample; ray.dir.x = dir.x + imageSamples[i].x; ray.dir.y = dir.y + imageSamples[i].y; antiAlias.plus(trace(ray)); } antiAlias.scale(1.0 / (samples + 1.0)); color.plus(antiAlias); } else if (hit.matIndex < shapes[hit.index].materials.length) color = shade(ray, hit, shapes[hit.index].materials[hit.matIndex], false); else color = shade( ray, hit, shapes[hit.index].materials[shapes[hit.index].materials.length - 1], false); } else // We hit nothing check for intersection with the far clip plane for checker board // pattern. if (scene.checkerBackground) color = shade(ray, hit, checkerBackgroundHit(ray, hit), true); return color; }