Beispiel #1
0
        /// <summary>
        /// Returns color of a ray traced in the scene.
        /// </summary>
        /// <param name="ray">Ray for tracing</param>
        /// <returns>Color of the object intersected, or the background color if no intersection occurred.</returns>
        public override RGBColor TraceRay(Ray ray)
        {
            ShadeRec shadeRec = new ShadeRec(worldPointer.HitObjects(ray));

            if(shadeRec.HitAnObject)
            {
                //Console.Write("hit");
                //return new RGBColor(1.0, 0, 0);
                shadeRec.Ray = ray; //Store information for specular highlight.
                return (shadeRec.ObjectMaterial.Shade(shadeRec)); //Call shader function for object material.
            }
            else { return worldPointer.CurrentBackgroundColor; } //No need to call shader function if no intersection occurred.
        }
 public override RGBColor Shade(ShadeRec sr)
 {
     RGBColor multiplar = base.Shade(sr);
     float scalefactor;
     if(Math.Abs(sr.HitPoint.X) % 50 < 25 && Math.Abs(sr.HitPoint.Z) % 50 > 25)
     {
         scalefactor = 0.1f;
     }
     else
     {
         scalefactor = 1.0f;
     }
     return scalefactor * multiplar;
 }
Beispiel #3
0
        /// <summary>
        /// Step 1 in rendering pipeline.
        /// Generic intersection detection for objectList called by a Tracer, returns ShadeRec describing intersection.
        /// </summary>
        /// <param name="ray">Ray for intersection calculation</param>
        /// <returns>ShadeRec object with all relevant information about object that was intersected for generating
        /// pixel data</returns>
        public ShadeRec HitObjects(Ray ray)
        {
            ShadeRec sr = new ShadeRec(this); // create shaderec

            // set normal and local hit point to non-null values
            Normal normal = new Normal();
            Point3D local_hit_point = new Point3D();

            float t = GlobalVars.K_HUGE_VALUE - 1.0f; // t value for corrent object
            float tmin = GlobalVars.K_HUGE_VALUE; //  current lowest t value
            int num_objects = _renderList.Count; // store count of objects to minimize unecessary member access
            Material closestmat = null; // material reference for closest object

            //Find the closest intersection point along the given ray
            for(int i = 0; i < num_objects; i++)
            {
                // Intersect each object in render list
                // First term evaluated first, therefore (t < tmin) will be doing a comparison of t value
                // of present object vs minimum t value.
                if (_renderList[i].Hit(ray, ref t, ref sr) && (t < tmin))
                {
                    sr.HitAnObject = true; // at least one intersection has occurred

                    // store temporary references to information about current object with minimum t
                    tmin = t;
                    closestmat = sr.ObjectMaterial;
                    sr.HitPoint = ray.Origin + t * ray.Direction; // calculate hit point in world space by adding t*direction to origin
                    normal = sr.Normal;
                    local_hit_point = sr.HitPointLocal;
                }
            }

            //If we hit an object, store local vars for closest object with ray intersection in sr before returning
            if(sr.HitAnObject)
            {
                sr.TMinimum = tmin;
                sr.Normal = normal;
                sr.HitPointLocal = local_hit_point;
                sr.ObjectMaterial = closestmat;
            }

            return (sr);
        }
Beispiel #4
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sr">Shading parameters</param>
        /// <param name="ray">Ray to cast from object to point light</param>
        /// <returns></returns>
        public override bool InShadow(ShadeRec sr, Ray ray)
        {
            int num_objects = sr.WorldPointer.RenderList.Count;
            float tmin;

            //Find the closest intersection point along the given ray
            for (int i = 0; i < num_objects; i++)
            {
                tmin = (_location - sr.HitPoint).Coordinates.Length();
                if (sr.WorldPointer.RenderList[i].Hit(ray, tmin))
                {
                    return true;
                }
            }
            return false;
        }
Beispiel #5
0
 //Gets and sets
 //public float getIntensity() { return _intensity; }
 public override Vect3D GetDirection(ShadeRec sr)
 {
     return ((_location - sr.HitPoint).Hat());
 }
