public override double intersection(Ray ray) { Vector3 p0 = Vertices[0]; Vector3 p1 = Vertices[2]; Vector3 p2 = Vertices[1]; Vector3 e1 = p1 - p0; Vector3 e2 = p2 - p0; Vector3 e1e2 = Vector3.Cross(e1, e2); Vector3 p = Vector3.Cross(ray.Direction, e2); e1e2.Normalize(); float a = Vector3.Dot(e1e2, p); if (a < 0.000001) return 0.0; float f = 1.0f / a; Vector3 s = ray.Start - p0; float u = f * Vector3.Dot(s, p); if (u < 0.0 || u > 1.0) return 0.0; Vector3 q = Vector3.Cross(s, e1); float v = f * Vector3.Dot(ray.Direction, q); if (v < 0.0 || u + v > 1.0) return 0.0; float t = f * Vector3.Dot(e2, q); return t; }
public override double intersection(Ray ray) { // sRay is the position of the eye/camera, dRay is the direction of the ray. // the new start and end of the ray for these calculations. Vector3 sRay = new Vector3(); Vector3 dRay = ray.Direction; dRay.Normalize(); //coefficients of quadratic equation, and discriminant double a, b, c, d, t; // transform ray to put sphere centre at origin to make calculations cleaner. sRay = ray.Start - position; a = Vector3.Dot(dRay, dRay); b = 2*Vector3.Dot(dRay, sRay); c = Vector3.Dot(sRay, sRay) - radius * radius; //Find discriminant d = b * b - 4 * a * c; // if discriminant < 0, then the ray did not intersect the object. if (d < 0.0) { return 0.0; } else { d = Math.Sqrt(d); // If there are one or two real values then chose the smallest, // non-negative value, as the intersection point. t = (-b - d) / (2.0 * a); if (t < INTERSECTION_TOLERANCE) t = (-b + d) / (2.0 * a); if (t < INTERSECTION_TOLERANCE) return 0.0; else return t; } }
private Vector3 calcLightRay(Ray ray) { GeometricObject hitShape = null; double closestShape = float.MaxValue; foreach (GeometricObject shape in Shapes) { double t; if (shape is Cube) { Tuple<double, Triangle> temp = shape.intersectionCube(ray); t = temp.Item1; } else { t = shape.intersection(ray); } if (t > 0.0 && t < closestShape) { hitShape = shape; closestShape = t; } } if (hitShape != null) { return FindPointOnRay(ray, closestShape); } else return new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); }
public void spawnVPL(Light light,float width,float height) { Random r = new Random(); List<Vector3> virtualLightPositions = new List<Vector3>(); for (int i = 0; i < NumVirtualLights/3; i++) { virtualLightPositions.Add(new Vector3(r.Next(0, (int)width), r.Next(0, (int)height/3), 0)); } for (int i = 0; i < NumVirtualLights/3; i++) { virtualLightPositions.Add(new Vector3(r.Next(0, (int)width), r.Next((int)height/3, 2*(int)height/3), 0)); } for (int i = 0; i < NumVirtualLights/3; i++) { virtualLightPositions.Add(new Vector3(r.Next(0, (int)width), r.Next(2 * (int)height / 3, (int)height), 0)); } foreach (Vector3 VPLPos in virtualLightPositions) { Vector3 dir = (new Vector3(VPLPos.X, VPLPos.Y, 0)) - Eye; dir.Normalize(); Ray ray = new Ray(Eye, dir); Vector3 newLightPos = calcLightRay(ray); SurfaceType hitSurface; if (newLightPos.X == float.MaxValue) { continue; } else { hitSurface = findSurfaceType(ray); } Vector3 dir2 = light.position - newLightPos; dir2.Normalize(); Ray ray2 = new Ray(newLightPos, dir2); if (isVisible(light, VPLPos, ray2) <= 0) { continue; } if (newLightPos.X != float.MaxValue && newLightPos.Y != float.MaxValue && newLightPos.Z != float.MaxValue) { if (drawSpheres) { GeometricObject testSphere = new Sphere(ImageSize.Y / 32.0f, newLightPos, new Vector4(0, 0, 0, 255), new SurfaceType(textureType.standard,new Vector3(200, 100, 100), new Vector3(100, 40, 78), new Vector3(50, 50, 50), new Vector3(255, 255, 255), 0)); Shapes.Add(testSphere); } else { VirtualLights.Add(new Light() { position = newLightPos, color = light.color, intensity = (float)(1.0f / (float)NumVirtualLights) }); } } } }
private SurfaceType findSurfaceType(Ray ray) { GeometricObject hitShape = null; double closestShape = float.MaxValue; foreach (GeometricObject shape in Shapes) { double t; if (shape is Cube) { Tuple<double, Triangle> temp = shape.intersectionCube(ray); t = temp.Item1; } else { t = shape.intersection(ray); } if (t > 0.0 && t < closestShape) { hitShape = shape; closestShape = t; } } if (hitShape != null) { return hitShape.surface; } else return null; }
public override double intersection(Ray r) { float t = float.MaxValue;//(r.Direction.X * r.Direction.X + r.Direction.Y * r.Direction.Y + r.Direction.Z * r.Direction.Z); List<poly> polynomMap = new List<poly>(); float rSquare, rInvSquare; rSquare = size * size; rInvSquare = invSizeSquare; float maxEstimatedPotential = 0.0f; float A = 0.0f; float B = 0.0f; float C = 0.0f; for (int i= 0; i< centerList.Count; i++) { Vector3 currentPoint = centerList[i]; Vector3 vDist = currentPoint - r.Start; float aa = 1.0f; float bb = - 2.0f * (r.Direction.X*vDist.X + r.Direction.Y*vDist.Y + r.Direction.Z*vDist.Z); float cc = (vDist.X*vDist.X + vDist.Y*vDist.Y + vDist.Z*vDist.Z); float BSquareOverFourMinusC = 0.25f * bb * bb - cc; float MinusBOverTwo = -0.5f * bb; float ATimeInvSquare = aa * rInvSquare; float BTimeInvSquare = bb * rInvSquare; float CTimeInvSquare = cc * rInvSquare; for (int j=0; j < zoneNumber - 1; j++) { float fDelta = BSquareOverFourMinusC + zoneTab[j].fCoef * rSquare; if (fDelta < 0.0f) { break; } float sqrtDelta = (float)Math.Sqrt(fDelta); float t0 = MinusBOverTwo - sqrtDelta; float t1 = MinusBOverTwo + sqrtDelta; poly poly0 = new poly(zoneTab[j].fGamma * ATimeInvSquare , zoneTab[j].fGamma * BTimeInvSquare , zoneTab[j].fGamma * CTimeInvSquare + zoneTab[j].fBeta, t0, zoneTab[j].fDeltaFInvSquare); poly poly1 = new poly(- poly0.a, - poly0.b, - poly0.c, t1, -poly0.fDeltaFInvSquare); maxEstimatedPotential += zoneTab[j].fDeltaFInvSquare; polynomMap.Add(poly0); polynomMap.Add(poly1); }; } if (polynomMap.Count < 2 || maxEstimatedPotential < 1.0f) { return 0; } polynomMap.Sort((x, y) => x.isLess(y)); maxEstimatedPotential = 0.0f; bool bResult = false; int it, itNext; for(it = 0, itNext = it+1; itNext < polynomMap.Count; it = itNext, itNext++) { A += polynomMap[it].a; B += polynomMap[it].b; C += polynomMap[it].c; maxEstimatedPotential += polynomMap[it].fDeltaFInvSquare; if (maxEstimatedPotential < 1.0f) { continue; } float fZoneStart = polynomMap[it].fDistance; float fZoneEnd = polynomMap[itNext].fDistance; if (t > fZoneStart && 0.01f < fZoneEnd ) { float fDelta = B * B - 4.0f * A * (C - 1.0f) ; if (fDelta < 0.0f) { continue; } if(A == 0) A = float.MinValue; float fInvA = (0.5f / A); float fSqrtDelta = (float)Math.Sqrt(fDelta); float t0 = fInvA * (- B - fSqrtDelta); float t1 = fInvA * (- B + fSqrtDelta); if ((t0 > 0.01f ) && (t0 >= fZoneStart ) && (t0 < fZoneEnd) && (t0 <= t )) { t = t0; bResult = true; } if ((t1 > 0.01f ) && (t1 >= fZoneStart ) && (t1 < fZoneEnd) && (t1 <= t )) { t = t1; bResult = true; } if (bResult) { return t; } } } return 0; }
public virtual Tuple<double, Triangle> intersectionCube(Ray ray) { throw new Exception("INTERSECTIONCUBE NOT IMPLEMENTED!!!"); }
public virtual double intersection(Ray ray) { throw new Exception("INTERSECTION NOT IMPLEMENTED!!!"); }
// Find the point along the ray vector where the hit occurs. private Vector3 FindPointOnRay(Ray ray, double t) { Vector3 intersect; intersect.X = (float)(ray.Start.X + t * ray.Direction.X); intersect.Y = (float)(ray.Start.Y + t * ray.Direction.Y); intersect.Z = (float)(ray.Start.Z + t * ray.Direction.Z); return intersect; }
private GeometricObject FindClosestShape(Ray r, Light l, GeometricObject theShape) { double dist = float.MaxValue; GeometricObject closest = null; foreach (GeometricObject shape in Shapes) { double t; if (shape is Cube) { Tuple<double, Triangle> temp = shape.intersectionCube(r); t = temp.Item1; } else { t = shape.intersection(r); } if (theShape != shape && t < dist && t > 0.0f && shape.surface.RefractionIndex < 1) { closest = shape; dist = t; } } foreach (Light light in Lights) { if (light != l) continue; double t = light.intersection(r); if (light.intersection(r) < dist) { closest = light; dist = t; } } return closest; }
private float isVisible(Light L, Vector3 hitPoint, Ray ray, GeometricObject theShape = null) { float retVal = 0.0f; float offset = 5; float numSegments = 1; float numAlongSegment = 1; Vector3 dir; Ray r; for (float i = 0; i <= 2 * Math.PI; i += 2.0f * (float)Math.PI / (numSegments)) { for (float j = 1; j <= numAlongSegment; j++) { dir = L.position + new Vector3((float)Math.Cos(i) * L.radius / j + offset * (Math.Cos(i) < 0 ? 1 : -1), (float)Math.Sin(i) * L.radius / j + offset * (Math.Sin(i) < 0 ? 1 : -1), 0); dir = dir - ray.Start; dir.Normalize(); r = new Ray(ray.Start, dir); if (FindClosestShape(r, L, theShape) == L) retVal += 1.0f / (numSegments * numAlongSegment); } } return Clamp(retVal, 0, 1); }
/// <summary> /// Traces rays and calculates their color. Recursive method /// </summary> /// <param name="ray"></param> /// <param name="depth"></param> /// <param name="coef"></param> /// <param name="specOn">if at any point an object is not specular, all successive recursive calls will ignore specular</param> /// <returns></returns> private Vector3 AddRay(Ray ray, int depth, float coef, ref float prevDist, float lastRIndex = 1) { Vector3 curColor = new Vector3(0, 0, 0); GeometricObject hitShape = null; double hitShapeDist = float.MaxValue; Vector3 vNormal; Vector3 hp; float LightValue = 0.0f; Triangle hitTri = new Triangle(); foreach (GeometricObject shape in Shapes) { if (shape == null) continue; double t; if (shape is Cube) { Tuple<double, Triangle> temp = shape.intersectionCube(ray); t = temp.Item1; hitTri = temp.Item2; } else { t = shape.intersection(ray); } if (t > 0.0 && t < hitShapeDist) { hitShape = shape; hitShapeDist = t; prevDist = (float)t; } } if (hitShape == null) { if (depth == 0) return new Vector3(-1, -1, -1); else return new Vector3(0, 0, 0); } else { hp = FindPointOnRay(ray, hitShapeDist); if (hitShape is Cube) { vNormal = hitShape.NormalAtCube(hp, Eye, hitTri); } else { vNormal = hitShape.NormalAt(hp, Eye); } if (hitShape.surface.type == textureType.bump) { const double bumpLevel = 0.2; double noiseX = perlinTexture.noise(0.1 * (double)hp.X, 0.1 * (double)hp.Y, 0.1 * (double)hp.Z); double noiseY = perlinTexture.noise(0.1 * (double)hp.Y, 0.1 * (double)hp.Z, 0.1 * (double)hp.X); double noiseZ = perlinTexture.noise(0.1 * (double)hp.Z, 0.1 * (double)hp.X, 0.1 * (double)hp.Y); vNormal.X = (float)((1.0 - bumpLevel) * vNormal.X + bumpLevel * noiseX); vNormal.Y = (float)((1.0 - bumpLevel) * vNormal.Y + bumpLevel * noiseY); vNormal.Z = (float)((1.0 - bumpLevel) * vNormal.Z + bumpLevel * noiseZ); double temp = Vector3.Dot(vNormal, vNormal); if (temp != 0.0) { temp = 1.0 / Math.Sqrt(temp); vNormal = (float)temp * vNormal; } } vNormal.Normalize(); foreach (Light light in Lights) { Vector3 dir = light.position - hp; dir.Normalize(); Ray lightRay = new Ray(hp, dir); if ((LightValue = isVisible(light, hp, lightRay)) > 0) { Vector3 color = new Vector3(); if (hitShape is Triangle) { if (((Triangle)hitShape).HasTexture) { color = GetPixelColorFromTexture(hp, hitShape as Triangle); } else { color = hitShape.surface.color; } } else { color = hitShape.surface.color; } //TODO to add ambient just do Llight[ambient] * hitShape[ambiemt] float lambert = Vector3.Dot(lightRay.Direction, vNormal) ; curColor += light.intensity * lambert * ((light.color)) * (color) * coef; Vector3 blinn = lightRay.Direction - ray.Direction; blinn.Normalize(); float blinnValue = (float)Math.Pow(Math.Max(0, Vector3.Dot(vNormal, blinn)), hitShape.surface.SpecExponent); curColor += hitShape.surface.specular * light.intensity * light.color * blinnValue * coef; curColor *= LightValue; } } } if (depth >= NumBounces) return Clamp(curColor); else { //calculate reflections Vector3 dir = ray.Direction - (2.0f * Vector3.Dot(ray.Direction, vNormal)) * vNormal; dir.Normalize(); float UGH = 0; curColor += AddRay(new Ray(hp, dir), depth + 1, coef * ((float)hitShape.surface.reflectiveness / 100.0f), ref UGH); //calculate refraction (nigguh) float refr = hitShape.surface.RefractionIndex; if (refr > 0) { float n = lastRIndex/refr; float cos = Vector3.Dot(ray.Direction, vNormal); float sin = (float)Math.Pow(n, 2) * (1 - (float)Math.Pow(cos,2)); if (Math.Pow(sin,2) <= 1) { Vector3 transmissiveDir = n * ray.Direction - (n * cos + (float)Math.Sqrt(1 - (float)Math.Pow(sin, 2))) * vNormal; transmissiveDir.Normalize(); float dist = 0; Vector3 theColor = AddRay(new Ray(hp, transmissiveDir), depth + 1, coef, ref dist, refr); Vector3 absorbance = hitShape.surface.color * 0.0000015f * -dist; Vector3 trans = new Vector3((float)Math.Exp(absorbance.X), (float)Math.Exp(absorbance.Y), (float)Math.Exp(absorbance.Z)); curColor += theColor * trans; } } } return Clamp(curColor); }
private async Task<byte[]> Trace(int width, int height) { string s = "0 = 100"; // 4 bytes required for each pixel byte[] result = new byte[width * height * 4]; int resultIndex = 0; float totalNum = width * height; Vector3 color = new Vector3(0, 0, 0); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { color = new Vector3(0, 0, 0); //if(y>ImageSize.Y / 2.0f ) for (float innerPixelY = 1.0f / numInnerPixels; innerPixelY <= 1; innerPixelY += 1.0f / numInnerPixels) { for (float innerPixelX = 1.0f / numInnerPixels; innerPixelX <= 1; innerPixelX += 1.0f / numInnerPixels) { Vector3 dir = (new Vector3(x + (innerPixelX - (1.0f / numInnerPixels * 2.0f)), y + (innerPixelY - (1.0f / numInnerPixels * 2.0f)), 0)) - Eye; dir.Normalize(); Ray ray = new Ray(Eye, dir); float ThisVariableDoesAbsolutelyNothingInThisSpotButYouNeedItForTheRefVariable = 0; color += AddRay(ray, 0, 1.0f, ref ThisVariableDoesAbsolutelyNothingInThisSpotButYouNeedItForTheRefVariable); } } color /= (numInnerPixels * numInnerPixels); color *= 255.0f; if (color.X < 0 || color.Y < 0 || color.Z < 0) { color = new Vector3(0, 0, 0); } result[resultIndex++] = Convert.ToByte(color.Z); // Green value of pixel result[resultIndex++] = Convert.ToByte(color.Y); // Blue value of pixel result[resultIndex++] = Convert.ToByte(color.X); // Red value of pixel result[resultIndex++] = Convert.ToByte(255); // Alpha value of pixel float n = (((float)y) * height + x) / totalNum * 100; if (n == (int)n) { if (!DontPornIt) { MainPage.d.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new Windows.UI.Core.DispatchedHandler(async () => { // Open a stream to copy the graph to the WriteableBitmap's pixel buffer using (Stream stream = WB.PixelBuffer.AsStream()) { byte[] tempr = result; await stream.WriteAsync(tempr, 0, tempr.Length); } WB.Invalidate(); })); } s = s.Replace("= ", " ="); System.Diagnostics.Debug.WriteLine(s); } } } return result; }
public override Tuple<double, Triangle> intersectionCube(Ray ray) { float closest = float.PositiveInfinity; foreach (Triangle triangle in planes) { Vector3 p0 = triangle.Vertices[0]; Vector3 p1 = triangle.Vertices[2]; Vector3 p2 = triangle.Vertices[1]; Vector3 e1 = p1 - p0; Vector3 e2 = p2 - p0; Vector3 p = Vector3.Cross(ray.Direction, e2); float a = Vector3.Dot(e1, p); if (a < 0.000001) continue;// return 0.0; float f = 1.0f / a; Vector3 s = ray.Start - p0; float u = f * Vector3.Dot(s, p); if (u < 0.0 || u > 1.0) continue;// return 0.0; Vector3 q = Vector3.Cross(s, e1); float v = f * Vector3.Dot(ray.Direction, q); if (v < 0.0 || u + v > 1.0) continue;// return 0.0; float t = f * Vector3.Dot(e2, q); //return t; if (t < closest) { closest = t; hitTri = triangle; } } if (closest < float.PositiveInfinity) { return new Tuple<double,Triangle>(closest,hitTri); } else return new Tuple<double, Triangle>(0.0, null) ; }