private void UpdateLightChart(LightSource light) { SpectralData data = light.SpectralPowerDistribution; Series series = LightSourceChart.Series[0]; series.Points.Clear(); for (int wavelength = data.LowestWavelength, i = 0; wavelength <= data.HighestWavelength; wavelength += data.StepSize, i++) { series.Points.Add(new DataPoint((float)wavelength, data.WaveData[i])); } }
public void RecalculateColors(LightSource lightSource, Observer observer, bool clipInvisible) { foreach (ModelNode modelNode in this.ModelGraph) { modelNode.RecalculateColors(lightSource, observer, clipInvisible); } }
public void RecalculateColors(LightSource lightSource, Observer observer, bool clipInvisible) { try { // Calculate RGB values this.MaterialRGB = Utilities.GetEquivalentRGB(this.Material); // Calculate the tristimulus values. this.FinalTristimulus = Utilities.CalculateTristimulusValues(lightSource, this.Material, observer, clipInvisible); this.FinalRGB = Utilities.CalculateRGBfromXYZ(FinalTristimulus); // Not sure why I'm having to do this, but for now sometimes the scene renders like a ghost, so make alpha 1. this.FinalRGB = new Vector4(FinalRGB.X, FinalRGB.Y, FinalRGB.Z, 1f); this.MaterialRGB = new Vector4(MaterialRGB.X, MaterialRGB.Y, MaterialRGB.Z, 1f); } catch (Exception e) { MessageBox.Show("Color calculations because " + e.Message); throw; } }
/// <summary> /// Read in all the light sources from the given file. /// </summary> /// <param name="fileName">Path to the data file.</param> protected void ReadInLights(string fileName) { XmlDocument lightSourcesXml = new XmlDocument(); lightSourcesXml.Load(fileName); foreach (XmlElement lightSourceXML in lightSourcesXml.GetElementsByTagName(XMLDataConstants.LightSource)) { LightSource lightSource = new LightSource(); lightSource.Initialize(lightSourceXML); this.LightSources.Add(lightSource); } }
/// <summary> /// Calculate the tristimulus values for the given combination of light source, material and observer. /// </summary> /// <returns>A float array of size 3 containing X, Y and Z in each cell respectively.</returns> public static Vector3 CalculateTristimulusValues(LightSource lightSource, Material material, Observer observer, bool clipInvisible = false) { // TODO: This may not be the most efficient of all approaches, make sure you change this to be more streamlined. // Normalize spectra. // List<SpectralData> spectraBank = new List<SpectralData>(); spectraBank.Add(lightSource.SpectralPowerDistribution); spectraBank.Add(material.ReflectanceDistribution); spectraBank.Add(observer.ResponseSpectra[0]); spectraBank.Add(observer.ResponseSpectra[1]); spectraBank.Add(observer.ResponseSpectra[2]); Utilities.NormalizeSpectra(spectraBank); // Calculate the normalizing constant for tristimulus integration // float K = Utilities.TristimulusNormalizingConstant(lightSource, observer); float summation; int stepSize = lightSource.SpectralPowerDistribution.StepSize; // The wave data we need is nested deep inside objects. So grab it into local arrays // for convenience of coding. // float[] lightSourceData, materialData, observerXData, observerYData, observerZData; if (clipInvisible) { // Find out what indexes correspond to wavelengths between 380 and 780 nm. // Since the data is normalized, calculating based on 1 source should be enough. int startIndex = (380 - lightSource.SpectralPowerDistribution.LowestWavelength) / lightSource.SpectralPowerDistribution.StepSize; int count = (780 - 380) / lightSource.SpectralPowerDistribution.StepSize + 1; // Sanity check if (startIndex < 0) { throw new ArgumentException("wavelength data provided started after 380 nm"); } lightSourceData = lightSource.SpectralPowerDistribution.WaveData.GetRange(startIndex, count).ToArray(); materialData = material.ReflectanceDistribution.WaveData.GetRange(startIndex, count).ToArray(); observerXData = observer.ResponseSpectra[0].WaveData.GetRange(startIndex, count).ToArray(); observerYData = observer.ResponseSpectra[1].WaveData.GetRange(startIndex, count).ToArray(); observerZData = observer.ResponseSpectra[2].WaveData.GetRange(startIndex, count).ToArray(); } else { lightSourceData = lightSource.SpectralPowerDistribution.WaveData.ToArray(); materialData = material.ReflectanceDistribution.WaveData.ToArray(); observerXData = observer.ResponseSpectra[0].WaveData.ToArray(); observerYData = observer.ResponseSpectra[1].WaveData.ToArray(); observerZData = observer.ResponseSpectra[2].WaveData.ToArray(); } // Calculate the L*M product array. This reduces the repeated multiplication operations that would otherwise be // required. // float[] lmProductArray = Utilities.ComputeLMProductArray(lightSourceData, materialData); Vector3 tristimulusValues = new Vector3(); // Calculate X // summation = Utilities.ComputeSummationTerm(lmProductArray, observerXData); tristimulusValues.X = K * summation * (float)stepSize; // Calculate Y // summation = Utilities.ComputeSummationTerm(lmProductArray, observerYData); tristimulusValues.Y = K * summation * (float)stepSize; // Calculate Z // summation = Utilities.ComputeSummationTerm(lmProductArray, observerZData); tristimulusValues.Z = K * summation * (float)stepSize; return tristimulusValues; }
/// <summary> /// Calculates the Tristimulus normalizing constant using the formula /// K = 100.0 / (total * stepSize) /// Where total is the sum of products of lightsource power and observers Y channel response /// </summary> /// <param name="lightSource">Light source</param> /// <param name="observer">The observer</param> /// <returns>The calculated tristimulus constant</returns> public static float TristimulusNormalizingConstant(LightSource lightSource, Observer observer) { int stepSize = lightSource.SpectralPowerDistribution.StepSize; int start = lightSource.SpectralPowerDistribution.LowestWavelength; int end = lightSource.SpectralPowerDistribution.HighestWavelength; int i, index; float[] observerYData = observer.ResponseSpectra[1].WaveData.ToArray(); float[] lightSourceData = lightSource.SpectralPowerDistribution.WaveData.ToArray(); float total = (float)0.0; for (i=start, index=0; i <= end; i += stepSize, index++) { total += lightSourceData[index] * observerYData[index]; } return (float)100.0 / (total * (float)stepSize); }
public static Vector4 GetEquivalentRGB(LightSource lightSource) { Vector3 lightXYZ = Utilities.CalculateTristimulusValues( lightSource, TheDataManager.GetMaterialByPartialName("White"), TheDataManager.GetObserverByPartialName("1964"), true); return Utilities.CalculateRGBfromXYZ(lightXYZ); }