private SampledSpectrum SampleLights(Scene scene, BSDF bsdf, ref Intersection intersection, ref Vector3 leaving) { var lights = scene.Lights; var spectrum = SampledSpectrum.Black(); foreach (var light in lights) { var nsamples = _strategy == LightSamplingStrategy.Multiple ? light.NSamples : 1; var lightContribution = SampledSpectrum.Black(); for (var i = 0; i < nsamples; ++i) { Vector3 incoming; VisibilityTester visibilityTester; var lightSpectrum = light.Sample(ref intersection.Point, scene, out incoming, out visibilityTester); if (lightSpectrum.IsBlack() || visibilityTester.Occluded()) { continue; } var cosangle = Math.Abs(Vector3.Dot(incoming, intersection.NormalVector)); // we get the light coming to us from transmission + reflection var distribution = bsdf.F(incoming, leaving, BxDF.BxDFType.All); // we scale the light by the incident angle of light on the surface and by the distribution // function from light to us and we add it to the spectrum lightContribution += distribution * lightSpectrum * cosangle; } spectrum += lightContribution / nsamples; } return(spectrum); }
public override SampledSpectrum Li(Scene scene, Ray ray, Renderer renderer, Sample sample, ref Intersection i) { var spectrum = SampledSpectrum.Black(); var lights = scene.Lights; var bsdfAtPoint = i.GetBSDF(); // we want to get the radiance coming from the surface to us, but the ray comes from us // to the surface var leaving = -ray.Direction; foreach (var light in lights) { Vector3 incoming; VisibilityTester visibilityTester; var lightSpectrum = light.Sample(ref i.Point, scene, out incoming, out visibilityTester); // We compute the BSDF value only if the light is not black and it is not occluded. Note that it is important // for the occlusion test to be after the test for black spectrum, because checking for intersection is an // expansive operation. if (!lightSpectrum.IsBlack() && !visibilityTester.Occluded()) { var cosangle = Math.Abs(Vector3.Dot(incoming, i.NormalVector)); // we get the light coming to us from transmission + reflection var bsdf = bsdfAtPoint.F(incoming, leaving, BxDF.BxDFType.All); // we scale the light by the incident angle of light on the surface and by the distribution // function from light to us and we add it to the spectrum spectrum += bsdf * lightSpectrum * cosangle; } } if (ray.Depth + 1 < MaxDepth) { spectrum += SpecularTransmit(ray, renderer, sample, bsdfAtPoint, ref i); spectrum += SpecularReflect(ray, renderer, sample, bsdfAtPoint, ref i); } return(spectrum); }
public FresnelBlend(SampledSpectrum d, SampledSpectrum s, MicrofacetDistribution dist) : base(BxDFType.Reflection | BxDFType.Glossy) { _distribution = dist; _rd = d; _rs = s; }
public Microfacet(SampledSpectrum reflectance, Fresnel f, MicrofacetDistribution d) : base(BxDFType.Reflection | BxDFType.Glossy) { _spectrum = reflectance; _distribution = d; _fresnel = f; }
public DiskLight(Transformation objectToWorld, float radius = 1, SampledSpectrum spectrum = null) : base(objectToWorld, spectrum) { _radius = radius; _normal = ObjectToWorld.TransformNormal(new Vector3(0, -1, 0)).Normalized(); NSamples = (uint)Math.Max(1, _radius / 4f); }
public override SampledSpectrum Sample(Vector3 leaving, out Vector3 incoming) { var entering = CosTheta(ref leaving) > 0; float ei, et; if (entering) { ei = IndexOfRefractionIncident; et = IndexOfRefractionTransmitted; } else { et = IndexOfRefractionIncident; ei = IndexOfRefractionTransmitted; } var sinIncidentSquared = SinThetaSquared(ref leaving); var eta = ei / et; var sinTransmittedSquared = eta * eta * sinIncidentSquared; var cosTransmitted = (float)Math.Sqrt(1 - sinTransmittedSquared); if (entering) { cosTransmitted = -cosTransmitted; } var sinTOversinI = eta; incoming = new Vector3(sinTOversinI * -leaving.X, sinTOversinI * -leaving.Y, cosTransmitted); if (sinTransmittedSquared >= 1) { return(SampledSpectrum.Black()); } var f = _fresnel.Evaluate(CosTheta(ref leaving)); return((new SampledSpectrum(1) - f) * _s / AbsCosTheta(ref incoming) * (et * et) / (ei * ei)); }
/// <summary> /// Compute the fresnel reflectance for dielectric materials /// </summary> /// <param name="cosi">the angle between incoming ray and normal</param> /// <param name="cost">the angle between outgoing ray and normal's inverse</param> /// <param name="si">the index of refraction of the first medium</param> /// <param name="st">the index of refraction of the second medium</param> /// <returns>the reflectance</returns> public static SampledSpectrum DielectricFresnel(float cosi, float cost, SampledSpectrum si, SampledSpectrum st) { var parallel = ((st * cosi) - (si * cost)) / ((st * cosi) + (si * cost)); var perpendicular = ((si * cosi) - (st * cost)) / ((si * cosi) + (st * cost)); return(parallel * parallel + perpendicular * perpendicular); }
/// <summary> /// Choose an incoming direction on the view from a BxDF matching a type /// and returns its contribution /// </summary> /// <param name="leaving">the vector leaving the surface</param> /// <param name="incoming">the vector arriving at the surface, the function will set it</param> /// <param name="type">the type of scattering</param> /// <returns></returns> public SampledSpectrum Sample(Vector3 leaving, ref Vector3 incoming, BxDF.BxDFType type) { /* we randomly choose a BxDF that matches the type */ var matchingBxDFs = _bxdfs.Where(f => type.HasFlag(f.Type)).ToList(); // the list of bxdf matching the type if (matchingBxDFs.Count == 0) { return(SampledSpectrum.Black()); } // random selection over matching bxdfs var bxdf = matchingBxDFs.ElementAt(Math.Min((int)(StaticRandom.NextFloat() * matchingBxDFs.Count), matchingBxDFs.Count - 1)); var leavingLocal = WorldToLocal(ref leaving); Vector3 incomingLocal; // we sample the chosen bxdf var spectrum = bxdf.Sample(leavingLocal, out incomingLocal); // we transform the incoming ray returned by the sampling to world space incoming = LocalToWorld(ref incomingLocal); // is the reflection is not specular, we add contribution from other bxdfs of the same type if (!bxdf.Type.HasFlag(BxDF.BxDFType.Reflection)) { spectrum = _bxdfs.Where(b => type.HasFlag(b.Type)) .Aggregate(spectrum, (current, b) => current + b.F(incomingLocal, leavingLocal)); } return(spectrum); }
public SpecularTransmission(float indexOfRefractionIncident, float indexOfRefractionTransmitted, SampledSpectrum s = null) : base(BxDFType.Transmission | BxDFType.Specular) { _fresnel = new FresnelDielectric(indexOfRefractionIncident, indexOfRefractionTransmitted); _s = s ?? SampledSpectrum.Random(); IndexOfRefractionIncident = indexOfRefractionIncident; IndexOfRefractionTransmitted = indexOfRefractionTransmitted; }
public SampledSpectrum F(Vector3 incoming, Vector3 leaving, BxDF.BxDFType type) { var s = SampledSpectrum.Black(); var incomingLocal = WorldToLocal(ref incoming); var leavingLocal = WorldToLocal(ref leaving); return(_bxdfs.Where(bxdf => type.HasFlag(bxdf.Type)) .Aggregate(s, (current, bxdf) => current + bxdf.F(incomingLocal, leavingLocal))); }
public OrenNayar(SampledSpectrum spectrum, float sigma) : base(BxDFType.Reflection | BxDFType.Diffuse) { var sig = MathHelper.DegreesToRadians(sigma); var sigsqrd = sig * sig; _a = 1f - (sigsqrd / (2 * (sigsqrd + 0.33f))); _b = (0.45f * sigsqrd) / (sigsqrd + 0.09f); _spectrum = spectrum; }
public override void AddSample(Sample sample, SampledSpectrum spectrum) { var color = Colors[(int)sample.Y, (int)sample.X]; if (color != null) { color.AddSample(spectrum.ToRGB()); } }
public ClementiteMaterial(Vector3 ka, Vector3 kd, Vector3 ks, uint ns, float d, uint illum) { _ka = SampledSpectrum.FromRGB(new[] { ka.X, ka.Y, ka.Z }); _kd = SampledSpectrum.FromRGB(new[] { kd.X, kd.Y, kd.Z }); _ks = SampledSpectrum.FromRGB(new[] { ks.X, ks.Y, ks.Z }); _ns = ns; _illum = illum; _d = d; }
/// <summary> /// This function is used to parse a .poule file. /// </summary> private void ParsePoule(Scene scene, string filename) { string[] lines = File.ReadAllLines(filename); foreach (string str in lines) { if (_pointLightReg.Match(str).Success) { string[] array = str.Split(' '); scene.Lights.Add(new PointLight(Transformation.Translation( float.Parse(array[1], CultureInfo.InvariantCulture.NumberFormat), float.Parse(array[2], CultureInfo.InvariantCulture.NumberFormat), float.Parse(array[3], CultureInfo.InvariantCulture.NumberFormat)), SampledSpectrum.White())); } else if (_diskLightReg.Match(str).Success) { string[] array = str.Split(' '); scene.Lights.Add(new PointLight(Transformation.Translation( float.Parse(array[1], CultureInfo.InvariantCulture.NumberFormat), float.Parse(array[2], CultureInfo.InvariantCulture.NumberFormat), float.Parse(array[3], CultureInfo.InvariantCulture.NumberFormat)), SampledSpectrum.White())); } else if (_cameraReg.Match(str).Success) { string[] array = str.Split(' '); _camera = new SimpleCamera(_screen, Transformation.Compose( Transformation.Translation( Convert.ToInt32(array[1]), Convert.ToInt32(array[2]), Convert.ToInt32(array[3]) ), Transformation.RotateX(float.Parse(array[4], CultureInfo.InvariantCulture.NumberFormat)), Transformation.RotateY(float.Parse(array[5], CultureInfo.InvariantCulture.NumberFormat)), Transformation.RotateZ(float.Parse(array[6], CultureInfo.InvariantCulture.NumberFormat)) )); } else if (_objReg.Match(str).Success == true) { string[] array = str.Split(' '); try { string path = array[1].Replace(@"\\", @"\"); ParsingObj parser = new ParsingObj(path); parser.AddToScene(scene); } catch (Exception e) { FileName.Text = e.Message; } } } }
public AccumulatedSpectrum Mul(ref SampledSpectrum sp) { if (storeInRgb) { this.rgbAcc *= sp.ToRgb(); } else { this.spAcc *= sp; } return this; }
public override SampledSpectrum F(Vector3 incoming, Vector3 leaving) { var diffuse = _rd * (float)(28f / (23 * Math.PI)) * (new SampledSpectrum(1) - _rs) * (1f - (float)Math.Pow(1 - 0.5 * AbsCosTheta(ref incoming), 5)) * (1f - (float)Math.Pow(1 - 0.5 * AbsCosTheta(ref leaving), 5)); var half = (incoming + leaving).Normalized(); var specular = new SampledSpectrum(_distribution.D(ref half)) / (new SampledSpectrum(4 * AbsDot(ref incoming, ref leaving) * Math.Max(AbsCosTheta(ref incoming), AbsCosTheta(ref leaving))) * SchlickFresnel(Vector3.Dot(incoming, half))); return(diffuse + specular); }
public AccumulatedSpectrum Mul(ref RgbSpectrum rgb, SpectrumType t) { if (storeInRgb) { this.rgbAcc *= rgb; } else { this.spAcc *= new SampledSpectrum(ref rgb, t); } return this; }
public override SampledSpectrum Li(Scene scene, Ray ray, Renderer renderer, Sample sample, ref Intersection intersection) { var spectrum = SampledSpectrum.Black(); var bsdfAtPoint = intersection.GetBSDF(); var leaving = -ray.Direction; spectrum += SampleLights(scene, bsdfAtPoint, ref intersection, ref leaving); if (ray.Depth + 1 < MaxDepth) { spectrum += SpecularTransmit(ray, renderer, sample, bsdfAtPoint, ref intersection); spectrum += SpecularReflect(ray, renderer, sample, bsdfAtPoint, ref intersection); } return(spectrum); }
public SampledSpectrum SpecularTransmit(Ray ray, Renderer renderer, Sample sample, BSDF bsdf, ref Intersection i) { var leaving = -ray.Direction; var incoming = new Vector3(); var f = bsdf.Sample(leaving, ref incoming, BxDF.BxDFType.Transmission | BxDF.BxDFType.Specular); var angle = Math.Abs(Vector3.Dot(incoming.Normalized(), i.NormalVector)); if (f.IsBlack() || angle == 0f) { return(SampledSpectrum.Black()); } var reflectedRay = new Ray(incoming.Normalized(), i.Point, 0.1f, Ray.DefaultEndValue, ray.Depth + 1); var li = renderer.Li(sample, reflectedRay); return(f * li * angle); }
/// <summary> /// Compute radiance for a sample /// </summary> /// <param name="sample"></param> /// <param name="ray"></param> /// <returns></returns> public SampledSpectrum Li(Sample sample, Ray ray = null) { ray = ray ?? Camera.GenerateRay(sample); var intersection = new Intersection(); var spectrum = SampledSpectrum.Black(); if (Scene.TryToIntersect(ray, ref intersection)) { spectrum = Integrator.Li(Scene, ray, this, sample, ref intersection); } else { spectrum = Scene.Lights.Aggregate(spectrum, (current, light) => current + light.Le(ray)); } return(spectrum); }
/// <summary> /// </summary> /// <remarks>This function let us choose the incoming vector</remarks> /// <param name="leaving"></param> /// <param name="incoming"></param> /// <returns></returns> public override SampledSpectrum Sample(Vector3 leaving, out Vector3 incoming) { /* Since we are in the reflection system, rotating the vector by PI radians * around the normal consists of negating its x component and its y component */ incoming = new Vector3(-leaving.X, -leaving.Y, leaving.Z); var abscostheta = AbsCosTheta(ref incoming); var reflectedLight = SampledSpectrum.Black(); if (_fresnel != null) { var reflectedAmount = _fresnel.Evaluate(CosTheta(ref incoming)); reflectedLight = _spectrum * reflectedAmount / abscostheta; } else { reflectedLight = _spectrum * _reflectiveness / abscostheta; } return(reflectedLight); }
private void InitNewScene() { _scene = new Scene(); var screen = new raytracer.core.Screen(1024, 768); _film = new MyFilm(screen, NSamples); Camera camera = new SimpleCamera(screen, Transformation.Translation((float)PositionX.Value, (float)PositionY.Value, (float)PositionZ.Value) * Transformation.RotateX((float)(RotationX.Value % 360)) * Transformation.RotateY((float)(RotationY.Value % 360)) * Transformation.RotateZ((float)(RotationZ.Value % 360))); _renderer = new Renderer(_scene, new GridSampler(screen), camera, _film, new WhittedIntegrator()); _scene.Lights.Add(new PointLight(Transformation.Translation(100, 650, -500), SampledSpectrum.White() * 2000000)); _scene.Lights.Add(new PointLight(Transformation.Translation(0, 0, -1000), SampledSpectrum.Random() * 200000)); SimpleObjParser(_scene, _file); }
public TestMaterial(float?reflectiveness = null, SampledSpectrum spectrum = null) { _reflectiveness = reflectiveness ?? StaticRandom.NextFloat(); _spectrum = spectrum ?? SampledSpectrum.Random() * 0.3f; }
/// <summary> /// Create a light from a transformation /// </summary> /// <param name="objectToWorld">the light-to-world transformation</param> /// <param name="spectrum">the spectrum of the light</param> /// <param name="nsamples">the number of samples to take from the light</param> protected Light(Transformation objectToWorld = null, SampledSpectrum spectrum = null, uint nsamples = 1) { ObjectToWorld = objectToWorld ?? Transformation.Identity; Spectrum = spectrum ?? SampledSpectrum.White(); NSamples = Math.Max(1, nsamples); }
/// <summary> /// </summary> /// <remarks> /// This function returns nothing since it is nearly impossible to have /// a correct incoming vector (there is only a single incoming vector) /// </remarks> /// <param name="incoming"></param> /// <param name="leaving"></param> /// <returns></returns> public override SampledSpectrum F(Vector3 incoming, Vector3 leaving) { return(SampledSpectrum.Black()); }
/// <summary> /// Create a specular reflection model based on Snell's laws. /// </summary> /// <param name="fresnel">the fresnel properties of the material</param> /// <param name="spectrum">a scaling spectrum</param> public SpecularReflection(Fresnel fresnel = null, SampledSpectrum spectrum = null) : base(BxDFType.Reflection | BxDFType.Specular) { _spectrum = spectrum ?? new SampledSpectrum(1); _fresnel = fresnel; }
/// <summary> /// Creates a specular reflection model based on unrealistic properties /// </summary> /// <param name="reflectiveness">the reflectiveness (between 0 and 1000)</param> /// <param name="spectrum">a scaling spectrum</param> public SpecularReflection(float reflectiveness = 1, SampledSpectrum spectrum = null) : base(BxDFType.Reflection | BxDFType.Specular) { _spectrum = spectrum ?? new SampledSpectrum(1); _reflectiveness = MathHelper.Clamp(reflectiveness, 0, 1000); }
public LambertianReflection(SampledSpectrum spectrum) : base(BxDFType.Reflection | BxDFType.Diffuse) { _spectrum = spectrum ?? SampledSpectrum.Random(); }
/// <summary> /// Return the spectrum of light when ray does not hit anything. /// </summary> /// <param name="ray">the ray</param> /// <returns></returns> public virtual SampledSpectrum Le(Ray ray) { return(SampledSpectrum.Black()); }
protected AreaLight(Transformation objectToWorld = null, SampledSpectrum spectrum = null, uint nsamples = 1) : base(objectToWorld, spectrum, nsamples) { }
public GlassMaterial(float refractionIndex1, float refractionIndex2, SampledSpectrum spectrum = null) { _transmission = new SpecularTransmission(refractionIndex1, refractionIndex2, spectrum); }
/// <summary> /// Adds the result of the ray casting (a spectrum) for the ray generated /// by a sample /// <seealso cref="CoefficientSpectrum" /> /// <seealso cref="Sample" /> /// </summary> /// <param name="sample">the sample from which the ray was generated</param> /// <param name="spectrum">the result of the casting of the ray in the scene</param> public abstract void AddSample(Sample sample, SampledSpectrum spectrum);