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

se.llbit.math.UVTriangle Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
/* Copyright (c) 2013 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.math;

/**
 * UV-mapped triangle
 *
 * @author Jesper Öqvist 
 */
public class UVTriangle {

  /**
   * Normal vector - normal to triangle vertices
   * in counterclockwise order
   */
  public final Vector3 n;

  private final Vector3 a;
  private final Vector3 b;
  private final Vector3 c;

  private final Vector3 b_a;
  private final Vector3 c_a;
  private final Vector3 c_b;
  private final Vector3 a_c;

  private final Vector2 sa;
  private final Vector2 sb;
  private final Vector2 sc;

  private final double d;
  private final double rn;

  /**
   * Construct a new triangle.
   */
  public UVTriangle(Vector3 v0, Vector3 v1, Vector3 v2, Vector2 s0,
      Vector2 s1, Vector2 s2) {

    a = new Vector3(v0);
    b = new Vector3(v1);
    c = new Vector3(v2);

    this.sa = new Vector2(s0);
    this.sb = new Vector2(s1);
    this.sc = new Vector2(s2);

    b_a = new Vector3();
    c_a = new Vector3();
    c_b = new Vector3();
    a_c = new Vector3();

    b_a.sub(b, a);
    c_a.sub(c, a);
    c_b.sub(c, b);
    a_c.sub(a, c);

    n = new Vector3();

    n.cross(b_a, c_a);
    rn = 1.0 / n.length();
    n.normalize();

    d = -n.dot(a);
  }

  /**
   * Find intersection between the ray and this triangle.
   *
   * @return true if the ray intersects the triangle
   */
  public boolean intersect(Ray ray) {
    double px = ray.o.x - QuickMath.floor(ray.o.x + ray.d.x * Ray.OFFSET);
    double py = ray.o.y - QuickMath.floor(ray.o.y + ray.d.y * Ray.OFFSET);
    double pz = ray.o.z - QuickMath.floor(ray.o.z + ray.d.z * Ray.OFFSET);

    // Test that the ray is heading toward the plane.
    double denom = ray.d.dot(n);
    if (denom < -Ray.EPSILON) {

      // Test for intersection with the plane at origin.
      double t = -(px * n.x + py * n.y + pz * n.z + d) / denom;
      if (t > -Ray.EPSILON && t < ray.t) {

        // Calculate plane intersection point.
        px = px + ray.d.x * t;
        py = py + ray.d.y * t;
        pz = pz + ray.d.z * t;

        // Calculate barycentric coordinates.
        double nax = c_b.y * (pz - b.z) - c_b.z * (py - b.y);
        double nay = c_b.z * (px - b.x) - c_b.x * (pz - b.z);
        double naz = c_b.x * (py - b.y) - c_b.y * (px - b.x);

        double nbx = a_c.y * (pz - c.z) - a_c.z * (py - c.y);
        double nby = a_c.z * (px - c.x) - a_c.x * (pz - c.z);
        double nbz = a_c.x * (py - c.y) - a_c.y * (px - c.x);

        double ncx = b_a.y * (pz - a.z) - b_a.z * (py - a.y);
        double ncy = b_a.z * (px - a.x) - b_a.x * (pz - a.z);
        double ncz = b_a.x * (py - a.y) - b_a.y * (px - a.x);

        // alpha, beta, gamma are the barycentric coordinates
        double alpha = (n.x * nax + n.y * nay + n.z * naz) * rn;
        double beta = (n.x * nbx + n.y * nby + n.z * nbz) * rn;
        double gamma = (n.x * ncx + n.y * ncy + n.z * ncz) * rn;

        if (alpha >= 0 && beta >= 0 && gamma >= 0) {

          ray.tNext = t;
          ray.u = alpha * sa.x + beta * sb.x + gamma * sc.x;
          ray.v = alpha * sa.y + beta * sb.y + gamma * sc.y;
          return true;
        }
      }
    }

    return false;
  }

  /**
   * @return Rotated copy of this triangle
   */
  public UVTriangle getYRotated() {
    Transform t = Transform.NONE.rotateY();
    Vector3 ar = new Vector3(a);
    ar.add(-0.5, -0.5, -0.5);
    t.apply(ar);
    ar.add(0.5, 0.5, 0.5);
    Vector3 br = new Vector3(b);
    br.add(-0.5, -0.5, -0.5);
    t.apply(br);
    br.add(0.5, 0.5, 0.5);
    Vector3 cr = new Vector3(c);
    cr.add(-0.5, -0.5, -0.5);
    t.apply(cr);
    cr.add(0.5, 0.5, 0.5);
    return new UVTriangle(ar, br, cr, sa, sb, sc);
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy