/** * Tests this surface for intersection with ray. If an intersection is found record is filled out * with the information about the intersection and the method returns true. It returns false * otherwise and the information in outRecord is not modified. * * @param outRecord the output IntersectionRecord * @param ray the ray to intersect * @return true if the surface intersects the ray */ public boolean intersect(IntersectionRecord outRecord, Ray rayIn) { // TODO#A2: fill in this function. Vector3d p = rayIn.origin.clone().sub(center); Vector3d d = rayIn.direction.clone(); double discr = Math.pow(d.dot(p), 2) - (d.dot(d)) * (p.dot(p) - Math.pow(radius, 2)); if (discr >= 0) { double tPlus = (-d.dot(p) + Math.sqrt(discr)) / d.dot(d); double tMinus = (-d.dot(p) - Math.sqrt(discr)) / d.dot(d); double t = Math.min(tPlus, tMinus); if (t > rayIn.end || t < rayIn.start) return false; Vector3d intersect = new Vector3d(); rayIn.evaluate(intersect, t); outRecord.location.set(intersect); Vector3d normal = intersect.clone().sub(center).normalize(); outRecord.normal.set(normal); outRecord.t = t; outRecord.surface = this; return true; } return false; }
@Override public void getColor(float u, float v, Color outColor) { // TODO A4 // get our position if sphere is at 0, radius 1 (all that matters is ratios) Vector3d pt = getPositionFromUV(u, v); // create TBN inverse matrix Vector3d normal = (new Vector3d(pt.x, pt.y, pt.z)).normalize(); Vector3d tangent; if (u < .25 || (u > .5 && u < .75)) { tangent = (new Vector3d(1 / pt.x, 0, -1 / pt.z)).normalize(); } else { tangent = (new Vector3d(-1 / pt.x, 0, 1 / pt.z)).normalize(); } Vector3d bitangent = (normal.clone().cross(tangent.clone())).normalize(); Matrix3d invTBN = (new Matrix3d( tangent.x, bitangent.x, normal.x, tangent.y, bitangent.y, normal.y, tangent.z, bitangent.z, normal.z)) .invert(); // ~-- The rest of this function calculates the new normal --~ Vector3d newNormal = new Vector3d(); // first determine distance to closest disk center float divSize = (float) (1.0 / resolution); // -calculate column float modU = u % divSize; float closestColumn = (u - modU) / divSize; if (modU > divSize / 2) { closestColumn++; } // -calculate row float modV = v % divSize; float closestRow = (v - modV) / divSize; if (modV > divSize / 2) { closestRow++; } // -calculate distance float centerX = closestColumn * divSize; float centerY = closestRow * divSize; double distanceToCenter = Math.sqrt(Math.pow((centerX - u), 2) + Math.pow((centerY - v), 2)); // If we are on disk, use normal from disk center // (the following formula ensures a bumpRadius of 0.5 is tangent circles, and >=1 is full // overlap) double diskRadius = (divSize / 2) * (Math.sqrt(2 * bumpRadius)); if (distanceToCenter <= diskRadius) { Vector3d diskNormal = getPositionFromUV(centerX, centerY).normalize(); newNormal = multByMatrix(diskNormal, invTBN).normalize(); } // if not on disk, use position normalized as normal else { newNormal = multByMatrix(normal, invTBN).normalize(); } // Convert from [-1,1] to [0,1] to [0, 255] Vector3d converted = new Vector3d(); converted.setMultiple(0.5, newNormal.clone().normalize()); converted.add(0.5); Colord outColorAccurate = new Colord(converted); outColor.set(outColorAccurate); }