public bool trace(RayContext rayContext)
        {
            double maxt = rayContext.ray.maxt;
            bool haveIntersection = false;

            foreach (GeomPrimitive primitive in m_primitives)
            {

                if (rayContext.ignorePrimitive == primitive)
                    continue; //skip this primitive

                IntersectionData hitData = new IntersectionData();

                if (primitive.intersect(rayContext.ray, hitData))
                {

                    if (maxt > hitData.hitT && hitData.hitT > rayContext.ray.mint)
                    {
                        maxt = hitData.hitT;

                        rayContext.hitData = hitData;
                        rayContext.hitData.hitPrimitive = primitive;
                        haveIntersection = true;
                    }

                    if (haveIntersection)
                    {
                        rayContext.hitData.hitPos = rayContext.ray.p + rayContext.ray.dir * rayContext.hitData.hitT;
                    }
                }
            }//foreach
            return haveIntersection;
        }
        public override bool intersect( Ray ray, IntersectionData hitData )
        {
            Vector3 d = ray.dir;
            Vector3 p = ray.p;
            //лъчът преминава в локални координати на сферата
            p = p - center;

            double A = d * d;
            double B = 2 * (d * p);
            double C = (p * p) - (radius * radius);

            //връщаме лъча в коодинати на сцената
            p = p + center;

            double D = (B * B) - (4 * A * C);

            if (D < 0)
                return false;
            else
                D = System.Math.Sqrt(D);

            double t0 = (-B - D) / (2 * A);
            double t1 = (-B + D) / (2 * A);

            if (t1 < t0)
                t0 = t1;

            hitData.hitT = t0;
            Vector3 wp = p + d * t0;
            hitData.hitPos = wp;
            hitData.hitNormal = wp - center;
            hitData.hitNormal.normalize();

            double u = (System.Math.PI + System.Math.Atan2(wp.z - center.z, wp.x - center.x)) / (System.Math.PI * 2);
            double v = 1.0 - ((System.Math.PI / 2) + System.Math.Asin((wp.y - center.y) / radius)) / System.Math.PI;

            hitData.textureUVW = new Vector3(u, v, 0);

            return true;
        }
 public abstract bool intersect( Ray ray, IntersectionData hitData );
 public override bool intersect( Ray ray, IntersectionData hitData )
 {
     Vector3 e1, e2;
     e1 = v[1] - v[0];// e1 = edge v0 to v1
     e2 = v[2] - v[0];// e2 = edge v0 to v2
     Vector3 pvec = ray.dir ^ e2;// pvec = cross(dir,e2)
     double det = e1 * pvec;// determinant = dot(e1,pvec)
     if (det < 1e-6f && det > -1e-6f) return false; // if det close to zero -> ray lies in the plane
     double inv_det = 1.0f / det;// inverse determinant
     Vector3 tvec = ray.p - v[0];// distance v0 to ray origin
     double u = inv_det * (tvec * pvec);// u = dot(tvec,pvec) / det
     if (u < -1e-6f || u > (1.0f + 1e-6f)) return false;// if u outside triangle return
     Vector3 qvec = tvec ^ e1;// qvec = cross(tvec,e1)
     double t = inv_det * (e2 * qvec);// t = dot(e2,qvec) / det
     if (t < ray.mint || t > ray.maxt) return false;// return false if t is outside range
     double uvV = inv_det * (ray.dir * qvec);// v = dot(dir,qvec) / det
     if (uvV < -1e-6f || (u + uvV) > (1.0f + 1e-6f)) return false;// if v outside triangle return
     hitData.hitT = t;
     hitData.hitNormal = e1 ^ e2;
     hitData.hitNormal.normalize();
     hitData.textureUVW = ((1 - u - uvV) * tc[0]) + (u * tc[1]) + (uvV * tc[2]);
     hitData.shaderID = shaderID;
     return true;
 }
        public void GetIntersection(
            Vector3 rayOrigin, Vector3 rayDirection, GeomPrimitive lastHit,
            out GeomPrimitive pHitObject, Vector3 pStart, RayContext rayContext)
        {
            //hitPosition = null;
            pHitObject = null;
            // is branch: step through subcells and recurse
            if (isBranch)
            {
                //if (pStart == null)
                //    pStart = rayOrigin;

                // find which subcell holds ray origin (ray origin is inside cell)
                int subCell = 0;
                for (int i = 3; i-- > 0; )
                {
                    // compare dimension with center
                    if (pStart[i] >= ((bound[i] + bound[i + 3]) * 0.5f))
                        subCell |= 1 << i;
                }

                // step through intersected subcells
                Vector3 cellPosition = new Vector3(pStart);
                for (; ; )
                {
                    if (null != spatial[subCell])
                    {
                        // intersect subcell
                        spatial[subCell].GetIntersection(rayOrigin, rayDirection, lastHit, out pHitObject, cellPosition, rayContext);
                        // exit if item hit
                        if (null != pHitObject)
                            break;
                    }

                    // find next subcell ray moves to
                    // (by finding which face of the corner ahead is crossed first)
                    int axis = 2;
                    float[] step = new float[3]; // todo - move this allocation?
                    for (int i = 3; i-- > 0; axis = step[i] < step[axis] ? i : axis)
                    {
                        bool high = ((subCell >> i) & 1) != 0;
                        float face = (rayDirection[i] < 0.0f) ^ high ? bound[i + ((high ? 1 : 0) * 3)] : (bound[i] + bound[i + 3]) * 0.5f;
                        // distance to face
                        // (div by zero produces infinity, which is later discarded)
                        step[i] = (float)(face - rayOrigin[i]) / (float)rayDirection[i];
                    }

                    // leaving branch if: subcell is low and direction is negative,
                    // or subcell is high and direction is positive
                    if ((((subCell >> axis) & 1) != 0) ^ (rayDirection[axis] < 0.0f))
                        break;

                    // move to (outer face of) next subcell
                    cellPosition = rayOrigin + (rayDirection * step[axis]);
                    subCell = subCell ^ (1 << axis);
                }
            }
            else
            { // is leaf: exhaustively intersect contained items
                //float nearestDistance = float.MaxValue;

                // step through items
                foreach (GeomPrimitive item in triangles)
                {
                    if (rayContext.ignorePrimitive == item)
                        continue; //skip this primitive

                    if (item == lastHit)
                        continue; //skip this primitive

                    IntersectionData hitData = new IntersectionData();

                    if (item.intersect(rayContext.ray, hitData))
                    {
                        // check intersection is inside cell bound (with tolerance)
                        Vector3 hit = rayOrigin + (rayDirection * hitData.hitT);
                        float t = TOLERANCE;
                        if ((bound[0] - hit[0] <= t) && (hit[0] - bound[3] <= t) &&
                            (bound[1] - hit[1] <= t) && (hit[1] - bound[4] <= t) &&
                            (bound[2] - hit[2] <= t) && (hit[2] - bound[5] <= t))
                        {
                            pHitObject = item;
                            //nearestDistance = distance;
                            //hitPosition = hit;

                            rayContext.hitData = hitData;
                            rayContext.hitData.hitPrimitive = item;
                            rayContext.hitData.hitPos = rayContext.ray.p + rayContext.ray.dir * rayContext.hitData.hitT;

                            rayContext.hitData.hasIntersection = true;
                        }
                    }

                }
            }
        }