public void RecalculateColors(LightSource lightSource, Observer observer, bool clipInvisible) { foreach (ModelNode modelNode in this.ModelGraph) { modelNode.RecalculateColors(lightSource, observer, clipInvisible); } }
private void UpdateObserverChart(Observer observer) { int channel = 0; foreach (SpectralData spectrum in observer.ResponseSpectra) { Series series = ObserverChart.Series[channel]; series.Points.Clear(); for (int wavelength = spectrum.LowestWavelength, i = 0; wavelength <= spectrum.HighestWavelength; wavelength += spectrum.StepSize, i++) { series.Points.Add(new DataPoint((float)wavelength, spectrum.WaveData[i])); } channel++; } }
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 observers from the given file. /// </summary> /// <param name="fileName">Path to the data file.</param> protected void ReadInObservers(string fileName) { XmlDocument observersXML = new XmlDocument(); observersXML.Load(fileName); foreach (XmlElement observerXML in observersXML.GetElementsByTagName(XMLDataConstants.Observer)) { Observer observer = new Observer(); observer.Initialize(observerXML); this.Observers.Add(observer); } }
/// <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); }