Package ca.eandb.jmist.framework.geometry.primitive

Source Code of ca.eandb.jmist.framework.geometry.primitive.BoxGeometry

/**
* Java Modular Image Synthesis Toolkit (JMIST)
* Copyright (C) 2008-2013 Bradley W. Kimmel
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package ca.eandb.jmist.framework.geometry.primitive;

import ca.eandb.jmist.framework.Intersection;
import ca.eandb.jmist.framework.IntersectionRecorder;
import ca.eandb.jmist.framework.ShadingContext;
import ca.eandb.jmist.framework.geometry.PrimitiveGeometry;
import ca.eandb.jmist.framework.random.RandomUtil;
import ca.eandb.jmist.framework.random.SeedReference;
import ca.eandb.jmist.math.Basis3;
import ca.eandb.jmist.math.Box2;
import ca.eandb.jmist.math.Box3;
import ca.eandb.jmist.math.Point2;
import ca.eandb.jmist.math.Point3;
import ca.eandb.jmist.math.Ray3;
import ca.eandb.jmist.math.Sphere;
import ca.eandb.jmist.math.Vector3;

/**
* An axis aligned box <code>SceneElement</code>.
* @author Brad Kimmel
*/
public final class BoxGeometry extends PrimitiveGeometry {

  /** Serialization version ID. */
  private static final long serialVersionUID = 2733253411334817090L;

