public Color trace(Scene scene) { // find first intersection point with scene objects Hit firstHit = scene.intersect(this); // calculate light intensity/color at hit point if (firstHit == null) { return new Color(0, 0, 0); } Material material = firstHit.getShape().getMaterial(); Color result = new Color(0, 0, 0); result = result.add(material.computeAmbient(scene.getAmbientLight())); for (LightSource light : scene.getLightSources()) { Vector direction = light.getPosition().sub(firstHit.getIntersectionPoint()).normalize(); Vector offset = direction.mult(OFFSET); Ray shadowRay = new Ray(direction, firstHit.getIntersectionPoint().add(offset), recursionDepth); Hit intersection = scene.intersect(shadowRay); if (intersection == null) { result = result.add(material.computeDiffuseLight(firstHit, light)); result = result.add(material.computeSpecularLight(firstHit, light)); } } if (recursionDepth > 0) { float n1 = material.getRefractionMediumOutside(); float n2 = material.getRefractionMediumInside(); float reflectionAbility = 1; if (n1 > 0 && n2 > 0) { Refraction refractionIn = getRefraction(direction, firstHit.getNormal(), n1, n2); if (refractionIn != null) { reflectionAbility = refractionIn.reflectionAbility; Vector offset = refractionIn.direction.mult(OFFSET); Ray refractionRay = new Ray( refractionIn.direction, firstHit.getIntersectionPoint().add(offset), recursionDepth); Hit outHit = scene.intersect(refractionRay); Refraction refractionOut = getRefraction(refractionRay.direction, outHit.getNormal().mult(-1), n2, n1); if (refractionOut != null) { Ray outRay = new Ray( refractionOut.direction, outHit.getIntersectionPoint().add(refractionOut.direction.mult(OFFSET)), recursionDepth - 1); result = result.add(outRay.trace(scene).modulate(refractionIn.transmissionAbility)); } } } if (material.getReflectionCo() > 0) { Vector direction = getReflection(this.direction, firstHit.getNormal()); Vector offset = direction.mult(OFFSET); Ray reflectionRay = new Ray(direction, firstHit.getIntersectionPoint().add(offset), recursionDepth - 1); result = result.add( reflectionRay .trace(scene) .modulate(material.getReflectionCo() * reflectionAbility)); } } return result; }