GwieF.com : Project : Classes : Ray
logo

Ray.java


package com.gwief.jTrace;

/*
    Ray.java by Damian Newport
    Stores a Ray, and implements behavior to trace it
*/

public class Ray {

    Vector3D origin;
    Vector3D direction;
    
    public Ray(){
        origin = new Vector3D(0,0,0);
        direction = new Vector3D(0,0,0);
    }

    public Ray(Vector3D start, Vector3D dir){
        origin = new Vector3D(start);
        direction = new Vector3D(dir);
    }
    
    public Ray(Ray a){
        origin = new Vector3D(a.origin);
        direction = new Vector3D(a.direction);
    }
    
    public final Color3D trace(Scene3D scene,int deadray){
        Color3D color = new Color3D();
        Shape3D temp;
        deadray--;
        if (deadray < 1){
            return scene.background;
        }
        
        /* get intersection */
        Intersection point = traceRay(scene);
        if (point == null){
            return scene.background;
        }
        Shape3D hit = point.hit;
        
        /* find intersection point and normal */
        Vector3D intersect = new Vector3D(direction);
        intersect.multiply(point.value);
        intersect.add(origin);
        Vector3D normal = hit.getNormal(intersect);
        normal.unit();
        if (point.stype == -1){
            normal.negate();
        }

        /* Get unit vector to viewer */
        Vector3D V = new Vector3D(origin);
        V.minus(intersect);
        V.unit();
        
        /* find reflected ray - for use in reflection and specular lighting */
        double Rangle = 2 * normal.dot(V);
        Vector3D R = new Vector3D(normal);
        R.multiply(Rangle);
        R.minus(V);
        R.unit();
        
        /* Handles Transarency */
        if (hit.material.transparency > rayTrace.TINY){
            
            Ray tran = new Ray(intersect, direction);
            Color3D transparent = tran.trace(scene, deadray);
            transparent.multiply(hit.material.transparency);
            color.add(transparent);
        }
        
        /* Handles reflection */
        if (hit.material.reflect > rayTrace.TINY){

            Ray ref = new Ray(intersect, R);
            Color3D reflect = ref.trace(scene, deadray);
            reflect.multiply(hit.material.reflect);
            color.add(reflect);
        }
        

        /* Lighting */
        int lcount = scene.getNumLights();
        Light light;
        Vector3D L;
        Ray lightRay;
        double modulus;
        Intersection Check;
        
        /* for each light */
        for(int i = 0; i < lcount; i++){
            /* get current light */
            light = scene.getlight(i);

            /* work out ray from intersect to curent light */
            L = new Vector3D(light.position);
            L.minus(intersect);
            modulus = L.modulus();
            L.divide(modulus);
            
            if (normal.dot(L) > 0){
            
                lightRay = new Ray(intersect, L);

                /* check ray to light against all shapes */      
                Check = lightRay.traceRay(scene);
                if (Check != null){                 /* do you hit a shape? */
                    if (Check.value < modulus){     /* if you hit the shape before the light */
                        continue;                   /* skip current light */
                    }
                }
                /* If we got here we do this light */
                double val;

                /* Get intensity of light */
                /* using 1/n rather than 1/(n^2) for efficiency */
                double Ip = light.intensity / modulus;

                /* Specular Lighting*/
                /* Ip = source intensity */
                /* Ks = specular coefficient */

                /* Is = Ip * Ks *  (V.R)^n */
                double specular = hit.material.Ks * Ip * Math.pow(L.dot(R),hit.material.n);
                Color3D Is = new Color3D(light.color);
                Is.multiply(specular);
                color.add(Is);

                /* diffuse */
                /* Id = (Ip - Is) * Kd * cos(b) */
                /* Id = (Ip - Is) * Kd * (N . L) */
                val = normal.dot(L);
                if ((val > 0) && (val <= 1)){
                    double diffuse = (Ip - specular) * hit.material.Kd * val;
                    Color3D Id = new Color3D(hit.material.color);
                    Id.multiply(diffuse);
                    color.add(Id);
                }
            }
        }

        /* Ambient Lighting */
        /* Ia = Ka * La */
        /* Ka = ambient constant */
        /* La = incident light */
        Color3D Ia = new Color3D(scene.Ia);
        Ia.multiply(hit.material.color);
        
        color.add(Ia);
        
        return color;
    }
    
