Package ca.eandb.jmist.framework.job.bidi

Source Code of ca.eandb.jmist.framework.job.bidi.MultipleImportanceSamplingStrategy

/**
* 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.job.bidi;

import ca.eandb.jmist.framework.Function1;
import ca.eandb.jmist.framework.Lens;
import ca.eandb.jmist.framework.Light;
import ca.eandb.jmist.framework.Random;
import ca.eandb.jmist.framework.path.PathInfo;
import ca.eandb.jmist.framework.path.PathNode;
import ca.eandb.jmist.framework.path.PathUtil;
import ca.eandb.jmist.framework.path.ScatteringNode;
import ca.eandb.jmist.math.MathUtil;
import ca.eandb.jmist.math.Point2;
import ca.eandb.jmist.math.Vector3;

/**
* @author Brad
*
*/
public final class MultipleImportanceSamplingStrategy implements BidiPathStrategy {

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

  private final int maxLightDepth;

  private final int maxEyeDepth;

  private final Function1 heuristic;

  /**
   * @param maxLightDepth
   * @param maxEyeDepth
   * @param heuristic
   */
  public MultipleImportanceSamplingStrategy(int maxLightDepth, int maxEyeDepth, Function1 heuristic) {
    this.maxLightDepth = maxLightDepth;
    this.maxEyeDepth = maxEyeDepth;
    this.heuristic = heuristic;
  }

  public static final MultipleImportanceSamplingStrategy useBalanceHeuristic(
      int maxLightDepth, int maxEyeDepth) {
    return new MultipleImportanceSamplingStrategy(maxLightDepth,
        maxEyeDepth, null);
  }

  public static final MultipleImportanceSamplingStrategy usePowerHeuristic(
      int maxLightDepth, int maxEyeDepth) {
    return new MultipleImportanceSamplingStrategy(maxLightDepth,
        maxEyeDepth, new Function1() {
          private static final long serialVersionUID = -343284523840769794L;
          public double evaluate(double x) {
            return x * x;
          }
        });
  }

  public static final MultipleImportanceSamplingStrategy usePowerHeuristic(
      final double exp, int maxLightDepth, int maxEyeDepth) {
    return new MultipleImportanceSamplingStrategy(maxLightDepth,
        maxEyeDepth, new Function1() {
          private static final long serialVersionUID = -3002611588758156695L;
          public double evaluate(double x) {
            return Math.pow(x, exp);
          }
        });
  }

  private void bp() {

  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.path.BidiPathStrategy#getWeight(ca.eandb.jmist.framework.path.PathNode, ca.eandb.jmist.framework.path.PathNode)
   */
  public double getWeight(PathNode lightNode, PathNode eyeNode) {

    int s = getNodeDepth(lightNode);
    int t = getNodeDepth(eyeNode);
    int k = s + t - 1;

    if (k < 0) {
      return 0.0;
    }

    if (k < 1) {
      return 0.0;
    }

//    if (k != 2) {
//      return 0.0;
//    }
//    if (t < 2) {
//      return 0.0;
//    }

    double gle = lightNode == null || eyeNode == null ? 1.0
        : PathUtil.getGeometricFactor(lightNode, eyeNode);
    double[] pdf = new double[k + 2];

    pdf[s] = 1.0;

    // Shorter eye path, longer light path
    if (eyeNode != null) {
      if (s < maxLightDepth) {
        if (lightNode != null) {
          Vector3 v = PathUtil.getDirection(lightNode, eyeNode);
          double ratio = (lightNode.getPDF(v) * gle)
              / (eyeNode.getPDF() * eyeNode.getGeometricFactor());
          //if (ratio < 0.0) bp();
          pdf[s + 1] = pdf[s] * Math.max(ratio, 0.0);
        } else if (eyeNode instanceof ScatteringNode) {
          ScatteringNode scatNode = (ScatteringNode) eyeNode;
          double ratio = scatNode.getSourcePDF()
              / (eyeNode.getPDF() * eyeNode.getGeometricFactor());
          //if (ratio < 0.0) bp();
          pdf[s + 1] = pdf[s] * Math.max(ratio, 0.0);
        }
      }

      PathNode zjp2 = lightNode;
      PathNode zjp1 = eyeNode; // z_{j+1}, j == k - i
      for (int i = s + 1; i <= k; i++) {
        if (i + 1 > maxLightDepth) {
          break;
        }

        PathNode zj = zjp1.getParent();
        double rpdf = 0.0;
        if (zjp2 != null) {
          Vector3 v = PathUtil.getDirection(zjp2, zjp1);
          rpdf = zjp2.isSpecular() ? zjp2.getPDF() : zjp1.getReversePDF(v);
        } else if (zjp1 instanceof ScatteringNode) {
          ScatteringNode scatNode = (ScatteringNode) zjp1;
          Vector3 v = PathUtil.getDirection(zjp1, zj);
          rpdf = scatNode.getSourcePDF(v);
        }
        double ratio = (rpdf * zjp1.getGeometricFactor())
            / (zj.getPDF() * zj.getGeometricFactor());

        if (ratio < 0.0) bp();

        pdf[i + 1] = pdf[i] * Math.max(ratio, 0.0);

        zjp2 = zjp1;
        zjp1 = zj;
      }

      PathNode zj = eyeNode;
      boolean specular = false;
      for (int i = s; i <= k; i++) {
        if (specular) {
          pdf[i + 1] = 0.0;
        }
        specular = zj.isSpecular();
        if (specular) {
          pdf[i + 1] = 0.0;
        }
        zj = zj.getParent();
      }
    }

    // Shorter light path, longer eye path
    if (lightNode != null) {
      if (t < maxEyeDepth) {
        if (eyeNode != null) {
          Vector3 v = PathUtil.getDirection(eyeNode, lightNode);
          double ratio = (eyeNode.getPDF(v) * gle)
              / (lightNode.getPDF() * lightNode.getGeometricFactor());
          //if (ratio < 0.0) bp();
          pdf[s - 1] = pdf[s] * Math.max(ratio, 0.0);
        } else {
          /* Here the ratio has in the numerator the probability density
           * of selecting the node at the end of the light path (i.e.,
           * lightNode) as the starting point for an eye path.  Since we
           * do not currently support intersections with the aperture,
           * this probability is zero.  Therefore pdf[s - 1] == 0.0, so
           * we have nothing to do here.
           */
        }
      }

      PathNode yip1 = eyeNode;
      PathNode yi = lightNode;
      for (int i = s - 1; i > 0; i--) {
        if (k + 2 - i > maxEyeDepth) {
          break;
        }

        PathNode yim1 = yi.getParent();
        double rpdf = yip1 != null
            ? (yip1.isSpecular() ? yip1.getPDF() : yi.getReversePDF(PathUtil.getDirection(yip1, yi)))
            : 0.0;
        double ratio = (rpdf * yi.getGeometricFactor())
            / (yim1.getPDF() * yim1.getGeometricFactor());

        //if (ratio < 0) bp();
        pdf[i - 1] = pdf[i] * Math.max(ratio, 0.0);

        yip1 = yi;
        yi = yim1;
      }

      PathNode yim1 = lightNode;
      boolean specular = false;
      for (int i = s; i > 0; i--) {
        if (specular) {
          pdf[i - 1] = 0.0;
        }
        specular = yim1.isSpecular();
        if (specular) {
          pdf[i - 1] = 0.0;
        }
        yim1 = yim1.getParent();
      }
    }

    pdf[k + 1] = 0.0; // Aperture not modeled as part of the scene
    //pdf[k] = 0.0;
    //pdf[k-1] = 0.0;

    if (heuristic != null) {
      for (int i = 0; i < pdf.length; i++) {
        pdf[i] = heuristic.evaluate(pdf[i]);
      }
    }
    double total = MathUtil.sum(pdf);

    if (pdf[s] / total > 1.0 + MathUtil.EPSILON) {
      bp();
    }
    return pdf[s] / total;
  }

  private final int getNodeDepth(PathNode node) {
    return node != null ? node.getDepth() + 1 : 0;
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.path.BidiPathStrategy#traceEyePath(ca.eandb.jmist.framework.Lens, ca.eandb.jmist.math.Point2, ca.eandb.jmist.framework.path.PathInfo, ca.eandb.jmist.framework.Random)
   */
  public PathNode traceEyePath(Lens lens, Point2 p, PathInfo pathInfo,
      Random rnd) {
    if (maxEyeDepth > 0) {
      PathNode head = lens.sample(p, pathInfo, rnd.next(), rnd.next(), rnd.next());
      return PathUtil.expand(head, maxEyeDepth - 1, rnd);
    }
    return null;
  }

  /* (non-Javadoc)
   * @see ca.eandb.jmist.framework.path.BidiPathStrategy#traceLightPath(ca.eandb.jmist.framework.Light, ca.eandb.jmist.framework.path.PathInfo, ca.eandb.jmist.framework.Random)
   */
  public PathNode traceLightPath(Light light, PathInfo pathInfo, Random rnd) {
    if (maxLightDepth > 0) {
      PathNode head = light.sample(pathInfo, rnd.next(), rnd.next(), rnd.next());
      return PathUtil.expand(head, maxLightDepth - 1, rnd);
    }
    return null;
  }

}
TOP

Related Classes of ca.eandb.jmist.framework.job.bidi.MultipleImportanceSamplingStrategy

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.