tutorials:basic-spectral-light-modeling
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
tutorials:basic-spectral-light-modeling [2024/12/06 20:13] – extended, minor fixes MH | tutorials:basic-spectral-light-modeling [2025/06/04 14:08] (current) – MH | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Spectral Light Modelling ====== | ====== Spectral Light Modelling ====== | ||
- | |||
- | ===== General Introduction ===== | ||
- | |||
- | Light modelling generally involves three aspects: | ||
- | |||
- | * Global illumination model | ||
- | * Light sources | ||
- | * Local illumination model | ||
- | |||
- | {{ : | ||
- | |||
- | Whereas the Global illumination model handles the actual light computation, | ||
- | |||
- | In each aspect, computer graphics offers plenty of alternatives. | ||
- | |||
- | {{ : | ||
- | |||
- | Several of them are implemented in GroIMP as ready-to-use tools. | ||
- | |||
- | GroIMP integrates two two main **light model implementations**, | ||
- | |||
- | * Twilight, a CPU-based implementation | ||
- | * GPUFlux, a GPU-based implementation | ||
- | |||
- | Both implementing different global illumination model for rendering and for light computation. | ||
- | |||
- | {{ : | ||
- | |||
- | In the following, only light computation or light modelling will be discussed. | ||
- | |||
- | |||
- | Regarding light sources, GroIMP provides a complete set of possible implementations. They all implement the //Light// and // | ||
- | |||
- | {{ : | ||
- | |||
- | For the Local illumination model, which defines the optical properties of the scene objects such as values for absorption, transmission, | ||
- | |||
- | {{ : | ||
- | |||
- | GroIMP provides a set of standard shader implementations, | ||
- | |||
- | {{ : | ||
- | |||
- | |||
- | ===== Spectral light modelling ===== | ||
- | |||
These three core aspects of light simulation—global and local illumination models, and light sources—are the base for any light simulation. When it comes to spectral light simulations, | These three core aspects of light simulation—global and local illumination models, and light sources—are the base for any light simulation. When it comes to spectral light simulations, | ||
Line 53: | Line 7: | ||
{{ : | {{ : | ||
- | Spectral light simulations now deal not only with the pure calculation of light distributions but also include aspects of the principal characteristics | + | Spectral light simulations now deal not only with the pure calculation of light distributions |
{{ : | {{ : | ||
- | The main factor influencing | + | The main factor influencing light quality is the light' |
{{ : | {{ : | ||
Line 65: | Line 19: | ||
In GroIMP, the GPUFlux model allows us to simulate spectral light between 380 and 720 nm (default values). | In GroIMP, the GPUFlux model allows us to simulate spectral light between 380 and 720 nm (default values). | ||
- | Note: The implementation essentially allows setting individual limits for min and // | + | Note: The implementation essentially allows setting individual limits for min and // |
- | The spectral range // | + | The spectral range // |
{{ : | {{ : | ||
Line 73: | Line 27: | ||
Setting up the GPUFlux light model within GroIMP, or more accurately XL, follows the typical Java conventions of importing the required classes, and initializing and parameterizing the light model. | Setting up the GPUFlux light model within GroIMP, or more accurately XL, follows the typical Java conventions of importing the required classes, and initializing and parameterizing the light model. | ||
- | Note: The examples require | + | Note: The examples require |
<code java> | <code java> | ||
Line 88: | Line 42: | ||
const int RAYS = 10000000; //number of simulated light rays | const int RAYS = 10000000; //number of simulated light rays | ||
- | const int DEPTH = 10; //maxiaml | + | const int DEPTH = 10; //maximal |
const FluxLightModel LM = new FluxLightModel(RAYS, | const FluxLightModel LM = new FluxLightModel(RAYS, | ||
protected void calculateLight() { | protected void calculateLight() { | ||
- | LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | + | LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); |
LM.setSpectralBuckets(21); | LM.setSpectralBuckets(21); | ||
- | LM.setSpectralDomain(380, | + | LM.setSpectralDomain(380, |
+ | ... | ||
} | } | ||
</ | </ | ||
Line 111: | Line 66: | ||
LM.setCutoffPower(0.01); | LM.setCutoffPower(0.01); | ||
- | // disables the simulation of sensor | + | // enable or disables the simulation of sensors |
LM.setEnableSensors(true); | LM.setEnableSensors(true); | ||
- | // sets the random seed for the random number generator; | + | // sets the random seed for the random number generator; |
LM.setRandomseed(123456); | LM.setRandomseed(123456); | ||
// enable dispersion | // enable dispersion | ||
- | LM.setDispersion(ture); // default: false | + | LM.setDispersion(true); // default: false |
</ | </ | ||
- | After the light model is configured, it can be invoked by calling the // | + | After the light model has been configurated, it can be invoked by calling the // |
<code java> | <code java> | ||
Line 128: | Line 83: | ||
</ | </ | ||
- | To obtain the total amount of absorbed radiation of a node x, the // | + | To obtain the total amount of absorbed radiation of a node x, the // |
<code java> | <code java> | ||
+ | import de.grogra.gpuflux.scene.experiment.Measurement; | ||
+ | |||
Measurement spectrum = LM.getAbsorbedPowerMeasurement(x); | Measurement spectrum = LM.getAbsorbedPowerMeasurement(x); | ||
float absorbedPower = spectrum.integrate(); | float absorbedPower = spectrum.integrate(); | ||
</ | </ | ||
+ | |||
+ | Have in mind, the unit here is Watt. The output power of the light sources is set in Watt and the values for absorption, reflectance, | ||
By doing this within a rule, the light absorption can be obtained for all objects of the specified type, such as a //Box//, as in this example: | By doing this within a rule, the light absorption can be obtained for all objects of the specified type, such as a //Box//, as in this example: | ||
Line 150: | Line 109: | ||
<code java> | <code java> | ||
Measurement spectrum = LM.getAbsorbedPowerMeasurement(x); | Measurement spectrum = LM.getAbsorbedPowerMeasurement(x); | ||
- | // absorbed power for the first bucket: 380 -397nm | + | // absorbed power for the first bucket: 380 - 397 nm |
float ap380_397 = spectrum.data[0]; | float ap380_397 = spectrum.data[0]; | ||
Line 165: | Line 124: | ||
==== Light sources ==== | ==== Light sources ==== | ||
- | After the light model is set up, the next step is to define the spectral light sources. The GPUFlux light model works with all basic light nodes, such as // | + | After the light model has been set up, the next step is to define the spectral light sources. The GPUFlux light model works with all basic light nodes, such as // |
<code java> | <code java> | ||
Line 175: | Line 134: | ||
- | Note: The step size does not have to be equal, and values in between are linearly interpolated. The unit of the amplitudes | + | Note: Step sizes do not have to be equal, and values in between are linearly interpolated. The unit of the amplitude |
A spectrum, given by an array of wavelengths and corresponding amplitudes, is called a spectral curve, and in computer graphics, it defines a spectral power distribution. In GroIMP, a spectral curve can be defined using the // | A spectrum, given by an array of wavelengths and corresponding amplitudes, is called a spectral curve, and in computer graphics, it defines a spectral power distribution. In GroIMP, a spectral curve can be defined using the // | ||
<code java> | <code java> | ||
+ | import de.grogra.gpuflux.imp3d.spectral.SpectralCurve; | ||
+ | import de.grogra.gpuflux.imp3d.spectral.IrregularSpectralCurve; | ||
+ | |||
const float[] WAVELENGTHS = {380, 410, 420, 450, 465, 480, 490, 600, 620, 630, 640, 655, 660, 670, 690, 700, 720}; | const float[] WAVELENGTHS = {380, 410, 420, 450, 465, 480, 490, 600, 620, 630, 640, 655, 660, 670, 690, 700, 720}; | ||
- | const AMPLITUDES = {0.05, 0.1, 0.4, 0.63, 0.25, 0.15, 0.05, 0.01, 0.1, 0.3, 0.4, 0.85, 0.75, 0.95, 0.6, 0.25, 0.1}; | + | const float[] |
- | const ChannelSPD | + | const SpectralCurve |
</ | </ | ||
+ | |||
+ | **SPD** = **S**pectral **P**ower **D**istribution | ||
+ | |||
Besides user-defined spectral curves, GroIMP provides a set of spectral curves: | Besides user-defined spectral curves, GroIMP provides a set of spectral curves: | ||
Line 196: | Line 161: | ||
{{ : | {{ : | ||
- | + | Since these spectral curve classes all implement the same // | |
- | Since these spectral curve classes all implement the same // | + | |
<code java> | <code java> | ||
+ | import de.grogra.gpuflux.imp3d.spectral.SpectralCurve; | ||
+ | import de.grogra.gpuflux.imp3d.spectral.IrregularSpectralCurve; | ||
+ | import de.grogra.gpuflux.imp3d.shading.ChannelSPD; | ||
+ | |||
//user defined spectral curve, applied to an IrregularSpectralCurve | //user defined spectral curve, applied to an IrregularSpectralCurve | ||
float[] WAVELENGTHS = {380, 485, 490, 610, 615, 720}; | float[] WAVELENGTHS = {380, 485, 490, 610, 615, 720}; | ||
Line 211: | Line 179: | ||
ChannelSPD CONST_SPD = new ChannelSPD(new ConstantSpectralCurve(0.25)); | ChannelSPD CONST_SPD = new ChannelSPD(new ConstantSpectralCurve(0.25)); | ||
- | //a regular spectral curve will apply the given intensities | + | //a regular spectral curve will apply the given intensities |
ChannelSPD REG_SPD = new ChannelSPD(new | ChannelSPD REG_SPD = new ChannelSPD(new | ||
Line 217: | Line 185: | ||
ChannelSPD REG_SPD = new ChannelSPD(new CIENormSpectralCurve(Attributes.CIE_NORM_D55)); | ChannelSPD REG_SPD = new ChannelSPD(new CIENormSpectralCurve(Attributes.CIE_NORM_D55)); | ||
- | // a black body spectral curve with a temperature of 5000K | + | //a black body spectral curve with a temperature of 5000K |
ChannelSPD REG_SPD = new ChannelSPD(new BlackbodySpectralCurve(5000)); | ChannelSPD REG_SPD = new ChannelSPD(new BlackbodySpectralCurve(5000)); | ||
</ | </ | ||
Line 223: | Line 191: | ||
{{ : | {{ : | ||
- | To use the spectral curve as input for a light source, a // | + | To use the spectral curve as input for a light source, a // |
<code java> | <code java> | ||
- | const float[] WAVELENGTHS = {380,385,...}; | + | import de.grogra.gpuflux.imp3d.objects.SpectralLight; |
- | const float[] AMPLITUDES = {0.000967721, 0.000980455, ...}; | + | import de.grogra.gpuflux.imp3d.spectral.SpectralCurve; |
+ | import de.grogra.gpuflux.imp3d.spectral.IrregularSpectralCurve; | ||
+ | |||
+ | //user defined spectral curve, applied to an IrregularSpectralCurve | ||
+ | const float[] WAVELENGTHS = {380, 485, 490, 610, 615, 720}; | ||
+ | const float[] AMPLITUDES = {0,0,1,1,0,0}; | ||
+ | const SpectralCurve TEST_SPD = new IrregularSpectralCurve(WAVELENGTHS, | ||
module MyLamp extends LightNode() { | module MyLamp extends LightNode() { | ||
{ | { | ||
setLight( | setLight( | ||
- | new SpectralLight(new IrregularSpectralCurve(WAVELENGTHS, | + | new SpectralLight(TEST_SPD).( |
setPower(100), | setPower(100), | ||
setLight(new PointLight()) | setLight(new PointLight()) | ||
Line 239: | Line 214: | ||
} | } | ||
} | } | ||
+ | |||
+ | protected void init() [ | ||
+ | Axiom ==> MyLamp; | ||
+ | ] | ||
</ | </ | ||
+ | Note: // | ||
+ | |||
+ | Within the // | ||
+ | |||
+ | * at 1nm resolution [300, 780] | ||
+ | * A, D65 | ||
+ | * at 5nm resolution [300, 780] | ||
+ | * A, C, D50, D55, D65, D75 | ||
+ | * at 5nm resolution [380, 780] | ||
+ | * FL1-12, FL3_1-15, HP1-5 | ||
+ | |||
+ | For instance, to use the predefined CIE NORM D65 for typical sun light within a user defined light module, one could use the following code. | ||
+ | |||
+ | <code java> | ||
+ | import de.grogra.gpuflux.imp3d.spectral.CIENormSpectralCurve; | ||
+ | import de.grogra.gpuflux.imp3d.objects.SpectralLight; | ||
+ | |||
+ | //define a light module | ||
+ | module MyLamp extends LightNode { | ||
+ | { | ||
+ | setLight( | ||
+ | new SpectralLight( new CIENormSpectralCurve(Attributes.CIE_NORM_D65) ).( | ||
+ | setPower(100), | ||
+ | setLight(new PointLight()) | ||
+ | ) //end SpectralLight | ||
+ | ); //end setLight | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | Using the SPD, we define the light ' | ||
+ | |||
+ | In the above example, a // | ||
- | To complete the definition of a light source, besides the spectral power distribution, | + | This is especially helpful or necessary for any definition of artificial light sources, such as those found in greenhouses, |
- | The physical light distribution can be defined as a polar distribution diagram (also called polar curve) showing the luminous intensity values with increasing angles from two imaginary axes of the lamp which is placed in the centre. Red: 0–180◦ plane, blue 90–270◦ plane. On the right of the Figure | + | The physical light distribution can be defined as a polar distribution diagram (also called polar curve) showing the luminous intensity values with increasing angles from two imaginary axes of the lamp, which is placed in the centre. Red: 0–180◦ plane, blue 90–270◦ plane. On the right of the figure |
{{ : | {{ : | ||
Line 264: | Line 277: | ||
</ | </ | ||
- | The result of the light ray visualization, | + | The result of the light ray visualization, |
{{ : | {{ : | ||
- | To see a more realistic light pattern, the scene needs to be rendered using one of the light models. Below is a rendered image of the LampDemo.gsz, | + | To see a more realistic light pattern, the scene needs to be rendered using one of the light models. Below is a rendered image of the //LampDemo.gsz//, as it can be found in the GroIMP internal example gallery. |
{{ : | {{ : | ||
Line 275: | Line 288: | ||
Defining a PLD for a light source can be done in two ways: 1) ' | Defining a PLD for a light source can be done in two ways: 1) ' | ||
- | In any case, instead of one of the predefined light sources, such as // | + | In any case, instead of one of the predefined light sources, such as // |
Line 300: | Line 313: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | |||
+ | A PLD distribution is defined as two-dimensional array, where the values of each row represent the intensities in one direction, starting at 90 degree (above the light source) going down to 270 degree (right below the light source), covering 180 degree. The values given are equally distributed of the 180 degree, e.g., when only three values are given, the first will be associated with 90 degree, the second with zero and the third with 270 degree. The rows on the other hand are equally distributed around the virtual z-axis, around the light source. If only one row is given, this distribution defined within the first row, will be used equally around the whole light source. If two rows are given, the first one will be used at zero degree and the second one at 180 degree. The values in-between are interpolated. The intensities are given in ether in absolute values (in Watt) or in percent in the range or zero to one or zero to 100. They are normalized internally again. | ||
Line 306: | Line 322: | ||
After the definition of the global illumination model and the light sources, the last missing part required for proper spectral light modelling is the definition of the local illumination model. In computer graphics, the tools used are called Shaders. A shader defines the local optical properties of an object, namely the values for reflection, absorption, and transmission. The Phong illumination model, or Phong shader for short, allows us to define all required aspects. | After the definition of the global illumination model and the light sources, the last missing part required for proper spectral light modelling is the definition of the local illumination model. In computer graphics, the tools used are called Shaders. A shader defines the local optical properties of an object, namely the values for reflection, absorption, and transmission. The Phong illumination model, or Phong shader for short, allows us to define all required aspects. | ||
- | In the same way as the spectral curves are defined for the light sources, the spectrum for reflectance and transmission | + | In the same way as the spectral curves are defined for the light sources, the spectrum for reflectance and transmittance |
+ | |||
+ | Note: we employ the terms // | ||
- | Note: there is no check of plausibility implemented within the Phong shader. The user needs to make sure that the sum of reflectance | + | Note: there is no check of plausibility implemented within the Phong shader. The user needs to make sure that the sum of reflection |
A Phong shader can be defined as following: | A Phong shader can be defined as following: | ||
<code java> | <code java> | ||
- | float[] WAVELENGTHS = {380, 485, 490, 610, 615, 720}; | + | import de.grogra.gpuflux.imp3d.shading.ChannelSPD; |
- | float[] AMPLITUDES = {0, | + | import de.grogra.gpuflux.imp3d.spectral.IrregularSpectralCurve; |
- | ChannelSPD GREEN_SPD = new ChannelSPD(new IrregularSpectralCurve(WAVELENGTHS, | + | import de.grogra.gpuflux.imp3d.spectral.RGBSpectralCurve; |
+ | import de.grogra.gpuflux.imp3d.spectral.ConstantSpectralCurve; | ||
- | ChannelSPD RED_SPD | + | static float[] WAVELENGTHS |
- | ChannelSPD | + | static float[] AMPLITUDES = {0,0,1,1,0,0}; |
+ | static | ||
- | Phong myShader | + | static ChannelSPD RED_SPD |
- | myShader.setDiffuse(GREEN_SPD); | + | static ChannelSPD CONST_SPD = new ChannelSPD(new ConstantSpectralCurve(0.25)); |
- | myShader.setTrasnparency(RED_SPD); | + | |
+ | //shader definition as global variable | ||
+ | Phong myShader0 = new Phong(); | ||
+ | static { | ||
+ | myShader0.setDiffuse(GREEN_SPD); | ||
+ | myShader0.setTransparency(RED_SPD); | ||
+ | } | ||
- | //within a module that extends a Box | + | //and use of the global shader within a module that is interpreted as Box |
+ | module TestBox ==> { | ||
+ | } Box(0.001, | ||
+ | |||
+ | |||
+ | //or define the shader | ||
module TestBox extends Box(0.001, | module TestBox extends Box(0.001, | ||
| | ||
Line 343: | Line 373: | ||
} | } | ||
} | } | ||
- | |||
- | //as a module that is interpreted as Box | ||
- | module TestBox ==> { | ||
- | Phong myShader = new Phong(); | ||
- | } Box(0.001, | ||
</ | </ | ||
- | Within | + | Note: Do NOT mix common RGB shaders (like the //RGBAShader//) and spectral |
- | * on 1nm resolution [300, 780] | ||
- | * A, D65 | ||
- | * on 5nm resolution [300, 780] | ||
- | * A, C, D50, D55, D65, D75 | ||
- | * on 5nm resolution [380, 780] | ||
- | * FL1-12, FL3_1-15, HP1-5 | ||
- | For instance, to use the predefined CIE NORM D65 for typical sun light within a user defined light module, one could use the following code. | ||
- | |||
- | <code java> | ||
- | import de.grogra.imp3d.objects.Attributes; | ||
- | import de.grogra.gpuflux.imp3d.spectral.CIENormSpectralCurve; | ||
- | |||
- | //define a light module | ||
- | module MyLamp extends LightNode { | ||
- | { | ||
- | setLight( | ||
- | new SpectralLight( | ||
- | new CIENormSpectralCurve(Attributes.CIE_NORM_D65) | ||
- | ).( | ||
- | setPower(100), | ||
- | setLight( | ||
- | new SpotLight(DISTRIBUTION).( | ||
- | setVisualize(true), | ||
- | setNumberofrays(250), | ||
- | setRaylength(1)// | ||
- | ) | ||
- | ) | ||
- | ) //end SpectralLight | ||
- | ); //end setLight | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | |||
- | |||
- | Note: Do NOT mix common RGB shader like the // | ||
- | |||
- | |||
- | ==== Sensor nodes ==== | ||
- | |||
- | To monitor light distributions with a scene without interfering, | ||
- | |||
- | Note: The size of the sensor node directly correlates with the probability of got hit by a light ray. For a very small sphere the probability to got hit by a light ray is relatively low, so the number of light rays simulated by the light model needs to be much larger to get repayable results. Therefore, better not to use very small sensor nodes. | ||
- | |||
- | Note: The colour of the sensor node determines which wavelengths should be observed. The default value is white, what stands for monitor all colours. If, for instance, the sensor colour is set to red, only red spectra will be sensed. | ||
- | |||
- | Note: The output of a sensor node is normalized to absorbed radiance per square meter, independent of the actual size of the sensor. | ||
- | |||
- | Note: Sensor nodes can be enabled and disabled for the light model using the LM.setEnableSensors(true/ | ||
- | |||
- | <code java> | ||
- | // create a 5cm, white sensor node | ||
- | Axiom ==> SensorNode().(setRadius(0.05), | ||
- | |||
- | //check what the sensor node has sensed | ||
- | x: | ||
- | Measurement spectrum = lm.getSensedIrradianceMeasurement(x); | ||
- | float absorbedPower = spectrum.integrate(); | ||
- | ... | ||
- | } | ||
- | </ | ||
Line 439: | Line 403: | ||
</ | </ | ||
+ | GroIMP supports the inport of ' | ||
==== Example ==== | ==== Example ==== | ||
Line 469: | Line 433: | ||
println(" | println(" | ||
FluxLightModel GPU_LM = new FluxLightModel(RAYS, | FluxLightModel GPU_LM = new FluxLightModel(RAYS, | ||
- | GPU_LM.setSeed(12345); // to produce reproducible results | + | GPU_LM.setSeed(1234567890); // to produce reproducible results |
GPU_LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | GPU_LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | ||
GPU_LM.setSpectralDomain(300, | GPU_LM.setSpectralDomain(300, | ||
Line 477: | Line 441: | ||
</ | </ | ||
- | The model will run and directly when saved, creates an instance of the light model, set wanted parameters and run it. there will be no output (except the one form the light model itself, stating that it was executed and giving some statistics on the scene). | + | The model will run and directly when saved, creates an instance of the light model, set wanted parameters and run it. there will be no output (except the one form the light model itself, stating that it was executed and giving some statistics on the scene and further stating that no light sources could be found within |
If you already get errors here, your system most probably does not support spectral light modelling. | If you already get errors here, your system most probably does not support spectral light modelling. | ||
Line 547: | Line 511: | ||
println(" | println(" | ||
FluxLightModel GPU_LM = new FluxLightModel(RAYS, | FluxLightModel GPU_LM = new FluxLightModel(RAYS, | ||
- | GPU_LM.setSeed(12345); // to produce reproduceable results | + | GPU_LM.setSeed(1234567890); // to produce reproduceable results |
GPU_LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | GPU_LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | ||
GPU_LM.setSpectralDomain(300, | GPU_LM.setSpectralDomain(300, | ||
Line 645: | Line 609: | ||
println(" | println(" | ||
FluxLightModel GPU_LM = new FluxLightModel(RAYS, | FluxLightModel GPU_LM = new FluxLightModel(RAYS, | ||
- | GPU_LM.setSeed(12345); // to produce reproduceable results | + | GPU_LM.setSeed(1234567890); // to produce reproduceable results |
GPU_LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | GPU_LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | ||
GPU_LM.setSpectralDomain(300, | GPU_LM.setSpectralDomain(300, | ||
Line 765: | Line 729: | ||
println(" | println(" | ||
FluxLightModel GPU_LM = new FluxLightModel(RAYS, | FluxLightModel GPU_LM = new FluxLightModel(RAYS, | ||
- | GPU_LM.setSeed(12345); // to produce reproduceable results | + | GPU_LM.setSeed(1234567890); // to produce reproduceable results |
GPU_LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | GPU_LM.setMeasureMode(MeasureMode.FULL_SPECTRUM); | ||
GPU_LM.setSpectralDomain(300, | GPU_LM.setSpectralDomain(300, | ||
Line 776: | Line 740: | ||
x: | x: | ||
] | ] | ||
- | print(" | + | print(" |
//plot the absorption spectrum | //plot the absorption spectrum | ||
for(int i: | for(int i: | ||
- | absorbedChart.addRow().(set(1, | + | absorbedChart.addRow().(set(1, |
} | } | ||
} | } | ||
</ | </ | ||
+ | |||
+ | |||
+ | |||
+ | ==== Dispersion ==== | ||
+ | |||
+ | The GPUFlux light model also supports the simulation of dispersion effects – the phenomenon where light separates into its constituent colours due to variations in the reflective index with wavelengths. Different wavelengths of light refract (bend) at different angles when passing through a medium like glass, causing the colours to separate. Essentially, | ||
+ | |||
+ | As default the simulation of dispersion is turned off - to speed up calculations - but can be enabled in the preferences of the GPUFlux light model or within the code as following: | ||
+ | |||
+ | <code java> | ||
+ | FluxLightModel LM = new FluxLightModel(RAYS, | ||
+ | |||
+ | // enable dispersion | ||
+ | LM.setDispersion(true); | ||
+ | </ | ||
+ | |||
+ | |||
+ | When enabled and applied to a scene containing some ‘diamonds’ (imported OBJ objects), one can generate things like shown below (Henke and Buck-Sorlin 2018): | ||
+ | |||
+ | {{ : | ||
tutorials/basic-spectral-light-modeling.1733512436.txt.gz · Last modified: 2024/12/06 20:13 by MH