  /**
   * Creates a new <code>BoxGeometry</code>.
   * @param box The axis aligned <code>Box3</code> to be rendered.
   */
  public BoxGeometry(Box3 box) {
    this.box = box;
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.geometry.PrimitiveGeometry#intersect(ca.eandb.jmist.math.Ray3, ca.eandb.jmist.framework.IntersectionRecorder)
   */
  public void intersect(Ray3 ray, IntersectionRecorder recorder) {

    // Check for an empty box.
    if (!this.box.isEmpty()) {

      assert(ray.direction().x() != 0.0 || ray.direction().y() != 0.0 || ray.direction().z() != 0.0);

      double    t;
      int      n = 0;
      Point3    p;

      // Check for intersection with each of the six sides of the box.
      if (ray.direction().x() != 0.0) {
        t = (box.minimumX() - ray.origin().x()) / ray.direction().x();
        if (t > 0.0) {
          p = ray.pointAt(t);
          if (box.minimumY() < p.y() && p.y() < box.maximumY() && box.minimumZ() < p.z() && p.z() < box.maximumZ()) {
            Intersection x = super.newIntersection(ray, t, ray.direction().x() > 0.0, BOX_SURFACE_MIN_X)
              .setLocation(p);
            recorder.record(x);
            if (++n == 2) return;
          }
        }

        t = (box.maximumX() - ray.origin().x()) / ray.direction().x();
        if (t > 0.0) {
          p = ray.pointAt(t);
          if (box.minimumY() < p.y() && p.y() < box.maximumY() && box.minimumZ() < p.z() && p.z() < box.maximumZ()) {
            Intersection x = super.newIntersection(ray, t, ray.direction().x() < 0.0, BOX_SURFACE_MAX_X)
              .setLocation(p);
            recorder.record(x);
            if (++n == 2) return;
          }
        }
      }

      if (ray.direction().y() != 0.0) {
        t = (box.minimumY() - ray.origin().y()) / ray.direction().y();
        if (t > 0.0) {
          p = ray.pointAt(t);
          if (box.minimumX() < p.x() && p.x() < box.maximumX() && box.minimumZ() < p.z() && p.z() < box.maximumZ()) {
            Intersection x = super.newIntersection(ray, t, ray.direction().y() > 0.0, BOX_SURFACE_MIN_Y)
              .setLocation(p);
            recorder.record(x);
            if (++n == 2) return;
          }
        }

        t = (box.maximumY() - ray.origin().y()) / ray.direction().y();
        if (t > 0.0) {
          p = ray.pointAt(t);
          if (box.minimumX() < p.x() && p.x() < box.maximumX() && box.minimumZ() < p.z() && p.z() < box.maximumZ()) {
            Intersection x = super.newIntersection(ray, t, ray.direction().y() < 0.0, BOX_SURFACE_MAX_Y)
              .setLocation(p);
            recorder.record(x);
            if (++n == 2) return;
          }
        }
      }

      if (ray.direction().z() != 0.0) {
        t = (box.minimumZ() - ray.origin().z()) / ray.direction().z();
        if (t > 0.0) {
          p = ray.pointAt(t);
          if (box.minimumX() < p.x() && p.x() < box.maximumX() && box.minimumY() < p.y() && p.y() < box.maximumY()) {
            Intersection x = super.newIntersection(ray, t, ray.direction().z() > 0.0, BOX_SURFACE_MIN_Z)
              .setLocation(p);
            recorder.record(x);
            if (++n == 2) return;
          }
        }

        t = (box.maximumZ() - ray.origin().z()) / ray.direction().z();
        if (t > 0.0) {
          p = ray.pointAt(t);
          if (box.minimumX() < p.x() && p.x() < box.maximumX() && box.minimumY() < p.y() && p.y() < box.maximumY()) {
            Intersection x = super.newIntersection(ray, t, ray.direction().z() < 0.0, BOX_SURFACE_MAX_Z)
              .setLocation(p);
            recorder.record(x);
            if (++n == 2) return;
          }
        }
      }

    }

  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.AbstractGeometry#getBasis(ca.eandb.jmist.framework.AbstractGeometry.GeometryIntersection)
   */
  @Override
  protected Basis3 getBasis(GeometryIntersection x) {
    return Basis3.fromW(x.getNormal(), Basis3.Orientation.RIGHT_HANDED);
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.AbstractGeometry#getNormal(ca.eandb.jmist.framework.AbstractGeometry.GeometryIntersection)
   */
  @Override
  protected Vector3 getNormal(GeometryIntersection x) {
    switch (x.getTag())
    {
    case BOX_SURFACE_MAX_X:  return Vector3.I;
    case BOX_SURFACE_MIN_X:  return Vector3.NEGATIVE_I;
    case BOX_SURFACE_MAX_Y:  return Vector3.J;
    case BOX_SURFACE_MIN_Y:  return Vector3.NEGATIVE_J;
    case BOX_SURFACE_MAX_Z:  return Vector3.K;
    case BOX_SURFACE_MIN_Z:  return Vector3.NEGATIVE_K;
    default:        assert(false); return null;
    }
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.AbstractGeometry#getTextureCoordinates(ca.eandb.jmist.framework.AbstractGeometry.GeometryIntersection)
   */
  @Override
  protected Point2 getTextureCoordinates(GeometryIntersection x) {

    Point2  facePoint;
    Point3  p = x.getPosition();

    switch (x.getTag())
    {
    case BOX_SURFACE_MAX_X:
      facePoint = new Point2(
          (box.maximumZ() - p.z()) / box.lengthX(),
          (box.maximumY() - p.y()) / box.lengthY()
      );
      break;

    case BOX_SURFACE_MIN_X:
      facePoint = new Point2(
          (p.z() - box.minimumZ()) / box.lengthZ(),
          (box.maximumY() - p.y()) / box.lengthY()
      );
      break;

    case BOX_SURFACE_MAX_Y:
      facePoint = new Point2(
          (p.x() - box.minimumX()) / box.lengthX(),
          (p.z() - box.minimumZ()) / box.lengthZ()
      );
      break;

    case BOX_SURFACE_MIN_Y:
      facePoint = new Point2(
          (p.x() - box.minimumX()) / box.lengthX(),
          (box.maximumZ() - p.z()) / box.lengthZ()
      );
      break;

    case BOX_SURFACE_MAX_Z:
      facePoint = new Point2(
          (p.x() - box.minimumX()) / box.lengthX(),
          (box.maximumY() - p.y()) / box.lengthY()
      );
      break;

    case BOX_SURFACE_MIN_Z:
      facePoint = new Point2(
          (p.x() - box.minimumX()) / box.lengthX(),
          (p.y() - box.minimumY()) / box.lengthY()
      );
      break;

    default:
      throw new IllegalArgumentException("invalid surface id");

    }

    return new Point2(
      FACE_DOMAIN[x.getTag()].minimumX() + facePoint.x() * FACE_DOMAIN[x.getTag()].lengthX(),
      FACE_DOMAIN[x.getTag()].minimumY() + facePoint.y() * FACE_DOMAIN[x.getTag()].lengthY()
    );

  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.SceneElement#isClosed()
   */
  public boolean isClosed() {
    return true;
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.Bounded3#boundingBox()
   */
  public Box3 boundingBox() {
    return this.box;
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.Bounded3#boundingSphere()
   */
  public Sphere boundingSphere() {
    return new Sphere(this.box.center(), this.box.diagonal() / 2.0);
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.geometry.PrimitiveGeometry#generateRandomSurfacePoint(ca.eandb.jmist.framework.ShadingContext)
   */
  @Override
  public void generateRandomSurfacePoint(ShadingContext context, double ru, double rv, double rj) {
    double xyArea = box.lengthX() * box.lengthY();
    double xzArea = box.lengthX() * box.lengthZ();
    double yzArea = box.lengthY() * box.lengthZ();

    SeedReference ref = new SeedReference(rj);
    double total = xyArea + xzArea + yzArea;
    boolean dir = RandomUtil.coin(ref);
    int id;
    Point3 p;

    ref.seed *= total;

    if (ref.seed < xyArea) {
      id = dir ? BOX_SURFACE_MAX_Z : BOX_SURFACE_MIN_Z;
      p = new Point3(
          RandomUtil.uniform(box.spanX(), ru),
          RandomUtil.uniform(box.spanY(), rv),
          dir ? box.maximumZ() : box.minimumZ());
    } else if (ref.seed < xyArea + xzArea) {
      id = dir ? BOX_SURFACE_MAX_Y : BOX_SURFACE_MIN_Y;
      p = new Point3(RandomUtil.uniform(box.spanX(), ru),
          dir ? box.maximumY() : box.minimumY(),
          RandomUtil.uniform(box.spanZ(), rv));

    } else {
      id = dir ? BOX_SURFACE_MAX_X : BOX_SURFACE_MIN_X;
      p = new Point3(dir ? box.maximumX() : box.minimumX(),
          RandomUtil.uniform(box.spanY(), ru),
          RandomUtil.uniform(box.spanZ(), rv));
    }

    Intersection x = newSurfacePoint(p, id);
    x.prepareShadingContext(context);
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.geometry.AbstractGeometry#getSurfaceArea()
   */
  @Override
  public double getSurfaceArea() {
    return box.surfaceArea();
  }

  /** The surface id for the side facing toward the positive x-axis. */
  private static final int BOX_SURFACE_MAX_X = 0;

  /** The surface id for the side facing toward the negative x-axis. */
  private static final int BOX_SURFACE_MIN_X = 1;

  /** The surface id for the side facing toward the positive y-axis. */
  private static final int BOX_SURFACE_MAX_Y = 2;

  /** The surface id for the side facing toward the negative y-axis. */
  private static final int BOX_SURFACE_MIN_Y = 3;

  /** The surface id for the side facing toward the positive z-axis. */
  private static final int BOX_SURFACE_MAX_Z = 4;

  /** The surface id for the side facing toward the negative z-axis. */
  private static final int BOX_SURFACE_MIN_Z = 5;

  /**
   * The <code>Box2</code>s that each face on the cube map to in texture
   * coordinate space.
   */
  private static final Box2 FACE_DOMAIN[] = {
      new Box2(2.0 / 3.0, 1.0 / 4.0, 1.0, 1.0 / 2.0),
      new Box2(0.0, 1.0 / 4.0, 1.0 / 3.0, 1.0 / 2.0),
      new Box2(1.0 / 3.0, 0.0, 2.0 / 3.0, 1.0 / 4.0),
      new Box2(1.0 / 3.0, 1.0 / 2.0, 2.0 / 3.0, 3.0 / 4.0),
      new Box2(1.0 / 3.0, 1.0 / 4.0, 2.0 / 3.0, 1.0 / 2.0),
      new Box2(1.0 / 3.0, 3.0 / 4.0, 2.0 / 3.0, 1.0)
  };

  /** The <code>Box3</code> that represents this <code>SceneElement</code>. */
  private final Box3 box;

}
TOP

Related Classes of ca.eandb.jmist.framework.geometry.primitive.BoxGeometry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.