All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.llbit.chunky.renderer.scene.PreviewRayTracer Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
/* Copyright (c) 2013-2014 Jesper Öqvist 
 *
 * This file is part of Chunky.
 *
 * Chunky is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Chunky is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Chunky.  If not, see .
 */
package se.llbit.chunky.renderer.scene;

import se.llbit.chunky.renderer.WorkerState;
import se.llbit.chunky.world.Block;
import se.llbit.math.Ray;
import se.llbit.math.Vector3;

/**
 * @author Jesper Öqvist 
 */
public class PreviewRayTracer implements RayTracer {

  /**
   * Do a quick preview ray tracing for the current ray.
   */
  @Override public void trace(Scene scene, WorkerState state) {
    Ray ray = state.ray;
    if (scene.isInWater(ray)) {
      ray.setCurrentMaterial(Block.get(Block.WATER_ID), 0);
    } else {
      ray.setCurrentMaterial(Block.AIR, 0);
    }
    while (true) {
      if (!nextIntersection(scene, ray)) {
        if (mapIntersection(scene, ray)) {
          break;
        }
        break;
      } else if (ray.getCurrentMaterial() != Block.AIR && ray.color.w > 0) {
        break;
      } else {
        ray.o.scaleAdd(Ray.OFFSET, ray.d);
      }
    }

    if (ray.getCurrentMaterial() == Block.AIR) {
      scene.sky.getSkySpecularColor(ray);
    } else {
      scene.sun.flatShading(ray);
    }
  }

  /**
   * Calculate sky occlusion.
   * @return occlusion value
   */
  public static double skyOcclusion(Scene scene, WorkerState state) {
    Ray ray = state.ray;
    double occlusion = 1.0;
    while (true) {
      if (!nextIntersection(scene, ray)) {
        break;
      } else {
        occlusion *= (1 - ray.color.w);
        ray.o.scaleAdd(Ray.OFFSET, ray.d);
      }
    }
    return 1 - occlusion;
  }

  /**
   * Find next ray intersection.
   * @return Next intersection
   */
  public static boolean nextIntersection(Scene scene, Ray ray) {
    ray.setPrevMaterial(ray.getCurrentMaterial(), ray.getCurrentData());
    ray.t = Double.POSITIVE_INFINITY;
    boolean hit = false;
    if (scene.sky().cloudsEnabled()) {
      hit = scene.sky().cloudIntersection(scene, ray);
    }
    if (scene.waterHeight > 0) {
      hit = waterIntersection(scene, ray) || hit;
    }
    if (scene.intersect(ray)) {
      // Octree tracer handles updating distance.
      return true;
    }
    if (hit) {
      ray.distance += ray.t;
      ray.o.scaleAdd(ray.t, ray.d);
      scene.updateOpacity(ray);
      return true;
    } else {
      ray.setCurrentMaterial(Block.AIR, 0);
      return false;
    }
  }

  private static boolean waterIntersection(Scene scene, Ray ray) {
    if (ray.d.y < 0) {
      double t = (scene.waterHeight - .125 - ray.o.y - scene.origin.y) / ray.d.y;
      if (t > 0 && t < ray.t) {
        Vector3 vec = new Vector3();
        vec.scaleAdd(t + Ray.OFFSET, ray.d, ray.o);
        if (!scene.isInsideOctree(vec)) {
          ray.t = t;
          Block.get(Block.WATER_ID).getColor(ray);
          ray.n.set(0, 1, 0);
          ray.setCurrentMaterial(Block.get(Block.WATER_ID), 0);
          return true;
        }
      }
    }
    if (ray.d.y > 0) {
      double t = (scene.waterHeight - .125 - ray.o.y - scene.origin.y) / ray.d.y;
      if (t > 0 && t < ray.t) {
        Vector3 vec = new Vector3();
        vec.scaleAdd(t + Ray.OFFSET, ray.d, ray.o);
        if (!scene.isInsideOctree(vec)) {
          ray.t = t;
          Block.get(Block.WATER_ID).getColor(ray);
          ray.n.set(0, -1, 0);
          ray.setCurrentMaterial(Block.AIR, 0);
          return true;
        }
      }
    }
    return false;
  }

  private static boolean mapIntersection(Scene scene, Ray ray) {
    if (ray.d.y < 0) {
      double t = (scene.waterHeight - .125 - ray.o.y - scene.origin.y) / ray.d.y;
      if (t > 0 && t < ray.t) {
        Vector3 vec = new Vector3();
        vec.scaleAdd(t + Ray.OFFSET, ray.d, ray.o);
        if (!scene.isInsideOctree(vec)) {
          ray.t = t;
          ray.o.set(vec);
          double xm = (ray.o.x % 16.0 + 16.0) % 16.0;
          double zm = (ray.o.z % 16.0 + 16.0) % 16.0;
          if (xm > 0.6 && zm > 0.6) {
            ray.color.set(0.8, 0.8, 0.8, 1);
          } else {
            ray.color.set(0.25, 0.25, 0.25, 1);
          }
          ray.setCurrentMaterial(Block.get(Block.STONE_ID), 0);
          ray.n.set(0, 1, 0);
          return true;
        }
      }
    }
    return false;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy