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; } }
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); } } } }
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); }