public override void PDF(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out double PDF) { PDF = 1; }
public override void Sample(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, out Vector3 SampleDirection, out LobeType SampledLobe) { SampleDirection = -ViewDirection; SampledLobe = LobeType.DiffuseTransmission; }
private Vector3 SampleLight(Shape Shape, Vector3 Hit, Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, Vector3 BSDFAttenuation) { //If this is not diffuse or there are no lights, no direct lighting calculation needs to be done if (SampledLobe != LobeType.DiffuseReflection || World.Lights.Count == 0) { return(Vector3.Zero); } //Pick a light World.PickLight(out Shape Light, out double LightPickPDF); Vector3 Emission = Light.Material.GetProperty("emission", UV).Color; Vector3 TotalDirectLighting = Vector3.Zero; //Sample BSDF if (BSDFAttenuation != Vector3.Zero) { //Visibility check World.Raycast(new Ray(Hit + SampleDirection * 0.001, SampleDirection), out Shape BSDFShape, out Vector3 BSDFHit, out Vector3 BSDFNormal, out Vector2 BSDFUV); if (BSDFShape == Light) { //Calculate light pdf for bsdf sample double LightPDF = Math.Pow((Hit - BSDFHit).Length(), 2) / (Vector3.Dot(BSDFNormal, Vector3.Normalize(Hit - BSDFHit)) * Light.Area()); //Calculate bsdf pdf for bsdf sample Shape.Material.PDF(ViewDirection, Normal, UV, SampleDirection, SampledLobe, out double ScatterPDF); //Weighted sum of the 2 sampling strategies for this sample TotalDirectLighting += BSDFAttenuation * Emission * Util.BalanceHeuristic(ScatterPDF, LightPDF) / ScatterPDF; } } //Sample light directly Vector3 LightSample = Light.Sample() - Hit; double Distance = LightSample.Length(); LightSample.Normalize(); //Visibility check World.Raycast(new Ray(Hit + LightSample * 0.001, LightSample), out Shape LightShape, out Vector3 LightHit, out Vector3 LightNormal, out Vector2 LightUV); if ((LightHit - Hit).Length() >= Distance - 0.001) { //Calculate light pdf for light sample, double LightPDF = Math.Pow(Distance, 2) / (Vector3.Dot(LightNormal, -LightSample) * Light.Area()); //Calculate bsdf pdf for light sample Shape.Material.Evaluate(ViewDirection, Normal, UV, LightSample, SampledLobe, out BSDFAttenuation); Shape.Material.PDF(ViewDirection, Normal, UV, LightSample, SampledLobe, out double ScatterPDF); //Weighted sum of the 2 sampling strategies for this sample if (BSDFAttenuation != Vector3.Zero) { TotalDirectLighting += BSDFAttenuation * Emission * Util.BalanceHeuristic(LightPDF, ScatterPDF) / LightPDF; } } return(TotalDirectLighting / LightPickPDF); }
public override void Evaluate(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out Vector3 Attenuation) { Attenuation = GetProperty("albedo", UV); }
public override void PDF(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out double PDF) { PDF = (Vector3.Dot(SampleDirection, Normal) / Math.PI); }
public abstract void PDF(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out double PDF);
public override void Sample(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, out Vector3 SampleDirection, out LobeType SampledLobe) { double RefractiveIndex = GetProperty("ior", UV); double Roughness = GetProperty("roughness", UV); //Reflection if (Util.Random.NextDouble() <= Util.FresnelReal(MathHelper.Clamp(Vector3.Dot(-ViewDirection, Normal), -1, 1), RefractiveIndex)) { SampledLobe = LobeType.SpecularReflection; SampleDirection = Vector3.Reflect(-ViewDirection, Normal); } else { SampledLobe = LobeType.SpecularTransmission; SampleDirection = Vector3.Refract(-ViewDirection, Normal, RefractiveIndex); } if (Roughness > 0) { SampleDirection = Util.SampleGGX(Util.Random.NextDouble(), Util.Random.NextDouble(), SampleDirection, Roughness); } }
public override void Evaluate(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out Vector3 Attenuation) { Vector3 Albedo = GetProperty("albedo", UV); double Metalness = GetProperty("metalness", UV); Vector3 F0 = Vector3.Lerp(new Vector3(0.04), Albedo, Metalness); double DiffuseSpecularRatio = 0.5 + (0.5 * Metalness); double CosTheta = Math.Max(Vector3.Dot(Normal, SampleDirection), 0); Vector3 Halfway = Vector3.Normalize(SampleDirection + ViewDirection); Vector3 Ks = Util.FresnelSchlick(Math.Max(Vector3.Dot(Halfway, ViewDirection), 0.0), F0); if (SampledLobe == LobeType.DiffuseReflection) { Vector3 Kd = Vector3.One - Ks; Kd *= 1.0 - Metalness; Vector3 Diffuse = Kd * Albedo / Math.PI; Attenuation = Diffuse * CosTheta / (1 - DiffuseSpecularRatio); } else { double Roughness = GetProperty("roughness", UV); double D = Util.GGXDistribution(Normal, Halfway, Roughness); double G = Util.GeometrySmith(Normal, ViewDirection, SampleDirection, Roughness); Vector3 SpecularNumerator = D * G * Ks; double SpecularDenominator = 4.0 * Math.Max(Vector3.Dot(Normal, ViewDirection), 0.0) * CosTheta + 0.001; Vector3 Specular = SpecularNumerator / SpecularDenominator; Attenuation = Specular * CosTheta / DiffuseSpecularRatio; } }
public override void Evaluate(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out Vector3 Attenuation) { throw new NotImplementedException(); }
public override void Evaluate(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out Vector3 Attenuation) { if (SampledLobe == LobeType.SpecularReflection) { Attenuation = Vector3.One; } else { Attenuation = GetProperty("albedo", UV); } }
public override void PDF(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out double PDF) { throw new NotImplementedException(); }
public override void Sample(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, out Vector3 SampleDirection, out LobeType SampledLobe) { throw new NotImplementedException(); }
public abstract void Evaluate(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out Vector3 Attenuation);
public override void Sample(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, out Vector3 SampleDirection, out LobeType SampledLobe) { double DiffuseSpecularRatio = 0.5 + (0.5 * GetProperty("metalness", UV)); if (Util.Random.NextDouble() > DiffuseSpecularRatio) { SampledLobe = LobeType.DiffuseReflection; Util.CreateCartesian(Normal, out Vector3 NT, out Vector3 NB); double R1 = Util.Random.NextDouble(); double R2 = Util.Random.NextDouble(); Vector3 Sample = Util.CosineSampleHemisphere(R1, R2); SampleDirection = new Vector3( Sample.X * NB.X + Sample.Y * Normal.X + Sample.Z * NT.X, Sample.X * NB.Y + Sample.Y * Normal.Y + Sample.Z * NT.Y, Sample.X * NB.Z + Sample.Y * Normal.Z + Sample.Z * NT.Z); SampleDirection.Normalize(); } //Glossy else { SampledLobe = LobeType.SpecularReflection; double Roughness = MathHelper.Clamp(GetProperty("roughness", UV), 0.001, 1); Vector3 ReflectionDirection = Vector3.Reflect(-ViewDirection, Normal); double R1 = Util.Random.NextDouble(); double R2 = Util.Random.NextDouble(); SampleDirection = Util.SampleGGX(R1, R2, ReflectionDirection, Roughness); } }
public override void Evaluate(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out Vector3 Attenuation) { double InverseSigmaSquared = 1.0 / Math.Pow(GetProperty("sigma", UV), 2); double NdotV = Vector3.Dot(Normal, ViewDirection); double NdotL = Vector3.Dot(Normal, SampleDirection); if (NdotV > 0 && NdotL > 0) { Vector3 Halfway = Vector3.Normalize(SampleDirection + ViewDirection); double NdotH = Vector3.Dot(Normal, Halfway); double VdotH = Math.Abs(Vector3.Dot(ViewDirection, Halfway)); if (Math.Abs(NdotH) < 0.99999 && VdotH > 0.00001) { double NdotHdivVdotH = NdotH / VdotH; NdotHdivVdotH = Math.Max(NdotHdivVdotH, 0.00001); double FactorView = 2 * Math.Abs(NdotHdivVdotH * NdotV); double FactorLight = 2 * Math.Abs(NdotHdivVdotH * NdotL); double SinNdotHSquared = 1 - NdotH * NdotH; double SinNdotHCubed = SinNdotHSquared * SinNdotHSquared; double CoTangentSquared = (NdotH * NdotH) / SinNdotHSquared; double D = Math.Exp(-CoTangentSquared * InverseSigmaSquared) * InverseSigmaSquared * (1.0 / Math.PI) / SinNdotHCubed; double G = Math.Min(1.0, Math.Min(FactorView, FactorLight)); double BSDFEval = 0.25 * (D * G) / NdotV; //BSDF attenuation * Albedo * Uniform hemisphere PDF Attenuation = new Vector3(BSDFEval, BSDFEval, BSDFEval) * GetProperty("albedo", UV).Color; } else { Attenuation = Vector3.Zero; } } else { Attenuation = Vector3.Zero; } }
public override void PDF(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out double PDF) { if (SampledLobe == LobeType.DiffuseReflection) { PDF = (Vector3.Dot(SampleDirection, Normal) / Math.PI); } else { Vector3 Halfway = Vector3.Normalize(SampleDirection + ViewDirection); double D = Util.GGXDistribution(Normal, Halfway, GetProperty("roughness", UV)); PDF = (D * Vector3.Dot(Normal, Halfway) / (4 * Vector3.Dot(Halfway, ViewDirection)) + 0.0001); } }
public override void PDF(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out double PDF) { PDF = (1.0 / (2.0 * Math.PI)); }
public override void Evaluate(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, Vector3 SampleDirection, LobeType SampledLobe, out Vector3 Attenuation) { Attenuation = GetProperty("albedo", UV).Color / Math.PI * Math.Max(Vector3.Dot(Normal, SampleDirection), 0); }
private Vector3 Trace(Ray Ray) { Medium CurrentMedium = null; LobeType SampledLobe = LobeType.SpecularReflection; Vector3 FinalColor = Vector3.Zero; Vector3 Throughput = Vector3.One; for (int Bounce = 0; Bounce < MaxBounces; Bounce++) { //Raycast to nearest geometry, if any World.Raycast(Ray, out Shape Shape, out Vector3 Hit, out Vector3 Normal, out Vector2 UV); //Return skybox color if nothing hit if (Shape == null) { if (SkyBox == null) { FinalColor += Throughput * Vector3.One; } else { FinalColor += Throughput * SkyBox.GetColorAtUV(new Vector2(1 - (1.0 + Math.Atan2(Ray.Direction.Z, Ray.Direction.X) / MathHelper.Pi) * 0.5, 1 - Math.Acos(Ray.Direction.Y) / MathHelper.Pi)); } break; } //Volumetrics, slightly borken bool Scattered = false; if (CurrentMedium != null) { double MaxDistance = (Hit - Ray.Origin).Length(); double Distance = CurrentMedium.SampleDistance(MaxDistance); Vector3 Transmission = CurrentMedium.Transmission(Distance); Throughput *= Transmission; if (Distance < MaxDistance) { Scattered = true; Ray.Direction = CurrentMedium.SampleDirection(Ray.Direction); Ray.Origin = Hit + Ray.Direction * 0.001; } } //If no scattering event happened, do normal path tracing if (!Scattered) { //Area lights if (Shape.Material.HasProperty("emission")) { //Don't add emission to diffuse term if NEE is on, we already sample it directly if (SampledLobe == LobeType.SpecularReflection || !NEE) { FinalColor += Throughput * Shape.Material.GetProperty("emission", UV).Color; } break; } Vector3 ViewDirection = Vector3.Normalize(Ray.Origin - Hit); //Sample BSDF Shape.Material.Sample(ViewDirection, Normal, UV, out Vector3 SampleDirection, out SampledLobe); Shape.Material.PDF(ViewDirection, Normal, UV, SampleDirection, SampledLobe, out double PDF); Shape.Material.Evaluate(ViewDirection, Normal, UV, SampleDirection, SampledLobe, out Vector3 Attenuation); //Sample direct lighting if (NEE) { FinalColor += Throughput * SampleLight(Shape, Hit, ViewDirection, Normal, UV, SampleDirection, SampledLobe, Attenuation); } //Accumulate BSDF attenuation Throughput *= Attenuation / PDF; //If we entered a medium, update current medium if (SampledLobe == LobeType.SpecularTransmission || SampledLobe == LobeType.DiffuseTransmission) { CurrentMedium = Shape.Material.Medium; } //Set new ray direction to sampled ray Ray.Origin = Hit + SampleDirection * 0.001; Ray.Direction = SampleDirection; } //Russian roulette if (Bounce >= MinBounces) { double Prob = Math.Max(Throughput.X, Math.Max(Throughput.Y, Throughput.Z)); if (Util.Random.NextDouble() > Prob) { break; } Throughput *= 1.0 / Prob; } } return(FinalColor); }
public override void Sample(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, out Vector3 SampleDirection, out LobeType SampledLobe) { SampledLobe = LobeType.DiffuseReflection; Util.CreateCartesian(Normal, out Vector3 NT, out Vector3 NB); double R1 = Util.Random.NextDouble(); double R2 = Util.Random.NextDouble(); Vector3 Sample = Util.CosineSampleHemisphere(R1, R2); SampleDirection = new Vector3( Sample.X * NB.X + Sample.Y * Normal.X + Sample.Z * NT.X, Sample.X * NB.Y + Sample.Y * Normal.Y + Sample.Z * NT.Y, Sample.X * NB.Z + Sample.Y * Normal.Z + Sample.Z * NT.Z); SampleDirection.Normalize(); }
public abstract void Sample(Vector3 ViewDirection, Vector3 Normal, Vector2 UV, out Vector3 SampleDirection, out LobeType SampledLobe);