Beispiel #6
0
 public virtual bool InShadow(ShadeRec sr, Ray ray)
 {
     return false;
 }
 //Gets and sets
 //public void setDirection(Vect3D d) { _direction = d.Hat(); }
 //public void setIntensity(float i) { _intensity = i; }
 //public void setShadows(bool shad) { _castsShadows = shad; }
 //public Vect3D getDirection() { return _direction; }
 //public float getIntensity() { return _intensity; }
 public override RGBColor GetLighting(ShadeRec sr)
 {
     return _intensity * _color;
 }
Beispiel #8
0
        public override bool Hit(Ray r, ref float tmin, ref ShadeRec sr)
        {
            //Calculate ray intersection with the Moller-Trumbore algorithm
            Vect3D edge1, edge2; //Edges
            Vect3D P, Q, T;
            float determinant, invDeterminant, u, v, t;

            edge1 = Vertex2 - Vertex1;
            edge2 = Vertex3 - Vertex1; //Vectors for the edges shared by vertex 1

            P = r.Direction ^ edge2;
            determinant = edge1 * P; //Determinant calculation

            //If determinant is almost zero, then ray is parallel
            if(determinant > -GlobalVars.K_EPSILON && determinant < GlobalVars.K_EPSILON)
            {
                return false;
            }

            invDeterminant = 1.0f / determinant;

            //Distance from v1 to ray origin
            T = r.Origin - Vertex1;

            //U parameter calculation and test
            u = (T * P) * invDeterminant;
            //If u is negative or greater than 1, then intersection is outside of triangle
            if(u < 0.0 || u > 1.0)
            {
                return false;
            }

            Q = T ^ edge1;
            //V parameter calculation and test
            v = (r.Direction * Q) * invDeterminant;
            //if v is negative or v+u is greater than 1, then intersection is outside of triangle
            if(v < 0.0 || u+v > 1.0 )
            {
                return false;
            }

            t = edge2 * Q * invDeterminant;

            if(t > GlobalVars.K_EPSILON && t < tmin)
            {
                //Ray hit something and intersection is in front of camera
                tmin = t;
                //Calculate normal, and ensure it's facing the direction that the ray came from
                Vect3D triNorm = (Vertex2 - Vertex1) ^ (Vertex3 - Vertex1);
                float triDotProd = triNorm * r.Direction;
                if(triDotProd < 0.0)
                {
                    sr.Normal = new Normal(triNorm);
                }
                else
                {
                    sr.Normal = new Normal(-triNorm);
                }
                sr.Normal.Normalize();
                sr.HitPointLocal = r.Origin + t * r.Direction;
                sr.ObjectMaterial = _material;
                return true;
            }
            else
            {
                return false;
            }
        }
Beispiel #9
0
        public override bool Hit(Ray r, ref float tmin, ref ShadeRec sr)
        {
            //Apply inverse transformation to incident ray and test for intersection
            Ray tfRay = new Ray(r);
            tfRay.Origin = inverseNetTransformationMatrix * r.Origin;
            tfRay.Direction = inverseNetTransformationMatrix * r.Direction;

            if(payload.Hit(tfRay, ref tmin, ref sr))
            {
                //Transform the computed normal into worldspace
                sr.Normal = inverseNetTransformationMatrix * sr.Normal;
                sr.Normal.Normalize();
                if(_material != null)
                {
                    sr.ObjectMaterial = _material;
                }
                return true;
            }
            else
            {
                return false;
            }
        }