    /* returns intersection of ray (null if none) */
    public final Intersection traceRay(Scene3D scene){
        Intersection[] answer = scene.trace(this);
        int count = answer.length;
        if(count != 0){
            if (rayTrace.bugmode){
                System.out.println("----------TRACERAY---------");
                for(int i=0; i< count; i++){
                    System.out.println("answer[" + i + "].value = " + answer[i].value);
                    System.out.println("answer[" + i + "].type = " + answer[i].type);
                    System.out.println("answer[" + i + "].stype = " + answer[i].stype);
                    System.out.println("answer[" + i + "].name = " + answer[i].hit.name);
                }
            }
            for(int i=0; i < count; i++){
                if (answer[i].value > rayTrace.TINY){
                    if (answer[i].type == 1){
                        return answer[i];
                    }
                }
            }
            /* if we get here all intersections are < 0 */
            return null;
        }else{
            return null;
        }
        
    }
    
    public final Color3D debug(Scene3D scene,int deadray){
        System.out.println("---------START DEBUG---------");
        Color3D color = new Color3D();
        Shape3D temp;
        deadray--;
        if (deadray < 1){
            return scene.background;
        }
        
        /* get intersection */
        Intersection point = traceRay(scene);
        if (point == null){
            return scene.background;
        }
        Shape3D hit = point.hit;
        
        /* find intersection point and normal */
        Vector3D intersect = new Vector3D(direction);
        intersect.multiply(point.value);
        intersect.add(origin);
        Vector3D normal = hit.getNormal(intersect);
        normal.unit();
        if (point.stype == -1){
            normal.negate();
        }
        
        System.out.println("intersect=" + intersect.out());
        System.out.println("normal=" + normal.out());

        /* Get unit vector to viewer */
        Vector3D V = new Vector3D(origin);
        V.minus(intersect);
        V.unit();
        System.out.println("V=" + V.out());
        
        /* find reflected ray - for use in reflection and specular lighting */
        double Rangle = 2 * normal.dot(V);
        Vector3D R = new Vector3D(normal);
        R.multiply(Rangle);
        R.minus(V);
        R.unit();
        System.out.println("R=" + R.out());
        
        /* Handles Transarency */
        if (hit.material.transparency > rayTrace.TINY){
            
            Ray tran = new Ray(intersect, direction);
            Color3D transparent = tran.trace(scene, deadray);
            transparent.multiply(hit.material.transparency);
            color.add(transparent);
        }
        
        /* Handles reflection */
        if (hit.material.reflect > rayTrace.TINY){

            Ray ref = new Ray(intersect, R);
            Color3D reflect = ref.trace(scene, deadray);
            reflect.multiply(hit.material.reflect);
            color.add(reflect);
        }
        
        System.out.println("---------LIGHTING-------");
        /* Lighting */
        int lcount = scene.getNumLights();
        Light light;
        Vector3D L;
        Ray lightRay;
        double modulus;
        Intersection Check;
        
        /* for each light */
        for(int i = 0; i < lcount; i++){
            System.out.println("--------Light[" + i + "]---------");
            /* get current light */
            light = scene.getlight(i);

            /* work out ray from intersect to curent light */
            L = new Vector3D(light.position);
            L.minus(intersect);
            modulus = L.modulus();
            L.divide(modulus);
            System.out.println("L=" + L.out());
            System.out.println("angle=" + normal.dot(L));
            
            if (normal.dot(L) > 0){
            
                lightRay = new Ray(intersect, L);

                /* check ray to light against all shapes */      
                Check = lightRay.traceRay(scene);
                if (Check != null){                 /* do you hit a shape? */
                    if (Check.value < modulus){     /* if you hit the shape before the light */
                        continue;                   /* skip current light */
                    }
                }
                /* If we got here we do this light */
                double val;

                /* Get intensity of light */
                /* using 1/n rather than 1/(n^2) for efficiency */
                double Ip = light.intensity / modulus;

                /* Specular Lighting*/
                /* Ip = source intensity */
                /* Ks = specular coefficient */

                /* Is = Ip * Ks *  (V.R)^n */
                double specular = hit.material.Ks * Ip * Math.pow(L.dot(R),hit.material.n);
                Color3D Is = new Color3D(light.color);
                Is.multiply(specular);
                color.add(Is);

                /* diffuse */
                /* Id = (Ip - Is) * Kd * cos(b) */
                /* Id = (Ip - Is) * Kd * (N . L) */
                val = normal.dot(L);
                if ((val > 0) && (val <= 1)){
                    double diffuse = (Ip - specular) * hit.material.Kd * val;
                    Color3D Id = new Color3D(hit.material.color);
                    Id.multiply(diffuse);
                    color.add(Id);
                }
            }
        }

        /* Ambient Lighting */
        /* Ia = Ka * La */
        /* Ka = ambient constant */
        /* La = incident light */
        Color3D Ia = new Color3D(scene.Ia);
        Ia.multiply(hit.material.color);
        
        color.add(Ia);
        
        return color;
    }
}