public override RealHitInfo DelayedHitCalc(Line by, HitInfo hit) { RealHitInfo realHit = new RealHitInfo(); realHit.HitStuff = Surface; realHit.Pigment = Pigment; realHit.Normal = new Line(); realHit.Normal.Start = by.Project(hit.HitDist); realHit.Normal.Direct.Dx = 0; realHit.Normal.Direct.Dy = 0; realHit.Normal.Direct.Dz = 0; switch (hit.SurfaceIndex) { case 0: Point hitLoc2 = inv.Apply(realHit.Normal.Start); realHit.Normal.Direct.Dx = hitLoc2.X; realHit.Normal.Direct.Dy = hitLoc2.Y; realHit.Normal.Direct.Dz = hitLoc2.Z; break; default: throw new InvalidOperationException("Invalid surface index in hitdata"); } Vector before = realHit.Normal.Direct; realHit.Normal.Direct = trans.Apply(realHit.Normal.Direct); if (realHit.Normal.Direct.Dot(by.Direct) > 0) { realHit.Normal.Direct.ScaleSelf(-1.0); } return realHit; }
public override RealHitInfo DelayedHitCalc(Line by, HitInfo hit) { RealHitInfo realHit = new RealHitInfo(); realHit.HitStuff = Surface; realHit.Pigment = Pigment; realHit.Normal = new Line(); realHit.Normal.Start = by.Project(hit.HitDist); realHit.Normal.Direct.Dx = 0; realHit.Normal.Direct.Dy = 0; realHit.Normal.Direct.Dz = 0; Point hitLoc; Vector deviance = new Vector(); if (rounded) { hitLoc = inv.Apply(realHit.Normal.Start); if (hit.SurfaceIndex == 1 || (!RoundedTopOnly && hit.SurfaceIndex == 2)) { double r = Math.Sqrt(hitLoc.X * hitLoc.X + hitLoc.Y * hitLoc.Y); if (r > 1 - RRounding) { double dr = (1 - (1 - r) / RRounding) / (r); deviance.Dx = hitLoc.X * dr; deviance.Dy = hitLoc.Y * dr; } } if (!RoundedTopOnly && hitLoc.Z < -1 + ZRounding) { switch (hit.SurfaceIndex) { case 0: deviance.Dz = -1 + (hitLoc.Z + 1) / ZRounding; break; } } if (hitLoc.Z > 1 - ZRounding) { switch (hit.SurfaceIndex) { case 0: deviance.Dz = 1 - (1 - hitLoc.Z) / ZRounding; break; } } } switch (hit.SurfaceIndex) { case 0: Point hitLoc2 = inv.Apply(realHit.Normal.Start); realHit.Normal.Direct.Dx = hitLoc2.X; realHit.Normal.Direct.Dy = hitLoc2.Y; break; case 1: realHit.Normal.Direct.Dz = 1; break; case 2: realHit.Normal.Direct.Dz = -1; break; default: throw new InvalidOperationException("Invalid surface index in hitdata"); } Vector before = realHit.Normal.Direct; realHit.Normal.Direct = trans.Apply(realHit.Normal.Direct); if (realHit.Normal.Direct.Dot(by.Direct) > 0) { if (rounded) { before.ScaleSelf(-1.0); deviance.ScaleSelf(-1.0); } else realHit.Normal.Direct.ScaleSelf(-1.0); } if (rounded) { realHit.Normal.Direct = before; realHit.Normal.Direct.Add(deviance); realHit.Normal.Direct = trans.Apply(realHit.Normal.Direct); if (realHit.Normal.Direct.Dot(by.Direct) > 0) { Vector perp1 = realHit.Normal.Direct.Cross(by.Direct); realHit.Normal.Direct = by.Direct.Cross(perp1); } } return realHit; }
private ColorIntensity ShadowShade(RealHitInfo hit, Line by, int recurse, double ratio, bool inside, int threadId, double lightdist) { #if DEBUG if (Gathering) { CurrentGather.Weight = ratio; CurrentGather.RealInfo = hit; } #endif ColorIntensity colors; Material surf = hit.HitStuff; double[] atten = new double[3]; double rI, gI, bI; double dist = hit.Normal.Start.LineTo(by.Start).Length; lightdist -= dist; bool stop = lightdist < 0; if (lightdist < 0) dist += lightdist; if (surf.Attenutive && inside) { atten[0] = Math.Exp(-(1.0 - surf.Attenuation[0]) * dist / surf.AttenuationDistance); atten[1] = Math.Exp(-(1.0 - surf.Attenuation[1]) * dist / surf.AttenuationDistance); atten[2] = Math.Exp(-(1.0 - surf.Attenuation[2]) * dist / surf.AttenuationDistance); ratio = ratio * (atten[0] + atten[1] + atten[2]) / 3; } if (recurse < maxrecurse && ratio > minratio) { if (!stop) { Line newray = new Line(); newray.Direct = new Vector(by.Direct.Dx, by.Direct.Dy, by.Direct.Dz); newray.Start = hit.Normal.Start.MoveBy(newray.Direct.Scale(EPSILON * 10)); SetIn(ref newray.Start, threadId); HitInfo hitnew = scene.Intersect(newray, threadId); if (!(hitnew.HitDist == -1)) { #if DEBUG GatherInfo last = null; if (Gathering) { last = CurrentGather; CurrentGather = new GatherInfo(); } #endif ColorIntensity cl = ShadowShade(hitnew.GetReal(newray), newray, recurse + 1, ratio, !inside, threadId, lightdist); #if DEBUG if (Gathering) { last.LightChildren.Add(CurrentGather); CurrentGather = last; } #endif rI = cl.R; gI = cl.G; bI = cl.B; } else { rI = 1.0; gI = 1.0; bI = 1.0; } } else { rI = 1.0; gI = 1.0; bI = 1.0; } } else { if (recurse >= maxrecurse) { // Recurse limit reached. int i = 0; i = i * 3; } rI = 0; bI = 0; gI = 0; } if (surf.Attenutive && inside) { rI *= atten[0]; gI *= atten[1]; bI *= atten[2]; } if (!stop) { // Correct for how much light would be diffused at each interface. rI *= surf.Specularity; gI *= surf.Specularity; bI *= surf.Specularity; // Correct for reflection. double minFresnelReflectence = (surf.RefractIndex - 1) / (surf.RefractIndex + 1); minFresnelReflectence *= minFresnelReflectence; rI *= 1.0 - surf.Reflectance[0] - minFresnelReflectence; gI *= 1.0 - surf.Reflectance[1] - minFresnelReflectence; bI *= 1.0 - surf.Reflectance[2] - minFresnelReflectence; } colors.R = rI; colors.G = gI; colors.B = bI; return colors; }
private ColorIntensity Shade(RealHitInfo hit, Line by, int threadId) { return Shade(hit, by, 0, 1.0, false, threadId); }
private ColorIntensity Shade(RealHitInfo hit, Line by, int recurse, double ratio, bool inside, int threadId) { #if DEBUG if (Gathering) { CurrentGather.Weight = ratio; CurrentGather.RealInfo = hit; } #endif ColorIntensity colors, shadowcolors; Material surf = hit.HitStuff; ColorIntensity pigment = hit.Pigment.GetTexture(hit.Normal, 0); ColorIntensity atten = new ColorIntensity(); if (surf.Attenutive && inside) { double dist = hit.Normal.Start.LineTo(by.Start).Length; atten.R = Math.Exp(-(1.0 - surf.Attenuation[0]) * dist / surf.AttenuationDistance); atten.G = Math.Exp(-(1.0 - surf.Attenuation[1]) * dist / surf.AttenuationDistance); atten.B = Math.Exp(-(1.0 - surf.Attenuation[2]) * dist / surf.AttenuationDistance); ratio = ratio * (atten.R + atten.G + atten.B) / 3; } double rI = 0; double gI = 0; double bI = 0; Vector lightdir; Line newray = new Line(); HitInfo hitnewray = new HitInfo(); hit.Normal.Direct = hit.Normal.Direct.Scale(1 / hit.Normal.Direct.Length); Vector eye = by.Direct.Scale(-1 / by.Direct.Length); int lightCount = (allLightsArePhotons && photons) ? 0 : lights.Count; //lightCount = 0; for (int i = 0; i < lightCount; i++) { double lightdist = double.PositiveInfinity; switch (lights[i].LightType) { case LightType.Ambient: rI += lights[i].Color.R * surf.Ambient[0]; gI += lights[i].Color.G * surf.Ambient[1]; bI += lights[i].Color.B * surf.Ambient[2]; continue; case LightType.Directional: lightdir = lights[i].Direction.Direct.Scale(-1); break; case LightType.Point: lightdir = hit.Normal.Start.LineTo(lights[i].Direction.Start); lightdist = lightdir.Length; break; default: continue; } // Add double illuminate flag or something to turn this off. if (true) { if (lightdir.Dot(hit.Normal.Direct) <= 0.0) continue; } newray.Direct = lightdir.Scale(1.0/lightdir.Length); if (newray.Direct.Dot(hit.Normal.Direct) >= 0) newray.Start = hit.Normal.Start.MoveBy(newray.Direct.Scale(EPSILON * 10)); else newray.Start = hit.Normal.Start.MoveBy(newray.Direct.Scale(-EPSILON * 10)); SetIn(ref newray.Start, threadId); HitInfo info = scene.Intersect(newray, false, threadId); if (!(info.HitDist == -1 || info.HitDist > lightdist)) continue; shadowcolors.R = 1.0; shadowcolors.G = 1.0; shadowcolors.B = 1.0; // Don't need to setIn again, seperate intersect cache for shadow vs non-shadow rays. hitnewray = scene.Intersect(newray, threadId); if (!photons) { if (!(hitnewray.HitDist == -1 || hitnewray.HitDist > lightdist)) { #if DEBUG GatherInfo last = null; if (Gathering) { last = CurrentGather; CurrentGather = new GatherInfo(); } #endif shadowcolors = ShadowShade(hitnewray.GetReal(newray), newray, recurse + 1, ratio, inside, threadId, lightdist); #if DEBUG if (Gathering) { last.LightChildren.Add(CurrentGather); CurrentGather = last; } #endif } } else { if (!(hitnewray.HitDist == -1 || hitnewray.HitDist > lightdist)) continue; } shadowcolors.R *= lights[i].Color.R; shadowcolors.G *= lights[i].Color.G; shadowcolors.B *= lights[i].Color.B; if (realLighting && lightdist < double.PositiveInfinity) { double lightdistSq = lightdist * lightdist; shadowcolors.R /= lightdistSq; shadowcolors.G /= lightdistSq; shadowcolors.B /= lightdistSq; } CalculateLightContrib(hit.Normal.Direct, shadowcolors, surf, pigment, ref rI, ref gI, ref bI, lightdir, eye); } if (photons) { double scaleRadSq; List<Photon> closePhotons = Map.GetClosest(hit.Normal.Start, hit.Normal.Direct, out scaleRadSq, threadId); double photoR = 0.0; double photoG = 0.0; double photoB = 0.0; foreach (Photon photon in closePhotons) { lightdir.Dx = -photon.TravelDir.Dx; lightdir.Dy = -photon.TravelDir.Dy; lightdir.Dz = -photon.TravelDir.Dz; if (true) { if (lightdir.Dot(hit.Normal.Direct) <= 0.0) continue; } ColorIntensity photonColor; photonColor.R = photon.PhotonColorPower.R; photonColor.G = photon.PhotonColorPower.G; photonColor.B = photon.PhotonColorPower.B; CalculateLightContrib(hit.Normal.Direct, photonColor, surf, pigment, ref photoR, ref photoG, ref photoB, lightdir, eye); #if DEBUG if (Gathering) { CurrentGather.GatheredPhotons.Add(photon); } #endif } if (closePhotons.Count > 0) { rI += photoR / Math.PI / scaleRadSq; if (rI > 3) { int breakpoint = 3; breakpoint *= 34; } gI += photoG / Math.PI / scaleRadSq; if (gI > 3) { int breakpoint = 3; breakpoint *= 34; } bI += photoB / Math.PI / scaleRadSq; if (bI > 3) { int breakpoint = 3; breakpoint *= 34; } } } if ((surf.Refractive || surf.Reflective) && recurse < maxrecurse) { by.Direct = by.Direct.Scale(1 / by.Direct.Length); ColorIntensity reflectance = new ColorIntensity(); reflectance.R = surf.Reflective ? surf.Reflectance[0] : 0.0; reflectance.G = surf.Reflective ? surf.Reflectance[1] : 0.0; reflectance.B = surf.Reflective ? surf.Reflectance[2] : 0.0; if (surf.Refractive) { double ni = inside ? surf.RefractIndex : 1.0; double nt = (!inside) ? surf.RefractIndex : 1.0; double cratio = ni / nt; double ct1 = -by.Direct.Dot(hit.Normal.Direct); double ct2sqrd = 1 - cratio * cratio * (1 - ct1 * ct1); if (ct2sqrd <= 0) { reflectance.R = 1; reflectance.G = 1; reflectance.B = 1; } else { double ct2 = Math.Sqrt(ct2sqrd); // fresnel equations for reflectance perp and parallel. double rperp = (ni * ct1 - nt * ct2) / (ni * ct1 + nt * ct2); double rpll = (nt * ct1 - ni * ct2) / (ni * ct2 + nt + ct1); // assume unpolarised light always - better then tracing 2 // rays for both sides of every interface. double reflectanceval = (rperp * rperp + rpll * rpll) / 2; reflectance.R = Math.Min(1.0, reflectance.R + reflectanceval); reflectance.G = Math.Min(1.0, reflectance.G + reflectanceval); reflectance.B = Math.Min(1.0, reflectance.B + reflectanceval); ColorIntensity transmitance = new ColorIntensity(); transmitance.R = 1 - reflectance.R; transmitance.G = 1 - reflectance.G; transmitance.B = 1 - reflectance.B; double avt = transmitance.R + transmitance.G + transmitance.B; avt /= 3; if (avt * ratio*surf.Specularity > minratio) { Line newray2 = new Line(); newray2.Direct = by.Direct.Scale(cratio); newray2.Direct.Add(hit.Normal.Direct.Scale(cratio * (ct1) - ct2)); newray2.Start = hit.Normal.Start.MoveBy(newray2.Direct.Scale(EPSILON * 10)); SetIn(ref newray2.Start, threadId); HitInfo hitnew = scene.Intersect(newray2, threadId); if (!(hitnew.HitDist == -1)) { #if DEBUG GatherInfo last2 = null; if (Gathering) { last2 = CurrentGather; CurrentGather = new GatherInfo(); } #endif ColorIntensity cl = Shade(hitnew.GetReal(newray2), newray2, recurse + 1, avt * ratio * surf.Specularity, !inside, threadId); #if DEBUG if (Gathering) { last2.Children.Add(CurrentGather); CurrentGather = last2; } #endif rI = rI + ((double)transmitance.R * cl.R) * surf.Specularity; gI = gI + ((double)transmitance.G * cl.G) * surf.Specularity; bI = bI + ((double)transmitance.B * cl.B) * surf.Specularity; } } } } double avr = reflectance.R + reflectance.G + reflectance.B; avr /= 3; double specularity = surf.Refractive ? surf.Specularity : 1.0; if (avr * ratio*specularity > minratio) { Line newray2 = new Line(); newray2.Direct = new Vector(by.Direct.Dx, by.Direct.Dy, by.Direct.Dz); newray2.Direct.Add(hit.Normal.Direct.Scale(-2 * by.Direct.Dot(hit.Normal.Direct))); newray2.Start = hit.Normal.Start.MoveBy(newray2.Direct.Scale(EPSILON * 10)); SetIn(ref newray2.Start, threadId); HitInfo hitnew2 = scene.Intersect(newray2, threadId); if (!(hitnew2.HitDist == -1)) { #if DEBUG GatherInfo last3 = null; if (Gathering) { last3 = CurrentGather; CurrentGather = new GatherInfo(); } #endif ColorIntensity cl2 = Shade(hitnew2.GetReal(newray2), newray2, recurse + 1, avr * ratio * specularity, inside, threadId); #if DEBUG if (Gathering) { last3.Children.Add(CurrentGather); CurrentGather = last3; } #endif rI = rI + ((double)reflectance.R * cl2.R) * specularity; gI = gI + ((double)reflectance.G * cl2.G) * specularity; bI = bI + ((double)reflectance.B * cl2.B) * specularity; } } } else { if (recurse >= maxrecurse) { // Recurse limit reached. int i = 0; i = i * 3; } } if (surf.Attenutive && inside) { rI *= atten.R; gI *= atten.G; bI *= atten.B; } colors.R = rI; colors.G = gI; colors.B = bI; return colors; }
private ColorIntensity ShadowShade(RealHitInfo hit, Line by, int threadId, double lightdist) { return ShadowShade(hit, by, 0, 1.0, false, threadId, lightdist); }
public override RealHitInfo DelayedHitCalc(Line by, HitInfo hit) { RealHitInfo realHit = new RealHitInfo(); realHit.Normal = new Line(); realHit.HitStuff = Surface; realHit.Pigment = Pigment; realHit.Normal.Start = by.Project(hit.HitDist); realHit.Normal.Direct.Dx = 0; realHit.Normal.Direct.Dy = 0; realHit.Normal.Direct.Dz = 0; Point hitLoc; Vector deviance = new Vector(); if (rounded) { hitLoc = inv.Apply(realHit.Normal.Start); if (hit.SurfaceIndex != 5 || !RoundedTopOnly) { if (hitLoc.X < -1 + XRounding) { switch (hit.SurfaceIndex) { case 2: case 3: case 4: case 5: deviance.Dx = -1 + (hitLoc.X + 1) / XRounding; break; } } if (hitLoc.X > 1 - XRounding) { switch (hit.SurfaceIndex) { case 2: case 3: case 4: case 5: deviance.Dx = 1 - (1 - hitLoc.X) / XRounding; break; } } if (hitLoc.Y < -1 + YRounding) { switch (hit.SurfaceIndex) { case 0: case 1: case 4: case 5: deviance.Dy = -1 + (hitLoc.Y + 1) / YRounding; break; } } if (hitLoc.Y > 1 - YRounding) { switch (hit.SurfaceIndex) { case 0: case 1: case 4: case 5: deviance.Dy = 1 - (1 - hitLoc.Y) / YRounding; break; } } } if (!RoundedTopOnly && hitLoc.Z < -1 + ZRounding) { switch (hit.SurfaceIndex) { case 0: case 1: case 2: case 3: deviance.Dz = -1 +(hitLoc.Z + 1) / ZRounding; break; } } if (hitLoc.Z > 1 - ZRounding) { switch (hit.SurfaceIndex) { case 0: case 1: case 2: case 3: deviance.Dz = 1 - (1 - hitLoc.Z) / ZRounding; break; } } } switch (hit.SurfaceIndex) { case 0: realHit.Normal.Direct.Dx = 1; break; case 1: realHit.Normal.Direct.Dx = -1; break; case 2: realHit.Normal.Direct.Dy = 1; break; case 3: realHit.Normal.Direct.Dy = -1; break; case 4: realHit.Normal.Direct.Dz = 1; break; case 5: realHit.Normal.Direct.Dz = -1; break; default: throw new InvalidOperationException("Invalid surface index in hitdata"); } Vector before = realHit.Normal.Direct; realHit.Normal.Direct = trans.Apply(realHit.Normal.Direct); if (realHit.Normal.Direct.Dot(by.Direct) > 0) { if (rounded) { before.ScaleSelf(-1.0); deviance.ScaleSelf(-1.0); } else realHit.Normal.Direct.ScaleSelf(-1.0); } if (rounded) { realHit.Normal.Direct = before; realHit.Normal.Direct.Add(deviance); realHit.Normal.Direct = trans.Apply(realHit.Normal.Direct); if (realHit.Normal.Direct.Dot(by.Direct) > 0) { Vector perp1 = realHit.Normal.Direct.Cross(by.Direct); realHit.Normal.Direct = by.Direct.Cross(perp1); } } return realHit; }