Beispiel #10
0
        //public float getA() { return _a; }
        //public float getB() { return _b; }
        //public BoundingBox getBB() { return _boundingBox; }
        public override bool Hit(Ray r, ref float tmin, ref ShadeRec sr)
        {
            if(!_boundingBox.Hit(r, tmin))
            {
                return false;
            }
            /// Hit point on a torus as distance from point r.origin along vector r.direction
            /// can be solved for as a quartic equation of the form c4t^4 + c3t^3 + c2t^2 + c1t + c0 = 0
            /// where:
            /// c4 = (xd^2 + yd^2 + zd^2)^2
            /// c3 = 4(xd^2 + yd^2 + zd^2)(xoxd+yoyd+zozd)
            /// c2 = 2(xd^2 + yd^2 + zd^2)(xo^2+yo^2+zo^2-(a^2 + b^2))+4(xoxd + yoyd + zozd)^2 + 4a^2yd^2
            /// c1 = 4(xo^2 + yo^2 + zo^2 - (a^2 + b^2))(xoxd + yoyd + zozd) + 8a^2yoyd
            /// c0 = 4(xo^2 + yo^2 + zo^2 - (a^2 + b^2))^2 - 4a^2(b^2 - yo^2)
            ///
            ///Using quartic solving algorithm
            ///
            float x1 = r.Origin.X; float y1 = r.Origin.Y; float z1 = r.Origin.Z;
            float d1 = r.Direction.X; float d2 = r.Direction.Y; float d3 = r.Direction.Z;

            float[] coefficients = new float[5];
            float[] roots = new float[4];

            float sum_d_sqrd = d1 * d1 + d2 * d2 + d3 * d3;
            float e = x1 * x1 + y1 * y1 + z1 * z1 - _a * _a - _b * _b;
            float f = x1 * d1 + y1 * d2 + z1 * d3;
            float four_a_sqrd = 4.0f * _a * _a;

            coefficients[0] = e * e - four_a_sqrd * (_b * _b - y1 * y1);
            coefficients[1] = 4.0f * f * e + 2.0f * four_a_sqrd * y1 * d2;
            coefficients[2] = 2.0f * sum_d_sqrd * e + 4.0f * f * f + four_a_sqrd * d2 * d2;
            coefficients[3] = 4.0f * sum_d_sqrd * f;
            coefficients[4] = sum_d_sqrd * sum_d_sqrd;

            //Find roots
            int numroots = FastMath.SolveQuartic(coefficients, roots);

            bool hit = false;
            float t = GlobalVars.K_HUGE_VALUE;

            if (numroots == 0)
            {

                return false;
            }

            //Find the smallest root
            for(int i = 0;i< numroots;i++)
            {
                if(roots[i] > GlobalVars.K_EPSILON && roots[i] < t)
                {
                    hit = true;
                    t = roots[i];
                }
            }

            if(!hit)
            {
                return false;
            }

            tmin = t;
            sr.HitPointLocal = r.Origin + (t * r.Direction);
            sr.ObjectMaterial = _material;

            //Compute the normal at the hit point (see Thomas and Finney, 1996)
            sr.Normal = CalculateNormal(sr.HitPointLocal);

            return hit;
        }
 public virtual bool Hit(Ray r, ref float tmin, ref ShadeRec sr)
 {
     return false;
 }
        public override bool Hit(Ray ray, ref float tMin, ref ShadeRec sr)
        {
            //First verify intersection point of ray with bounding box.
            Vector3 o = ray.Origin.Coordinates;
            //float ox = r.origin.coords.X;
            //float oy = r.origin.coords.Y;
            //float oz = r.origin.coords.Z;
            Vector3 d = ray.Direction.Coordinates;
            //float dx = r.direction.coords.X;
            //float dy = r.direction.coords.Y;
            //float dz = r.direction.coords.Z;

            Vector3 c0 = boundingBox.corner0;
            Vector3 c1 = boundingBox.corner1;
            //float x0 = bbox.c0.X;
            //float y0 = bbox.c0.Y;
            //float z0 = bbox.c0.Z;
            //float x1 = bbox.c1.X;
            //float y1 = bbox.c1.Y;
            //float z1 = bbox.c1.Z;

            float tx_min, ty_min, tz_min;
            float tx_max, ty_max, tz_max;

            Vector3 inverseDenominator = new Vector3(1.0f)/d;
            //Vector3 min;
            //Vector3 max;
            float a = inverseDenominator.X;
            if (a >= 0)
            {
                tx_min = (c0.X - o.X) * a;
                tx_max = (c1.X - o.X) * a;
            }
            else
            {
                tx_min = (c1.X - o.X) * a;
                tx_max = (c0.X - o.X) * a;
            }

            float b = inverseDenominator.Y;
            if (b >= 0)
            {
                ty_min = (c0.Y - o.Y) * b;
                ty_max = (c1.Y - o.Y) * b;
            }
            else
            {
                ty_min = (c1.Y - o.Y) * b;
                ty_max = (c0.Y - o.Y) * b;
            }

            float c = inverseDenominator.Z;
            if (c >= 0)
            {
                tz_min = (c0.Z - o.Z) * c;
                tz_max = (c1.Z - o.Z) * c;
            }
            else
            {
                tz_min = (c1.Z - o.Z) * c;
                tz_max = (c0.Z - o.Z) * c;
            }

            //Determine if volume was hit
            float t0, t1;
            t0 = (tx_min > ty_min) ? tx_min : ty_min;
            if (tz_min > t0) t0 = tz_min;
            t1 = (tx_max < ty_max) ? tx_max : ty_max;
            if (tz_max < t1) t1 = tz_max;

            if (t0 > t1)
            {
                return false;
            }

            float tPosition; //Entry value of t for ray, lowest possible t value
            if (!boundingBox.inside(ray.Origin))
                tPosition = t0; //Start casting from t0 if starting from outside bounding box
            else
                tPosition = GlobalVars.K_EPSILON; //Start casting from origin if starting from inside bounding box
            float tDistance = 0; //Value returned by the distance function approximation
            float tPositionPrevious = 0;
            float adjustedDistance = 0; //Adjusted distance scaled by distance adjustment parameter
            float currentDistanceFunctionValue = 0;
            float previousDistanceFunctionValue = 0;
            Point3D location;
            //Traverse space using raymarching algorithm
            do
            {
                location = ray.Origin + ray.Direction * tPosition;
                tDistance = EvaluateDistanceFunction(location,ray.Direction, ref currentDistanceFunctionValue);
                adjustedDistance = tDistance * distanceMultiplier;

                //Clamp the adjusted distance between the minimum and maximum steps
                adjustedDistance = FastMath.clamp(adjustedDistance, minimumRaymarchStep, maximumRaymarchStep);
                //Increment tpos by the adjusted distance
                tPosition += adjustedDistance;

                //Accidentally stepped over bounds, solve using bisection algorithm
                if(previousDistanceFunctionValue*currentDistanceFunctionValue < 0.0f)
                {
                    SolveRootByBisection(ray, ref tMin, ref sr, tPositionPrevious, tPosition, RECURSIONDEPTH);
                    return true;
                }
                tPositionPrevious = tPosition;
                previousDistanceFunctionValue = currentDistanceFunctionValue;
            } while (tPosition < t1 && tDistance > triggerDistance);

            //Hit
            if(tDistance < triggerDistance)
            {
                tMin = tPosition;
                sr.HitPointLocal = ray.Origin + tPosition * ray.Direction;
                sr.Normal = ApproximateNormal(sr.HitPointLocal, ray.Direction);
                sr.ObjectMaterial = _material;
                return true;
            }
            else
            {
                return false;
            }
        }
 private bool SolveRootByBisection(Ray ray, ref float tMin, ref ShadeRec sr, float lowBound, float highBound, int depth)
 {
     if(depth > 0)
     {
         //Find the mid point between the low and high bound
         float midbound;
         midbound = lowBound + ((highBound - lowBound) / 2.0f);
         if (ZeroExistsInInterval(ray, lowBound, midbound))
             return SolveRootByBisection(ray, ref tMin, ref sr, lowBound, midbound, depth - 1);
         else if (ZeroExistsInInterval(ray, midbound, highBound))
             return SolveRootByBisection(ray, ref tMin, ref sr, midbound, highBound, depth - 1);
         else
         {
             //Converged to correct location!
             tMin = lowBound;
             sr.HitPointLocal = ray.Origin + lowBound * ray.Direction;
             sr.Normal = ApproximateNormal(sr.HitPointLocal, ray.Direction);
             sr.ObjectMaterial = _material;
             return true;
         }
     }
     else
     {
         //Bottom of recursion stack, calculate relevant values
         tMin = lowBound;
         sr.HitPointLocal = ray.Origin + (float)lowBound * ray.Direction;
         sr.Normal = ApproximateNormal(sr.HitPointLocal, ray.Direction);
         sr.ObjectMaterial = sr.WorldPointer.MaterialList[0];
         return true;
     }
 }
