/// <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; }
/// <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); }
/// <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; }
//Gets and sets //public float getIntensity() { return _intensity; } public override Vect3D GetDirection(ShadeRec sr) { return ((_location - sr.HitPoint).Hat()); }
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; }
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; } }
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; } }
//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; } }
//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; } }
public virtual Vect3D GetDirection(ShadeRec sr) { return new Vect3D(0, 0, 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; }
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; }
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; }
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; } } } } }