public void resolveContacts(ParticleContact[] contactArray, int numContacts, float duration)
        {
            int i = 0;

            iterationsUsed = 0;
            while (iterationsUsed < iterations)
            {
                float max      = float.MaxValue;
                int   maxIndex = numContacts;
                for (i = 0; i < numContacts; i++)
                {
                    float sepVel = contactArray[i].calculateSeparatingVelocity();
                    if (sepVel < max && (sepVel < 0.0f || contactArray[i].penetration > 0.0f))
                    {
                        max      = sepVel;
                        maxIndex = i;
                    }
                }

                if (maxIndex == numContacts)
                {
                    break;
                }

                contactArray[maxIndex].resolve(duration);

                Vec3f move1 = contactArray[maxIndex].particleMovement1;
                Vec3f move2 = contactArray[maxIndex].particleMovement2;
                if (move1 != null)
                {
                    for (i = 0; i < numContacts; i++)
                    {
                        if (contactArray[i].particle1 == contactArray[maxIndex].particle1)
                        {
                            contactArray[i].penetration -= move1.dot(contactArray[i].contactNormal);
                        }
                        else if (contactArray[i].particle1 == contactArray[maxIndex].particle2)
                        {
                            contactArray[i].penetration -= move2.dot(contactArray[i].contactNormal);
                        }
                        if (contactArray[i].particle2 != null)
                        {
                            if (contactArray[i].particle2 == contactArray[maxIndex].particle1)
                            {
                                contactArray[i].penetration += move1.dot(contactArray[i].contactNormal);
                            }
                            else if (contactArray[i].particle2 == contactArray[maxIndex].particle2)
                            {
                                contactArray[i].penetration += move2.dot(contactArray[i].contactNormal);
                            }
                        }
                    }
                }

                iterationsUsed++;
            }
        }
        public Collision intersect(Vec3f rayorig, Vec3f raydir)
        {
            Vec3f l   = center - rayorig;
            float tca = l.dot(raydir);

            if (tca < 0)
            {
                return(new Collision());
            }
            float d2 = l.dot(l) - tca * tca;

            if (d2 > radius2)
            {
                return(new Collision());
            }
            float thc = (float)Math.Sqrt(radius2 - d2);

            return(new Collision(true, tca - thc, tca + thc));
        }
        public float calculateSeparatingVelocity()
        {
            Vec3f relativeVelocity = particle1.Velocity;

            if (particle2 != null)
            {
                relativeVelocity -= particle2.Velocity;
            }

            return(relativeVelocity.dot(contactNormal));
        }
        private void resolveVelocity(float duration)
        {
            float separatingVelocity = calculateSeparatingVelocity();

            if (separatingVelocity > 0.0f)
            {
                return;
            }

            float newSeparaiongVelocity = -separatingVelocity * restitution;

            Vec3f accCausedVelocity = particle1.Acceleration;

            if (particle2 != null)
            {
                accCausedVelocity -= particle2.Acceleration;
            }

            float accCausedSepVelocity = accCausedVelocity.dot(contactNormal) * duration;

            if (accCausedSepVelocity < 0.0f)
            {
                newSeparaiongVelocity += restitution * accCausedSepVelocity;
                if (newSeparaiongVelocity < 0.0f)
                {
                    newSeparaiongVelocity = 0.0f;
                }
            }

            float deltaVelocity = newSeparaiongVelocity - separatingVelocity;

            float totalInversMass = particle1.InverseMass;

            if (particle2 != null)
            {
                totalInversMass += particle2.InverseMass;
            }

            if (totalInversMass <= 0.0f)
            {
                return;
            }

            float impulse         = deltaVelocity / totalInversMass;
            Vec3f impulsePerIMass = contactNormal * impulse;

            particle1.Velocity = particle1.Velocity + impulsePerIMass * particle1.InverseMass;
            if (particle2 != null)
            {
                particle2.Velocity = particle2.Velocity + impulsePerIMass * -particle2.InverseMass;
            }
        }