Beispiel #14
0
        //Gets and sets
        /*
        public void setP(Point3D parg) { _p = parg; }
        public void setN(Normal narg) { _n = narg; }
        public Point3D getP() { return _p; }
        public Normal getN() { return _n; }
        */
        /// <summary>
        /// Determines t value for intersection of plane and given ray, passes shading info back through sr;
        /// </summary>
        /// <param name="r">Ray to determine intersection</param>
        /// <param name="tmin">Passed by reference, minimum t value</param>
        /// <param name="sr">ShadeRec to store shading info in</param>
        /// <returns></returns>
        public override bool Hit(Ray r, ref float tmin, ref ShadeRec sr)
        {
            float t = (_p - r.Origin) * _n / (r.Direction * _n);

            //Intersection is in front of camera
            if(t > GlobalVars.K_EPSILON && t < tmin)
            {
                tmin = t;
                sr.Normal = _n;
                sr.HitPointLocal = r.Origin + t * r.Direction;
                sr.ObjectMaterial = _material;
                return true;
            }
            //Intersection is behind camera
            else
            {
                return false;
            }
        }
Beispiel #15
0
 public virtual Vect3D GetDirection(ShadeRec sr)
 {
     return new Vect3D(0, 0, 0);
 }
Beispiel #16
0
        public override bool Hit(Ray r, ref float tmin, ref ShadeRec sr)
        {
            ///-------------------------------------------------------------------------------------
            /// same as colision code for axis aligned bounding box
            float ox = r.Origin.X; float oy = r.Origin.Y; float oz = r.Origin.Z;
            float dx = r.Direction.X; float dy = r.Direction.Y; float dz = r.Direction.Z;

            float tx_min, ty_min, tz_min;
            float tx_max, ty_max, tz_max;

            float a = 1.0f / dx;
            if (a >= 0.0)
            {
                tx_min = (x0 - ox) * a;
                tx_max = (x1 - ox) * a;
            }
            else
            {
                tx_min = (x1 - ox) * a;
                tx_max = (x0 - ox) * a;
            }

            float b = 1.0f / dy;
            if (b >= 0.0)
            {
                ty_min = (y0 - oy) * b;
                ty_max = (y1 - oy) * b;
            }
            else
            {
                ty_min = (y1 - oy) * b;
                ty_max = (y0 - oy) * b;
            }

            float c = 1.0f / dz;
            if (c >= 0.0)
            {
                tz_min = (z0 - oz) * c;
                tz_max = (z1 - oz) * c;
            }
            else
            {
                tz_min = (z1 - oz) * c;
                tz_max = (z0 - oz) * c;
            }
            ///code differs after this point
            ///--------------------------------------------------------------------------
            ///
            float t0, t1;
            int face_in, face_out; //for handling both inside and outside collisions with box

            //Find the largest entering t value
            if(tx_min > ty_min)
            {
                t0 = tx_min;
                face_in = (a >= 0.0) ? 0 : 3;
            }
            else
            {
                t0 = ty_min;
                face_in = (b >= 0.0) ? 1 : 4;
            }
            if(tz_min > t0)
            {
                t0 = tz_min;
                face_in = (c >= 0.0) ? 2 : 5;
            }

            //Find the smallest exiting t value
            if(tx_max < ty_max)
            {
                t1 = tx_max;
                face_out = (a >= 0.0) ? 3 : 0;
            }
            else
            {
                t1 = ty_max;
                face_out = (b >= 0.0) ? 4 : 1;
            }
            if(tz_max < t1)
            {
                t1 = tz_max;
                face_out = (c >= 0.0) ? 5 : 2;
            }

            //Hit conditions
            if (t0 < t1 && t1 > GlobalVars.K_EPSILON)
            {
                if (t0 > GlobalVars.K_EPSILON) //Ray hits outside surface
                {
                    tmin = t0;
                    sr.Normal = GetNormal(face_in);
                }
                else//Ray hits inside surface
                {
                    //Console.Write("hit inside");
                    tmin = t1;
                    sr.Normal = GetNormal(face_out);
                }

                sr.HitPointLocal = r.Origin + tmin * r.Direction;
                sr.ObjectMaterial = _material;
                return true;
            }
            else
                return false;
        }
