Пример #1
0
  /**
   * 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);
  }