Exemple #5
0
        public void calculateProj(float nearPlane = 0.1f, float farPlane = 1000.0f)
        {
            polygons_proj = new List <RPolygon>();
            foreach (RPolygon poly in polygons_view)
            {
                Vec3f nearPlaneNormal = new Vec3f(0.0f, 0.0f, 1.0f);
                Vec3f nearPlaneP0     = new Vec3f(0.0f, 0.0f, nearPlane);

                float sideOfPoint1 = nearPlaneNormal.dot(poly.vertex0.position - nearPlaneP0);
                float sideOfPoint2 = nearPlaneNormal.dot(poly.vertex1.position - nearPlaneP0);
                float sideOfPoint3 = nearPlaneNormal.dot(poly.vertex2.position - nearPlaneP0);

                if (sideOfPoint1 <= 0 || sideOfPoint2 <= 0 || sideOfPoint3 <= 0)
                {
                    poly.visible = false;
                }

                if (poly.visible)
                {
                    RVertex vertex1 = new RVertex(poly.vertex0);
                    vertex1.position = new Vec3f(proj * poly.v0);

                    RVertex vertex2 = new RVertex(poly.vertex1);
                    vertex2.position = new Vec3f(proj * poly.v1);

                    RVertex vertex3 = new RVertex(poly.vertex2);
                    vertex3.position = new Vec3f(proj * poly.v2);

                    RPolygon newPolygon = new RPolygon(vertex1, vertex2, vertex3, poly.rasterType, poly.texture);
                    float    cosTheta   = newPolygon.normalCalc().dot(GlobalDirection.forward3f);
                    newPolygon.visible = cosTheta >= 0.0f ? false : true;

                    if (newPolygon.visible)
                    {
                        polygons_proj.Add(newPolygon);
                    }
                }
            }
        }
