public Ray(Ray r)
 {
     p = new Vector3(r.p);
     dir = new Vector3(r.dir);
     mint = r.mint;
     maxt = r.maxt;
 }
 public RayContext(Ray _ray)
 {
     ray = new Ray(_ray);
     traceLevel = 0;
     traceLevelGI = 0;
     ignoreID = -1;
 }
        public static RayContext createNewContext(RayContext previousContext, Ray newRay)
        {
            RayContext newContext = new RayContext(newRay);
            newContext.traceLevel += previousContext.traceLevel + 1;
            newContext.scene = previousContext.scene;
            newContext.ignorePrimitive = previousContext.hitData.hitPrimitive;

            newContext.m_renderer = previousContext.m_renderer;
            newContext.ignoreID = previousContext.ignoreID;

            newContext.m_rndContext = previousContext.m_rndContext.createNew(previousContext.randomIndex, 2);
            return newContext;
        }
        public override Ray getRay(double x, double y)
        {
            double au = System.Math.Tan(  0.0174532925*((fov*0.5)) );//
            double av = au / aspect;

            double du = -au + (2.0 * au * x);
            double dv = -av + (2.0 * av * (1-y));

            Ray ray = new Ray();
            ray.p.set(pos);

            Vector3 rayDir = new Vector3(du, dv, -1.0f);

            ray.dir.x = right.x*rayDir.x + up.x*rayDir.y + forward.x*rayDir.z;
            ray.dir.y = right.y*rayDir.x + up.y*rayDir.y + forward.y*rayDir.z;
            ray.dir.z = right.z*rayDir.x + up.z*rayDir.y + forward.z*rayDir.z;

            return ray;
        }
        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 static RayContext startFromPixel(Ray startRay, int pixX, int pixY, Scene _scene, IIntegrator integrator)
        {
            RayContext newContext = new RayContext(startRay);
            newContext.scene = _scene;
            newContext.m_renderer = integrator;
            newContext.m_rndContext = new RandomContext(2, 17 * pixX + 73 * pixY);

            return newContext;
        }
 public static RayContext createNewContextGI(RayContext previousContext, Ray newRay)
 {
     RayContext newContext = createNewContext(previousContext, newRay);
     newContext.traceLevelGI += previousContext.traceLevelGI + 1;
     return newContext;
 }
 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 Color3 illuminate(RayContext rayContext, BRDF brdf)
        {
            Ray newRay = new Ray();

            double invPdf = 0;

            //във finalColor ще сумираме резултатния цвят
            Color3 finalColor = new Color3();

            //задаваме максималната бройка лъчи
            //с които ще проследяваме грапави отражения
            int numSamples = 10;
            int curSample = 0;  //номер на текущ лъч

            for (curSample = 0; curSample < numSamples; curSample++)
            {
                //генерирме двойка случайни числа (ru, rv)
                double ru = rayContext.getRandom(0, curSample);
                double rv = rayContext.getRandom(1, curSample);

                //искаме brdf да конструира лъч използвайки (ru, rv)
                bool isValidSample = brdf.getSample(rayContext, ru, rv, out newRay.dir, out invPdf);

                if (!isValidSample)
                    continue;

                //конструираме нов лъч от текущата точка
                //и го обвиваме във собствен контекст
                newRay.p = rayContext.hitData.hitPos;
                RayContext newContext = RayContext.createNewContext(rayContext, newRay);
                //извикваме функцията shade, която проследява
                //лъча в сцената и го осветява
                rayContext.scene.shade(newContext);

                double cosT = rayContext.hitData.hitNormal * (newRay.dir);
                if (cosT < 0.0) cosT *= -1.0;

                double pdf;

                Color3 w = new Color3(1, 1, 1);
                //пресмятаме, каква част от светлината ще отрази BRFD-a
                w = brdf.eval(rayContext, newRay.dir, out pdf);

                if (!brdf.isSingular())
                {
                    w *= cosT * invPdf;
                }
                //добавяме енергията на новия лъч
                finalColor += newContext.resultColor * w;

                //if (Double.IsNaN(finalColor.getIntensity()))
                //    break;

                if (brdf.isSingular())
                    break;
            }

            //сумираме енергията от всички лъчи
            if (curSample > 0)
                finalColor *= 1.0 / (double)curSample;

            return finalColor;
        }
 public bool traceShadowRay(Ray shadowRay, RayContext origContext)
 {
     RayContext rayContext = RayContext.createNewContext(origContext, shadowRay);
     rayContext.ignorePrimitive = origContext.hitData.hitPrimitive;
     rayContext.isShadowRay = true;
     return trace(rayContext);
 }
 public LightSample()
 {
     color = new Color3();
     shadowRay = new Ray();
 }