Beispiel #17
0
 public abstract RGBColor GetLighting(ShadeRec sr);
        public override bool Hit(Ray r, ref float tMin, ref ShadeRec sr)
        {
            float t = GlobalVars.K_HUGE_VALUE;
            Normal normal = new Normal();
            Point3D localHitPoint = new Point3D();
            bool hit = false;
            tMin = GlobalVars.K_HUGE_VALUE;
            int countObjects = containedObjects.Count;
            Material closestObjectMaterial = null;

            //Traverse the list of renderable objects, and test for collisions in the same manner as in the world
            //hit function
            for(int i = 0; i < countObjects; i++)
            {
                if(containedObjects[i].Hit(r, ref t, ref sr) && (t<tMin))
                {
                    hit = true;
                    tMin = t;
                    closestObjectMaterial = sr.ObjectMaterial;
                    normal = sr.Normal;
                    localHitPoint = sr.HitPointLocal;
                }
            }

            if(hit)
            {
                sr.TMinimum = tMin;
                sr.Normal = normal;
                sr.HitPointLocal = localHitPoint;
                sr.ObjectMaterial = closestObjectMaterial;
            }

            return hit;
        }
 public override Vect3D GetDirection(ShadeRec sr)
 {
     return -_direction;
 }
Beispiel #20
0
        public override RGBColor F(ShadeRec sr, Vect3D incomingDirection, Vect3D reflectedDirection)
        {
            RGBColor L = new RGBColor(0.0f, 0.0f, 0.0f);
            float nDotWi = (sr.Normal * incomingDirection); //Dot product of normal and angle of incidence gives the angle of mirror reflection
            Vect3D r = new Vect3D(-incomingDirection + 2.0f * sr.Normal * nDotWi); //Vector describing direction of mirror reflection
            float rDotWo = (r * reflectedDirection);

            if (rDotWo > 0.0)
            {
                L = _specularReflectionCoefficient * (float)Math.Pow(rDotWo, _phongExponent) * _colorSpecular;
            }

            return L;
        }
 public override bool InShadow(ShadeRec sr, Ray ray)
 {
     ShadeRec tempSr = sr.WorldPointer.HitObjects(ray);
     return tempSr.HitAnObject;
 }
