commit 2d3d4b9b09b31b6a75327546737b39520f0bc1b8
parent b9bdd278372b200207ee9de1d61c1fceabcbea9f
Author: Eduardo Fontana Lazzari <edufonlaz@gmail.com>
Date: Mon, 6 Oct 2025 12:23:21 +0200
Start refactoring the realization function
Although functional, the realization function was originally written as
a single block of code, with little concern for separating different
levels of abstraction. This is far from ideal for two main reasons:
i. A Monte Carlo algorithm is composed of a set of elementary gestures
(sampling a position, sampling a wavelength, tracing a ray, etc.) that,
when chained together, return a weight used to estimate an observable.
These gestures are not specific to the MVREA algorithm. The star-phor
philosophy naturally gives rise to an architectural pattern where such
gestures are abstracted as functions internally exposed within
star-phor. This makes it easier for newcomers to get started, as the
separation between the Monte Carlo algorithm layer and the rest of the
code becomes clearer (one can directly use these abstractions when
coding a new algorithm or study/modify them as desired).
ii. The algorithm is a numerical implementation of an integral
formulation representing the same physical problem. The correspondence
between the two should be straightforward, reinforcing the need to
abstract parts of the numerical representation into separate functions.
As the core of the star project, the algorithm should consist of
readable, self-explanatory code so one can easily establish this
correspondence. Low-level details mixed into the main logic would harm
readability for certain audiences.
This commit rewrites part of the realization function following this
philosophy. Future work should continue both within the algorithm and in
the architecture of the newly created functions.
Diffstat:
3 files changed, 349 insertions(+), 184 deletions(-)
diff --git a/src/sphor_compute_mvrea.c b/src/sphor_compute_mvrea.c
@@ -34,257 +34,350 @@
#include <star/ssp.h>
#include <omp.h>
+enum ray_interface_interaction_type {
+ RAY_INTERFACE_INTERACTION_REFLECTION, /* 0 */
+ RAY_INTERFACE_INTERACTION_TRANSMISSION, /* 1 */
+ RAY_INTERFACE_INTERACTION_ABSORPTION, /* 2 */
+ RAY_INTERFACE_INTERACTION_NONE__
+};
+
/*******************************************************************************
* Helper functions
******************************************************************************/
static res_T
-compute_MVREA_realization
-(struct sphor* sphor,
- struct ssp_rng* rng,
- double* weight/* TODO make this a list in sphor, since we can have multiple
- sensors. Each sensor should have its own weight */)
+volume_compute_total_ka
+ (struct sphor* sphor,
+ struct interface interface,
+ size_t side_id,
+ double wavelength,
+ double* ka)
{
+ double sigma_a = 0;
double concentration = 0;
+ size_t prop_rad_count = 0;
+ size_t j = 0;
+ struct sphin_prop_rad* prop_rad = NULL;
+ struct sphin_scatterer* scatterer = NULL;
+ struct sphin_spectral_property* abs_cross_sec = NULL;
+ struct sphin_volume* volume = NULL;
+ res_T res = RES_OK;
+
+ ASSERT(NULL != sphor);
+ ASSERT(NULL != ka);
+
+ res = sphin_config_get_volume
+ (sphor->config, interface.volumes[side_id], &volume);
+ if (RES_OK != res){ goto error; }
+
+ /* Get ka corresponding to the current wavelength */
+ res = sphin_volume_get_prop_rad_count(volume, &prop_rad_count);
+ if (RES_OK != res){ goto error; }
+
+ *ka = 0.;
+
+ FOR_EACH(j, 0, prop_rad_count) {
+ res = sphin_volume_get_prop_rad(volume, j, &prop_rad);
+ if (RES_OK != res){ goto error; }
+
+ res = sphin_prop_rad_get_scatterer(prop_rad, &scatterer);
+ if (RES_OK != res){ goto error; }
+
+ res = sphin_scatterer_get_concentration(scatterer, &concentration);
+ if (RES_OK != res){ goto error; }
+
+ res = sphin_scatterer_get_abs_cross_sec(scatterer, &abs_cross_sec);
+ if (RES_OK != res){ goto error; }
+
+ res = sphin_spectral_property_interpolate_at_wavelength
+ (abs_cross_sec, wavelength, SPHIN_INTERPOLATION_LINEAR, &sigma_a);
+ if (RES_OK != res){ goto error; }
+
+ *ka += concentration * sigma_a;
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+sample_abs_free_path_exp
+ (struct sphor* sphor,
+ struct ssp_rng* rng,
+ struct interface interface,
+ size_t side_id,
+ double wavelength,
+ double* s)
+{
double ka = 0; /* Absorption coefficient of current volume */
- double reflectivity = 0; /* Surface reflectivity */
- double response_function = 0;
- double sigma_a = 0;
- double wavelength = 0;
- double normal[3] = {0}; /* Geometry normal */
- double dir[3] = {0}; /* Current direction in path sampling */
- double pos[3] = {0}; /* Current position in path sampling */
- double sample[3] = {0};
- double s = 0; /* Random number */
+ res_T res = RES_OK;
+
+ ASSERT(NULL != sphor);
+ ASSERT(NULL != s);
+
+ /* Get the absorption coefficient of the current volume to compute an
+ * absorption free length. If the intersected interface does not correspond
+ * to any volume in the config, the absorption coefficient is supposed to be
+ * zero and the absorption free length is set to FLT_MAX */
+ if (INVALID_ID != interface.volumes[side_id]) {
+ res = volume_compute_total_ka(sphor, interface, side_id, wavelength, &ka);
+ if (RES_OK != res){ goto error; }
+ /* Sample free path length according to volume absorption coefficent */
+ *s = ssp_ran_exp(rng, ka);}
+ else {
+ *s = FLT_MAX;
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+interface_sample_ray_interaction_type
+ (struct sphor* sphor,
+ struct ssp_rng* rng,
+ struct interface* interface,
+ enum sphin_side side_id,
+ enum ray_interface_interaction_type* interaction_type)
+{
enum sphin_brdf_type brdf_type = SPHIN_BRDF_NONE__;
- enum sphin_side side_id = SPHIN_SIDE_NONE__;
+ double reflectivity = 0;
+ double s = 0; /* random number */
+ struct sphin_surface* surface = NULL;
+ struct sphin_brdf* brdf = NULL;
+ size_t i = 0;
+ res_T res = RES_OK;
+
+ ASSERT(NULL != sphor);
+ ASSERT(NULL != interface);
+ ASSERT(NULL != interaction_type);
+
+ FOR_EACH(i, 0, interface->surface_count[(size_t)side_id]) {
+ res = sphin_config_get_surface
+ (sphor->config, interface->surfaces[(size_t)side_id][i], &surface);
+ if (RES_OK != res){ goto error; }
+ res = sphin_surface_get_brdf(surface, &brdf);
+ if (RES_OK != res){ goto error; }
+ res = sphin_brdf_get_type(brdf, &brdf_type);
+ if (RES_OK != res){ goto error; }
+ if (NULL != brdf){ break; }
+ }
+ /* If the interface side does not have a BRDF (i.e., it defines only a
+ * sphin_volume or a sphin_surface without a BRDF), the photon
+ * crosses the interface the path continues */
+
+ if((NULL == brdf) || (interface->surface_count[side_id] == 0)){
+ *interaction_type = RAY_INTERFACE_INTERACTION_TRANSMISSION;
+ }
+ /* If the interface side is a sphin_surface with a BRDF declared,
+ * verify if a reflection takes place based on the reflectivity of the
+ * surface */
+ else{
+ switch (brdf_type) {
+ case SPHIN_BRDF_LAMBERT:
+ res = sphin_brdf_lambertian_get_reflectivity(brdf, &reflectivity);
+ if (RES_OK != res){ goto error; }
+ break;
+ case SPHIN_BRDF_SPECULAR:
+ res = sphin_brdf_specular_get_reflectivity(brdf, &reflectivity);
+ if (RES_OK != res){ goto error; }
+ break;
+ case SPHIN_BRDF_NONE__:
+ res = RES_BAD_ARG;
+ goto error;
+ default:
+ FATAL("Unreachable code\n");
+ break;
+ }
+ /* Test if the photon was absorbed or reflected */
+ s = ssp_rng_canonical(rng);
+ if (s < reflectivity) {
+ *interaction_type = RAY_INTERFACE_INTERACTION_REFLECTION;
+ }
+ else { *interaction_type = RAY_INTERFACE_INTERACTION_ABSORPTION; }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+trace_ray
+ (struct sphor* sphor,
+ double pos[3],
+ double dir[3],
+ struct interface* interface,
+ struct s3d_primitive* prim_org,
+ enum sphin_side* side_id,
+ struct s3d_hit *out_hit)
+{
/* Position and direction using when calling s3d functions */
float r[3] = {0}; /* Position */
float w[3] = {0}; /* Direction */
/* Allowed range for rays during path sampling */
float range[2] = {0.f, FLT_MAX};
- float st[2] = {0}; /* Parametric coordinates of a point in a s3d_primitive */
- int i = 0; /* Iterator */
- size_t j = 0;
+ struct s3d_hit hit = S3D_HIT_NULL;
size_t triangle_id;
- size_t scn_prim_id;
- size_t prop_rad_count;
+ res_T res = RES_OK;
+
+ f3_set_d3(r, pos);
+ f3_set_d3(w, dir);
+ res = s3d_scene_view_trace_ray
+ (sphor->scene_view, r, w, range, prim_org, &hit);
+ if (RES_OK != res){ goto error; }
+
+ if (S3D_HIT_NONE(&hit)) {
+ goto exit;
+ }
+
+ /* TODO: separated function */
+ /* Retrieve the intercepted triangle and the corresponding interface in the
+ * sphor structure */
+ triangle_id = hit.prim.prim_id;
+ *interface = darray_interface_data_get(&sphor->interfaces)[triangle_id];
+ /* Update current primitive */
+ *prim_org = hit.prim;
+ /* Retrieve the side of the intercepted interface corresponding to the
+ * income direction of the hit */
+ res = interface_get_side_id(dir, &hit, side_id);
+ if (RES_OK != res){ goto error; }
+
+exit:
+ *out_hit = hit;
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+compute_MVREA_realization
+ (struct sphor* sphor,
+ struct ssp_rng* rng,
+ double* weight/* TODO make this a list in sphor, since we can have multiple
+ sensors. Each sensor should have its own weight */)
+{
+ double dir[3] = {0}; /* Current direction in path sampling */
+ double pos[3] = {0}; /* Current position in path sampling */
+ double response_function = 0;
+ double s = 0; /* Random number */
+ double sample[3] = {0};
+ double wavelength = 0;
+ enum ray_interface_interaction_type ray_interface_interaction_type =
+ RAY_INTERFACE_INTERACTION_NONE__;
+ enum sphin_side side_id = SPHIN_SIDE_NONE__;
struct interface interface = INTERFACE_NULL;
- struct s3d_attrib attrib;
struct s3d_hit hit = S3D_HIT_NULL;
struct s3d_primitive prim = S3D_PRIMITIVE_NULL;
- struct s3d_primitive src_prim = S3D_PRIMITIVE_NULL;
+ struct s3d_attrib attrib;
struct source_view* source_view = NULL;
struct sphin_brdf* brdf = NULL;
- struct sphin_prop_rad* prop_rad = NULL;
- struct sphin_scatterer* scatterer = NULL;
struct sphin_sensor_volume* sensor_volume = NULL;
- struct sphin_source_surface* source = NULL;
- struct sphin_spectral_property* abs_cross_sec = NULL;
- struct sphin_surface* surface = NULL;
struct sphin_volume* volume = NULL;
- struct sphin_source_surface_flux_density flux_density
- = SPHIN_SOURCE_SURFACE_FLUX_DENSITY_NULL;
res_T res = RES_OK;
ASSERT(NULL != sphor);
ASSERT(NULL != rng);
/* Sample a random position from a source in the whole scene */
- res = sample_source_position(sphor, rng, &source_view, &src_prim, st);
- if (RES_OK != res){ goto error; }
-
- scn_prim_id = darray_size_t_data_get(&source_view->src2scn)[src_prim.prim_id];
-
- res = s3d_scene_view_get_primitive
- (sphor->scene_view, (unsigned)scn_prim_id, &prim);
- if (RES_OK != res){ goto error; }
-
- res = s3d_primitive_get_attrib (&prim, S3D_POSITION, st, &attrib);
+ res = sample_source_position(sphor, rng, &source_view, &prim, pos);
if (RES_OK != res){ goto error; }
- d3_set_f3(pos, attrib.value);
-
- res = sphin_config_get_surface
- (sphor->config, source_view->sphin_id, &surface);
- if (RES_OK != res){ goto error; }
- res = sphin_surface_get_source(surface, &source);
- if (RES_OK != res){ goto error; }
- if (NULL == source){ res = RES_BAD_ARG; goto error; }
-
- /* Retrieve geometry normal of the sampled primitive */
- res = s3d_primitive_get_attrib (&src_prim, S3D_GEOMETRY_NORMAL, st, &attrib);
+ /* Sample a direction according to the source direction distribution */
+ res = source_surface_sample_direction(sphor, rng, source_view, &prim, dir);
if (RES_OK != res){ goto error; }
- d3_normalize(normal, d3_minus(normal, d3_set_f3(normal, attrib.value)));
/* Sample a wavelength according to the source emission spectrum */
- res = sphin_source_surface_get_flux_density(source, &flux_density);
- if (RES_OK != res){ goto error; }
-
- if (NULL != flux_density.emission_spectrum) {
- wavelength = ssp_ranst_piecewise_linear_get
- (source_view->emission_spectrum_pdf, rng);
- }
-
- /* Sample a direction according to the source direction distribution */
- res = source_surface_sample_direction(source, rng, &src_prim, dir);
+ res = source_sample_wavelength(sphor, rng, source_view, &wavelength);
if (RES_OK != res){ goto error; }
/* While no absorption takes place and an interface is found */
for(;;) {
/* Trace a ray in the scene from the sampled primitive in the sampled
* direction and retrive the hit distance */
- f3_set_d3(r, pos);
- f3_set_d3(w, dir);
- res = s3d_scene_view_trace_ray
- (sphor->scene_view, r, w, range, &prim, &hit);
+ res = trace_ray(sphor, pos, dir, &interface, &prim, &side_id, &hit);
if (RES_OK != res){ goto error; }
/* If there is no intersection in the sampled direction from the sampled
* position, the photon is lost and it counts zero in the weight. */
- if (S3D_HIT_NONE(&hit)) {
- *weight = 0;
- break;
- }
-
- /* Retrieve the intercepted triangle and the corresponding interface in the
- * sphor structure */
- triangle_id = hit.prim.prim_id;
- interface = darray_interface_data_get(&sphor->interfaces)[triangle_id];
-
- /* Retrieve the position of the hit and set the new position */
- res = s3d_primitive_get_attrib
- (&hit.prim, S3D_POSITION, st, &attrib);
- if (RES_OK != res){ goto error; }
- d3_set_f3(pos, attrib.value);
- /* Update current primitive */
- prim = hit.prim;
+ if (S3D_HIT_NONE(&hit)) { *weight = 0; break; }
- /* Retrieve the side of the intercepted interface corresponding to the
- * income direction of the hit */
- res = interface_get_side_id(dir, &hit, &side_id);
+ /* Sample the free path length to absorption from an exponential
+ * distribution with rate parameter ka */
+ res = sample_abs_free_path_exp
+ (sphor, rng, interface, side_id, wavelength, &s);
if (RES_OK != res){ goto error; }
- /* Get the absorption coefficient of the current volume to compute an
- * absorption free length. If the intersected interface does not correspond
- * to any volume in the config, the absorption coefficient is supposed to be
- * zero and the absorption free length is set to FLT_MAX */
- if (INVALID_ID != interface.volumes[side_id]) {
- /* Retrieve the volume we are currently in */
- res = sphin_config_get_volume
- (sphor->config, interface.volumes[side_id], &volume);
- if (RES_OK != res){ goto error; }
-
- /* Get ka corresponding to the current wavelength */
- res = sphin_volume_get_prop_rad_count(volume, &prop_rad_count);
- if (RES_OK != res){ goto error; }
-
- ka = 0.;
-
- FOR_EACH(j, 0, prop_rad_count) {
- res = sphin_volume_get_prop_rad(volume, j, &prop_rad);
- if (RES_OK != res){ goto error; }
-
- res = sphin_prop_rad_get_scatterer(prop_rad, &scatterer);
- if (RES_OK != res){ goto error; }
-
- res = sphin_scatterer_get_concentration(scatterer, &concentration);
- if (RES_OK != res){ goto error; }
-
- res = sphin_scatterer_get_abs_cross_sec(scatterer, &abs_cross_sec);
- if (RES_OK != res){ goto error; }
-
- res = sphin_spectral_property_interpolate_at_wavelength
- (abs_cross_sec, wavelength, SPHIN_INTERPOLATION_LINEAR, &sigma_a);
- if (RES_OK != res){ goto error; }
-
- ka += concentration * sigma_a;
- }
-
- /* Sample free path length according to volume absorption coefficent */
- s = ssp_ran_exp(rng, ka);}
- else {
- s = FLT_MAX;
- }
-
/* If the distance between the ray origin and the intersection is bigger
* than the absorption free path length, an absorption takes place (check
* if the volume is a sensor and return the weight accordingly) */
if (s < hit.distance) {
+ res = sphin_config_get_volume
+ (sphor->config, interface.volumes[side_id], &volume);
+ if (RES_OK != res){ goto error; }
/* Check if the volume is a sensor */
res = sphin_volume_get_sensor(volume, &sensor_volume);
+ if (RES_OK != res){ goto error; }
+ /* TODO Increment the weight of each chemical species in the volume by
+ * ( ka_i / ka_tot ) response_function */
+
/* If the volume is a sensor, compute the weight using the response
* function */
if (NULL != sensor_volume) {
res = sphin_sensor_volume_get_response_function
(sensor_volume, &response_function);
if (RES_OK != res){ goto error; }
- ASSERT(response_function == 1);
*weight = response_function;
}
/* If the volume is not a sensor, the absorbed photon does not count in
* the weight */
- else {
- *weight = 0;
- }
+ else{ *weight = 0; }
break;
}
/* Else, the distance between the ray origin and the intersection is smaller
* than the absorption free path length. The photon intersects a primitive
- * in the scene view. */
-
- /* Use sphin to retrieve the properties of the intersected surface */
- FOR_EACH(i, 0, interface.surface_count[side_id]) {
- res = sphin_config_get_surface
- (sphor->config, interface.surfaces[side_id][i], &surface);
- if (RES_OK != res){ goto error; }
- res = sphin_surface_get_brdf(surface, &brdf);
- if (RES_OK != res){ goto error; }
- if (NULL != brdf){ break; }
- }
-
- /* If the interface side is a sphin_surface with a BRDF declared,
- * verify if a reflection takes place based on the reflectivity of the
- * surface */
- if((NULL != brdf) & (interface.surface_count[side_id] > 0)){
- res = sphin_brdf_get_type(brdf, &brdf_type);
- if (RES_OK != res){ goto error; }
- switch (brdf_type) {
- case SPHIN_BRDF_LAMBERT:
- res = sphin_brdf_lambertian_get_reflectivity(brdf, &reflectivity);
- if (RES_OK != res){ goto error; }
- break;
- case SPHIN_BRDF_SPECULAR:
- res = sphin_brdf_specular_get_reflectivity(brdf, &reflectivity);
- if (RES_OK != res){ goto error; }
- break;
- case SPHIN_BRDF_NONE__:
- res = RES_BAD_ARG;
- goto error;
- default:
- FATAL("Unreachable code\n");
- break;
- }
+ * in the scene view. Sample the type of interaction that the photon has
+ * with the interface */
+ res = interface_sample_ray_interaction_type
+ (sphor, rng, &interface, side_id, &ray_interface_interaction_type);
+ if (RES_OK != res){ goto error; }
- /* Test if the photon was absorbed or reflected */
- s = ssp_rng_canonical(rng);
+ int stop = 0;
+ switch (ray_interface_interaction_type) {
/* An absorption took place, the weight is zero and the path stops */
- if (s > reflectivity) {
+ case RAY_INTERFACE_INTERACTION_ABSORPTION:
*weight = 0;
+ stop = 1;
break;
- }
-
/* Else, if a reflection takes place, sample a new direction according to
* the photon arriving direction, geometry normak and surface brdf
* properties */
- res = ran_brdf_reflection_direction(brdf, rng, &hit.prim, dir, sample);
- if (RES_OK != res){ goto error; }
- d3_set(dir, sample);
+ case RAY_INTERFACE_INTERACTION_REFLECTION:
+ res = ran_brdf_reflection_direction(brdf, rng, &hit.prim, dir, sample);
+ if (RES_OK != res){ goto error; }
+ d3_set(dir, sample);
+ break;
+ /* If the ray traverses the interface, it simply continue in the same
+ * direction as before */
+ case RAY_INTERFACE_INTERACTION_TRANSMISSION:
+ break;
+ /* Handle the possible exceptions */
+ case RAY_INTERFACE_INTERACTION_NONE__:
+ res = RES_BAD_ARG;
+ goto error;
+ default:
+ FATAL("Unreachable code\n");
+ break;
}
+ if (stop) { break; }
- /* If the interface side does not have a BRDF (i.e., it defines only a
- * sphin_volume or a sphin_surface without a BRDF), the photon
- * crosses the interface the path continues */
+ /* The hit position is the new position in path tracing */
+ res = s3d_primitive_get_attrib (&hit.prim, S3D_POSITION, hit.uv, &attrib);
+ if (RES_OK != res){ goto error; }
+ d3_set_f3(pos, attrib.value);
}
exit:
return res;
diff --git a/src/sphor_ran_source.c b/src/sphor_ran_source.c
@@ -41,12 +41,15 @@
******************************************************************************/
res_T
source_surface_sample_direction
- (struct sphin_source_surface* source,
+ (struct sphor* sphor,
struct ssp_rng* rng,
+ struct source_view* source_view,
struct s3d_primitive* prim,
double dir[3])
{
struct s3d_attrib attrib;
+ struct sphin_source_surface* source = NULL;
+ struct sphin_surface* surface = NULL;
struct sphin_source_surface_direction_distribution src_dir_dist
= SPHIN_SOURCE_SURFACE_DIRECTION_DISTRIBUTION_NULL;
double normal[3] = {0};
@@ -54,6 +57,14 @@ source_surface_sample_direction
float st[2] = {0};
res_T res = RES_OK;
+ res = sphin_config_get_surface
+ (sphor->config, source_view->sphin_id, &surface);
+ if (RES_OK != res){ goto error; }
+
+ res = sphin_surface_get_source(surface, &source);
+ if (RES_OK != res){ goto error; }
+ if (NULL == source){ res = RES_BAD_ARG; goto error; }
+
/* Sample a direction according to the source direction distribution */
res = sphin_source_surface_get_direction_distribution(source, &src_dir_dist);
if (RES_OK != res){ goto error; }
@@ -110,10 +121,14 @@ sample_source_position
(struct sphor* sphor,
struct ssp_rng* rng,
struct source_view** source,
- struct s3d_primitive* primitive,
- float st[2])
+ struct s3d_primitive* scn_primitive,
+ double pos[3])
{
+ float st[2] = {0};
+ size_t scn_prim_id;
struct source_view* source_to_sample = NULL;
+ struct s3d_primitive src_prim = S3D_PRIMITIVE_NULL;
+ struct s3d_attrib attrib;
res_T res = RES_OK;
ASSERT(NULL != sphor);
@@ -122,12 +137,61 @@ sample_source_position
res = sample_source_view(sphor, rng, &source_to_sample);
if (RES_OK != res) { goto error; }
- res = sample_surface_position(sphor, rng, source_to_sample->view, primitive, st);
+ res = sample_surface_position
+ (sphor, rng, source_to_sample->view, &src_prim, st);
if (RES_OK != res) { goto error; }
+ res = s3d_primitive_get_attrib(&src_prim, S3D_POSITION, st, &attrib);
+ if (RES_OK != res){ goto error; }
+ d3_set_f3(pos, attrib.value);
+
+ scn_prim_id = darray_size_t_data_get
+ (&source_to_sample->src2scn)[src_prim.prim_id];
+ res = s3d_scene_view_get_primitive
+ (sphor->scene_view, (unsigned)scn_prim_id, scn_primitive);
+ if (RES_OK != res){ goto error; }
+
*source = source_to_sample;
exit:
return res;
error:
goto exit;
}
+
+res_T
+source_sample_wavelength
+ (struct sphor* sphor,
+ struct ssp_rng* rng,
+ struct source_view* source_view,
+ double* wavelength)
+{
+ struct sphin_surface* surface = NULL;
+ struct sphin_source_surface* source = NULL;
+ struct sphin_source_surface_flux_density flux_density
+ = SPHIN_SOURCE_SURFACE_FLUX_DENSITY_NULL;
+ res_T res = RES_OK;
+
+ ASSERT(NULL != sphor);
+ ASSERT(NULL != rng);
+ ASSERT(NULL != source_view);
+
+ res = sphin_config_get_surface
+ (sphor->config, source_view->sphin_id, &surface);
+ if (RES_OK != res){ goto error; }
+
+ res = sphin_surface_get_source(surface, &source);
+ if (RES_OK != res){ goto error; }
+ if (NULL == source){ res = RES_BAD_ARG; goto error; }
+
+ res = sphin_source_surface_get_flux_density(source, &flux_density);
+ if (RES_OK != res){ goto error; }
+
+ if (NULL != flux_density.emission_spectrum) {
+ *wavelength = ssp_ranst_piecewise_linear_get
+ (source_view->emission_spectrum_pdf, rng);
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
diff --git a/src/sphor_ran_source.h b/src/sphor_ran_source.h
@@ -33,11 +33,19 @@ struct s3d_primitive;
extern LOCAL_SYM res_T
source_surface_sample_direction
- (struct sphin_source_surface* source,
+ (struct sphor* sphor,
struct ssp_rng* rng,
+ struct source_view* source_view,
struct s3d_primitive* prim,
double dir[3]);
+extern LOCAL_SYM res_T
+source_sample_wavelength
+ (struct sphor* sphor,
+ struct ssp_rng* rng,
+ struct source_view* source_view,
+ double* wavelength);
+
/* Sample a source view considering the discrete distribution of power of all
* sources in the config */
extern LOCAL_SYM res_T
@@ -52,8 +60,8 @@ extern LOCAL_SYM res_T
sample_source_position
(struct sphor* sphor,
struct ssp_rng* rng,
- struct source_view** source,
- struct s3d_primitive* primitive,
- float st[2]);
+ struct source_view** source_view,
+ struct s3d_primitive* scn_primitive,
+ double pos[3]);
#endif /* SPHOR_RAN_SOURCES_H */