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 [2025/06/04 07:06] – MH | tutorials:basic-spectral-light-modeling [2025/06/04 14:08] (current) – MH | ||
---|---|---|---|
Line 86: | Line 86: | ||
<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(); | ||
Line 137: | Line 139: | ||
<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 |
</ | </ | ||
Line 155: | Line 160: | ||
{{ : | {{ : | ||
- | |||
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 177: | 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 183: | 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 199: | Line 214: | ||
} | } | ||
} | } | ||
+ | |||
+ | protected void init() [ | ||
+ | Axiom ==> MyLamp; | ||
+ | ] | ||
</ | </ | ||
- | **PLD** = **P**physical **L**ight **D**istribution | + | Note: // |
- | To complete | + | Within |
+ | |||
+ | * 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 | ||
+ | |||
+ | <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), //[W] | ||
+ | setLight(new PointLight()) | ||
+ | ) //end SpectralLight | ||
+ | ); //end setLight | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | Using the SPD, we define | ||
+ | |||
+ | In the above example, a // | ||
+ | |||
+ | 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 below, a 3D visualisation of the same light source is given. The colour of each point (gradient from black to bright red), as well as the distance to the light source, both indicate the power emitted by the light source in a particular direction per unit solid angle. | 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 below, a 3D visualisation of the same light source is given. The colour of each point (gradient from black to bright red), as well as the distance to the light source, both indicate the power emitted by the light source in a particular direction per unit solid angle. | ||
Line 229: | Line 281: | ||
{{ : | {{ : | ||
- | 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 236: | 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 261: | 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 276: | Line 331: | ||
<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 = new ChannelSPD(new RGBSpectralCurve(0.8, |
- | myShader.setDiffuse(GREEN_SPD); | + | static ChannelSPD CONST_SPD = new ChannelSPD(new ConstantSpectralCurve(0.25)); |
- | myShader.setTransparency(RED_SPD); | + | |
+ | //shader definition as global variable | ||
+ | Phong myShader0 | ||
+ | static { | ||
+ | myShader0.setDiffuse(GREEN_SPD); | ||
+ | | ||
+ | } | ||
+ | |||
+ | //and use of the global shader within a module that is interpreted as Box | ||
+ | module TestBox ==> { | ||
+ | } Box(0.001, | ||
- | //within a module that extends a Box | + | //or define the shader |
module TestBox extends Box(0.001, | module TestBox extends Box(0.001, | ||
| | ||
Line 306: | Line 373: | ||
} | } | ||
} | } | ||
- | |||
- | //as a module that is interpreted as Box | ||
- | module TestBox ==> { | ||
- | Phong myShader = new Phong(); | ||
- | } Box(0.001, | ||
</ | </ | ||
- | |||
- | 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.PhysicalLight; | ||
- | |||
- | //define a light module | ||
- | module MyLamp extends LightNode { | ||
- | { | ||
- | setLight( | ||
- | new SpectralLight( | ||
- | new CIENormSpectralCurve(Attributes.CIE_NORM_D65) | ||
- | ).( | ||
- | setPower(100), | ||
- | setLight( | ||
- | new PhysicalLight(DISTRIBUTION).( | ||
- | setVisualize(true), | ||
- | setNumberofrays(250), | ||
- | setRaylength(1)// | ||
- | ) | ||
- | ) | ||
- | ) //end SpectralLight | ||
- | ); //end setLight | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | |||
Note: Do NOT mix common RGB shaders (like the // | Note: Do NOT mix common RGB shaders (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 402: | Line 403: | ||
</ | </ | ||
+ | GroIMP supports the inport of ' | ||
==== Example ==== | ==== Example ==== | ||
Line 440: | 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. |
tutorials/basic-spectral-light-modeling.1749013607.txt.gz · Last modified: 2025/06/04 07:06 by MH