Beispiel #22
0
        public override bool Hit(Ray ray, ref float tMin, ref ShadeRec sr)
        {
            //
            // Code from Suffern (2007)
            //
            float ox = ray.Origin.X;
            float oy = ray.Origin.Y;
            float oz = ray.Origin.Z;
            float dx = ray.Direction.X;
            float dy = ray.Direction.Y;
            float dz = ray.Direction.Z;

            float x0 = _boundingBox.corner0.X;
            float y0 = _boundingBox.corner0.Y;
            float z0 = _boundingBox.corner0.Z;
            float x1 = _boundingBox.corner1.X;
            float y1 = _boundingBox.corner1.Y;
            float z1 = _boundingBox.corner1.Z;

            float tx_min, ty_min, tz_min;
            float tx_max, ty_max, tz_max;

            float a = 1.0f / dx;
            if(a >= 0)
            {
                tx_min = (x0 - ox) * a;
                tx_max = (x1 - ox) * a;
            }
            else
            {
                tx_min = (x1 - ox) * a;
                tx_max = (x0 - ox) * a;
            }

            float b = 1.0f / dy;
            if(b >= 0)
            {
                ty_min = (y0 - oy) * b;
                ty_max = (y1 - oy) * b;
            }
            else
            {
                ty_min = (y1 - oy) * b;
                ty_max = (y0 - oy) * b;
            }

            float c = 1.0f / dz;
            if(c >= 0)
            {
                tz_min = (z0 - oz) * c;
                tz_max = (z1 - oz) * c;
            }
            else
            {
                tz_min = (z1 - oz) * c;
                tz_max = (z0 - oz) * c;
            }

            //Determine if volume was hit
            float t0, t1;
            t0 = (tx_min > ty_min) ? tx_min : ty_min;
            if (tz_min > t0) t0 = tz_min;
            t1 = (tx_max < ty_max) ? tx_max : ty_max;
            if (tz_max < t1) t1 = tz_max;

            if(t0 > t1)
            {
                return false;
            }

            //Initial cell coordinates
            int ix, iy, iz;
            if(_boundingBox.inside(ray.Origin))
            {
                ix = (int)Clamp((ox - x0) * nx / (x1 - x0), 0, nx - 1); //Get indices of ray origin if inside
                iy = (int)Clamp((oy - y0) * ny / (y1 - y0), 0, ny - 1);
                iz = (int)Clamp((oz - z0) * nz / (z1 - z0), 0, nz - 1);
            }
            else
            {
                Point3D p = ray.Origin + t0 * ray.Direction;
                ix = (int)Clamp((p.X - x0) * nx / (x1 - x0), 0, nx - 1); //Get indices of ray hitpoint if origin outside
                iy = (int)Clamp((p.Y - y0) * ny / (y1 - y0), 0, ny - 1);
                iz = (int)Clamp((p.Z - z0) * nz / (z1 - z0), 0, nz - 1);
            }

            //Get increments for ray marching
            float dtx = (tx_max - tx_min) / nx;
            float dty = (ty_max - ty_min) / ny;
            float dtz = (tz_max - tz_min) / nz;

            float tx_next, ty_next, tz_next;
            int ix_step, iy_step, iz_step;
            int ix_stop, iy_stop, iz_stop;

            if(dx > 0)
            {
                tx_next = tx_min + (ix + 1) * dtx;
                ix_step = 1;
                ix_stop = nx;
            }
            else
            {
                tx_next = tx_min + (nx - ix) * dtx;
                ix_step = -1;
                ix_stop = -1;
            }
            //Avoid divide by zero error
            if(dx == 0.0)
            {
                tx_next = GlobalVars.K_HUGE_VALUE;
                ix_step = -1;
                ix_stop = -1;
            }

            if(dy > 0)
            {
                ty_next = ty_min + (iy + 1) * dty;
                iy_step = 1;
                iy_stop = ny;
            }
            else
            {
                ty_next = ty_min + (ny - iy) * dty;
                iy_step = -1;
                iy_stop = -1;
            }
            //Avoid divide by zero error
            if(dy == 0.0)
            {
                ty_next = GlobalVars.K_HUGE_VALUE;
                iy_step = -1;
                iy_stop = -1;
            }

            if(dz > 0)
            {
                tz_next = tz_min + (iz + 1) * dtz;
                iz_step = +1;
                iz_stop = nz;
            }
            else
            {
                tz_next = tz_min + (nz - iz) * dtz;
                iz_step = -1;
                iz_stop = -1;
            }
            //Avoid divide by zero error
            if(dz == 0.0)
            {
                tz_next = GlobalVars.K_HUGE_VALUE;
                iz_step = -1;
                iz_stop = -1;
            }

            //Traverse grid
            while(true)
            {
                RenderableObject objectPointer = cells[ix + (nx * iy) + (nx * ny * iz)];

                //Is the next cell an increment in the x direction?
                if(tx_next < ty_next && tx_next < tz_next)
                {
                    //Hit an object in this cell, cull cells behind this object
                    if ((objectPointer != null) && objectPointer.Hit(ray, ref tMin, ref sr) && tMin < tx_next)
                    {
                        //mat = object_ptr.getMaterial();
                        return true;
                    }

                    //Walk the ray to the next cell
                    tx_next += dtx;
                    ix += ix_step;

                    //Havn't hit anything in the volume at all?
                    if(ix == ix_stop)
                    {
                        return false;
                    }
                }
                //Next cell is either an increment in y or z direction
                else
                {
                    //Next cell is in the y direction
                    if(ty_next < tz_next)
                    {
                        //Hit an object in this cell? Cull cells behind object
                        if (objectPointer != null && objectPointer.Hit(ray, ref tMin, ref sr) && tMin < ty_next)
                        {
                            //mat = object_ptr.getMaterial();
                            return true;
                        }

                        //Walk the ray to the next cell
                        ty_next += dty;
                        iy += iy_step;

                        //Havn't hit anything in the volume?
                        if(iy == iy_stop)
                        {
                            return false;
                        }
                    }
                    //Next cell is in the z direction
                    else
                    {
                        //Hit an object in this cell? Cull cells behind object
                        if (objectPointer != null && objectPointer.Hit(ray, ref tMin, ref sr) && tMin < tz_next)
                        {
                            //mat = object_ptr.getMaterial();
                            return true;
                        }

                        //Walk the ray to the next cell
                        tz_next += dtz;
                        iz += iz_step;

                        //Havn't hit anything in the volume?
                        if(iz == iz_stop)
                        {
                            return false;
                        }
                    }
                }
            }
        }