Table of Contents

In this tutorial we will see how to get started with a FluxModel in GroIMP.

Go here to see more about how the FluxModel is defined in GroIMP.

Light Model

First, we setup of the Flux Light Model:

import de.grogra.gpuflux.tracer.FluxLightModelTracer.MeasureMode;
import de.grogra.gpuflux.scene.experiment.Measurement;
 
const int RAYS = 10000000;
const int DEPTH = 10;
const FluxLightModel LM = new FluxLightModel(RAYS,
DEPTH);
 
protected void init () {
LM.setMeasureMode(MeasureMode.FULL_SPECTRUM);
LM.setSpectralBuckets(81);
LM.setSpectralDomain(380, 780);
}

This is:

  1. importing of the needed classes
  2. initializing the model with 10 million rays and a recursion depth of 10
  3. setting the parameters with 400nm divided into 80 buckets of 5nm.

Then, run the light model and determine the amount of sensed radiation or of absorbed power for an object-type.

public void run () [
{
LM.compute();
}
 
 
x:SensorNode ::> {
Measurement spectrum = LM.getSensedIrradianceMeasurement(x);
float absorbedPower = spectrum.integrate();
//...
} 
 
x:Box ::> {
Measurement spectrum = LM.getAbsorbedPowerMeasurement(x);
float absorbedPower = spectrum.integrate();
//...
}
]

This is:

  1. computing the model
  2. computing the integration of the whole absorbed spectrum for both
  3. sensor nodes
  4. box objects

Demonstration of the method for the determination of the amount of absorbed power per bucket or integration over a certain spectral range.

Measurement spectrum = LM.getAbsorbedPowerMeasurement(x); 
 
//absorbed power for the first bucket: 380-385 nm
float ap380_385 = spectrum.data[0]; 
 
//accumulate absorbed power for the first four 50 nm buckets
float b0 = 0, b1 = 0, b2 = 0, b3 = 0;
for (int i:(0:10)) {
b0 += spectrum.data[i];
b1 += spectrum.data[i + 10];
b2 += spectrum.data[i + 20];
b3 += spectrum.data[i + 30];
} 
 
//integrate the whole spectrum
float ap = spectrum.integrate();

This is:

  1. Getting the absorbed spectrum
  2. Storing the first bucket in a variable
  3. building four integrals, each of 50 nm (10 buckets of 5 nm) and sum up the first 40 buckets.
  4. calculating the integral over the whole spectrum.

Light Sources

Now let's set up a parameterisable light node – with explicit definition of physical light and spectral power distribution by simple arrays:

import de.grogra.imp3d.spectral.IrregularSpectralCurve; 
 
const double[][] DISTRIBUTION = {
{131.25, 131.67, 132.37, ...},
{131.36, 131.81, ...},
...
};
 
static const float[] WAVELENGTHS = {380,385, ...};
static const float[] AMPLITUDES = {0.000967,0.000980, ...};
 
module MyLamp extends LightNode() {
{
setLight(new SpectralLight(
new IrregularSpectralCurve(WAVELENGTHS, AMPLITUDES)).(
setPower(10), //[W]
setLight(new PhysicalLight(DISTRIBUTION))));
}
}

This is :

  1. importing the required classes
  2. defining of the physical light distribution
  3. defining of the spectral power distribution
  4. defining of a lamp using the specified parameters

The light distribution and spectral distribution (i.e. the DISTRIBUTION, WAVELENGTHS and AMPLITUDES arrays) can also be provided from .ies files.

See here for more information on the supported file formats.

Then, let's create a parameterizable light node – using file references for physical and spectral power distribution.

const LightDistributionRef DISTRIBUTION = light("
distribution1");
const SpectrumRef SPECTRUM = spectrum("equal");
 
module MyLamp1 extends LightNode {
{
setLight(new SpectralLight(new PhysicalLight(
DISTRIBUTION), SPECTRUM, 10)); // 10 W
}
}
 
module MyLamp2 extends LightNode {
{
setLight(
new SpectralLight().(
setPower(10), //[W]
setLight(new PhysicalLight(DISTRIBUTION)),
setSpectrum(SPECTRUM)));
}
}

This is:

  1. Defining a file reference. This file can be included or linked to a project
  2. Applying a concrete lamp to the reference by:
    1. using the constructor
    2. using the set-methods of the LightNode class

Illumination Model

Definition of a Phong shader by textures, by colours and by a user-defined spectral power distribution.

Phong myShader = new Phong();
ImageMap image = new ImageMap();
image.setImageAdapter(new FixedImageAdapter(image("leaf").toImageAdapter().getBufferedImage()));
myShader.setDiffuse(image);
 
Phong myShader = new Phong();
myShader.setDiffuse(new RGBColor(0,1,0));
//myShader.setSpecular(new Graytone(0.5));
//myShader.setShininess(new Graytone(0.5));
myShader.setDiffuseTransparency(new RGBColor(0.5,0,0));
//myShader.setAmbient(new Graytone(0.5));
//myShader.setEmissive(new Graytone(0.5));
 
ChannelSPD MySPD = new ChannelSPD(new IrregularSpectralCurve(
    new float[] {400,410, ....,740,750}, //WAVELENGTHS
    new float[] {0.1,0, .... ,0.4,0.25} //AMPLITUDES
));
Phong myShader = new Phong();
myShader.setDiffuse(MySPD);

This is:

  1. Setting an image as texture: Values for reflection depend on the colour of the texture at each pixel of the image.
  2. Setting specific properties: At this configuration green will be reflected to 100 % and red will be transmitted to 50 % for the whole surface of the object.
  3. A user-defined SPD is used to define the diffuse colour.