Exemple #6
0
        public void calculateAll(float nearPlane, float farPlane, float width, float height, bool isNDC, bool backFaceCull = true)
        {
            polygons_raster = new List <RPolygon>();
            object sync = new object();

            Parallel.ForEach <RPolygon>(
                polygons,
                poly => {
                Mat4f mwv = model;
                mwv       = mwv * world;
                mwv       = mwv * view;

                RVertex vertex1  = new RVertex(poly.vertex0);
                vertex1.position = new Vec3f(mwv * poly.v0);

                RVertex vertex2  = new RVertex(poly.vertex1);
                vertex2.position = new Vec3f(mwv * poly.v1);

                RVertex vertex3  = new RVertex(poly.vertex2);
                vertex3.position = new Vec3f(mwv * poly.v2);

                Vec3f nearPlaneNormal = new Vec3f(0.0f, 0.0f, 1.0f);
                Vec3f nearPlaneP0     = new Vec3f(0.0f, 0.0f, nearPlane);

                Vec3f farPlaneNormal = new Vec3f(0.0f, 0.0f, -1.0f);
                Vec3f farPlaneP0     = new Vec3f(0.0f, 0.0f, farPlane);

                float sideOfPoint1near = nearPlaneNormal.dot(vertex1.position - nearPlaneP0);
                float sideOfPoint2near = nearPlaneNormal.dot(vertex2.position - nearPlaneP0);
                float sideOfPoint3near = nearPlaneNormal.dot(vertex3.position - nearPlaneP0);

                float sideOfPoint1far = farPlaneNormal.dot(vertex1.position - farPlaneP0);
                float sideOfPoint2far = farPlaneNormal.dot(vertex2.position - farPlaneP0);
                float sideOfPoint3far = farPlaneNormal.dot(vertex3.position - farPlaneP0);

                if ((sideOfPoint1near >= 0 && sideOfPoint2near >= 0 && sideOfPoint3near >= 0) && (sideOfPoint1far >= 0 && sideOfPoint2far >= 0 && sideOfPoint3far >= 0))
                {
                    vertex1.position = new Vec3f(proj * vertex1.position);
                    vertex2.position = new Vec3f(proj * vertex2.position);
                    vertex3.position = new Vec3f(proj * vertex3.position);

                    vertex1.position.x = isNDC ? (vertex1.position.x + 1.0f) * 0.5f * width : vertex1.position.x * width;
                    vertex1.position.y = isNDC ? (vertex1.position.y + 1.0f) * 0.5f * height : vertex1.position.y * height;

                    vertex2.position.x = isNDC ? (vertex2.position.x + 1.0f) * 0.5f * width : vertex2.position.x * width;
                    vertex2.position.y = isNDC ? (vertex2.position.y + 1.0f) * 0.5f * height : vertex2.position.y * height;

                    vertex3.position.x = isNDC ? (vertex3.position.x + 1.0f) * 0.5f * width : vertex3.position.x * width;
                    vertex3.position.y = isNDC ? (vertex3.position.y + 1.0f) * 0.5f * height : vertex3.position.y * height;

                    RPolygon newPolygon = new RPolygon(vertex1, vertex2, vertex3, poly.rasterType, poly.texture);

                    float cosTheta     = newPolygon.normalCalc().dot(GlobalDirection.forward3f);
                    newPolygon.visible = cosTheta >= 0.0f ? false : true;

                    if (!backFaceCull || newPolygon.visible)
                    {
                        newPolygon.sort();
                        lock (sync) {
                            polygons_raster.Add(newPolygon);
                        }
                    }
                }
            }
                );
        }
    public static Vec3f trace(Vec3f rayorig, Vec3f raydir, Sphere[] spheres, int depth)
    {
        float  tnear  = FAR;
        Sphere sphere = null;

        for (int i = 0; i < spheres.Length; i++)
        {
            Collision coll = spheres[i].intersect(rayorig, raydir);
            if (coll.collide && coll.t0 < tnear)
            {
                tnear  = coll.t0;
                sphere = spheres[i];
            }
        }
        if (sphere == null)
        {
            return(new Vec3f(2));
        }
        Vec3f surfaceColor = new Vec3f();
        Vec3f phit         = rayorig + raydir * tnear;
        Vec3f nhit         = (phit - sphere.center).normalize();
        float bias         = 1e-4f;
        bool  inside       = false;

        if (raydir.dot(nhit) > 0)
        {
            nhit = -nhit; inside = true;
        }
        if ((sphere.transparency > 0 || sphere.reflection > 0) && depth < MAX_RAY_DEPTH)
        {
            float facingratio   = -raydir.dot(nhit);
            float fresneleffect = mix((float)Math.Pow(1 - facingratio, 3), 1, 0.1f);
            Vec3f refldir       = (raydir - nhit * 2 * raydir.dot(nhit)).normalize();
            Vec3f reflection    = trace(phit + nhit * bias, refldir, spheres, depth + 1);
            Vec3f refraction    = new Vec3f();
            if (sphere.transparency > 0)
            {
                float ior = 1.1f; float eta = inside ? ior : 1 / ior;
                float cosi    = -nhit.dot(raydir);
                float k       = 1 - eta * eta * (1 - cosi * cosi);
                Vec3f refrdir = (raydir * eta + nhit * (eta * cosi - (float)Math.Sqrt(k))).normalize();
                refraction = trace(phit - nhit * bias, refrdir, spheres, depth + 1);
            }
            surfaceColor = (
                reflection * fresneleffect +
                refraction * (1 - fresneleffect) * sphere.transparency) * sphere.surfaceColor;
        }
        else
        {
            for (int i = 0; i < spheres.Length; i++)
            {
                if (spheres[i].emissionColor.x > 0)
                {
                    Vec3f transmission   = new Vec3f(1);
                    Vec3f lightDirection = (spheres[i].center - phit).normalize();
                    for (int j = 0; j < spheres.Length; j++)
                    {
                        if (i != j)
                        {
                            Collision jcoll = spheres[j].intersect(phit + nhit * bias, lightDirection);
                            if (jcoll.collide)
                            {
                                transmission = new Vec3f();
                                break;
                            }
                        }
                    }
                    surfaceColor += sphere.surfaceColor * transmission *
                                    Math.Max(0, nhit.dot(lightDirection)) * spheres[i].emissionColor;
                }
            }
        }
        return(surfaceColor + sphere.emissionColor);
    }
        public Vec3f trace(Vec3f rayorig, Vec3f raydir, List <Sphere> spheres, int depth)
        {
            float  tnear  = INFINITY;
            Sphere sphere = null;

            //find intersection of this ray with the sphere in the scene
            int spCount = spheres.Count();

            for (int i = 0; i < spCount; ++i)
            {
                float t0 = INFINITY;
                float t1 = INFINITY;
                (bool, float, float)inter = spheres[i].intersect(rayorig, raydir);
                if (inter.Item1)
                {
                    t0 = inter.Item2;
                    t1 = inter.Item3;
                    if (t0 < 0)
                    {
                        t0 = t1;
                    }
                    if (t0 < tnear)
                    {
                        tnear  = t0;
                        sphere = spheres[i];
                    }
                }
            }

            //if there's no intersection return black or background color
            if (sphere == null)
            {
                return(new Vec3f(1.0f));
            }

            Vec3f surfaceColor = new Vec3f(0.0f);          //color of the ray/surfaceof the object intersected by the ray
            Vec3f phit         = rayorig + raydir * tnear; //point of intersection
            Vec3f nhit         = phit - sphere.center;     //normal at the intersection point

            nhit.normalize();                              //normalize normal direction

            //If the normal and the view direction are not opposite to each other
            //reverse the normal direction. That also means we are inside the sphere so set
            //the inside bool to true. Finally reverse the sign of IdotN which we want
            //positive.
            float bias   = 0.0001f; //add some bias to the point from which we will be tracing
            bool  inside = false;

            if (raydir.dot(nhit) > 0)
            {
                nhit   = -1 * nhit;
                inside = true;
            }

            if ((sphere.transparency > 0 || sphere.reflection > 0) && depth < MAX_RAY_DEPTH)
            {
                float facingratio = -raydir.dot(nhit);

                // change the mix value to tweak the effect
                float fresneleffect = mix((float)Math.Pow(1 - facingratio, 3), 1, 0.1f);

                // compute reflection direction (not need to normalize because all vectors
                // are already normalized)
                Vec3f refldir = raydir - nhit * 2 * raydir.dot(nhit);
                refldir.normalize();
                Vec3f reflection = trace(phit + nhit * bias, refldir, spheres, depth + 1);
                Vec3f refraction = new Vec3f(0.0f);

                // if the sphere is also transparent compute refraction ray (transmission)
                if (sphere.transparency != 0.0f)
                {
                    float ior     = 1.1f;
                    float eta     = (inside) ? ior : 1 / ior; // are we inside or outside the surface?
                    float cosi    = -nhit.dot(raydir);
                    float k       = 1 - eta * eta * (1 - cosi * cosi);
                    Vec3f refrdir = raydir * eta + nhit * (eta * cosi - (float)Math.Sqrt(k));
                    refrdir.normalize();
                    refraction = trace(phit - nhit * bias, refrdir, spheres, depth + 1);
                }

                // the result is a mix of reflection and refraction (if the sphere is transparent)
                surfaceColor = (reflection * fresneleffect + refraction * (1.0f - fresneleffect) * sphere.transparency) * sphere.surfaceColor;
            }
            else
            {
                // it's a diffuse object, no need to raytrace any further
                for (int i = 0; i < spCount; ++i)
                {
                    if (spheres[i].emissionColor.x > 0)
                    {
                        // this is a light
                        Vec3f transmission   = new Vec3f(1.0f);
                        Vec3f lightDirection = spheres[i].center - phit;
                        lightDirection.normalize();

                        for (int j = 0; j < spCount; ++j)
                        {
                            if (i != j)
                            {
                                if (spheres[j].intersect(phit + nhit * bias, lightDirection).Item1)
                                {
                                    transmission = new Vec3f(0.0f);
                                    break;
                                }
                            }
                        }

                        surfaceColor += sphere.surfaceColor * transmission * Math.Max(0.0f, nhit.dot(lightDirection)) * spheres[i].emissionColor;
                    }
                }
            }

            return(surfaceColor + sphere.emissionColor);
        }