commit 4bb38119658506de2aa1ba9f9173c3376851adc4
parent 5b1b7e0d8b475e5d19612915e158d180c68b266e
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 25 Apr 2017 17:16:25 +0200
Handle spectral data in the path-tracer
Diffstat:
9 files changed, 142 insertions(+), 78 deletions(-)
diff --git a/src/ssol_draw_draft.c b/src/ssol_draw_draft.c
@@ -157,6 +157,9 @@ ssol_draw_draft
darray_float_init(scn->dev->allocator, &samples);
+ res = scene_check(scn, FUNC_NAME);
+ if(res != RES_OK) goto error;
+
res = darray_float_reserve(&samples, spp * 2/*#dimensions*/);
if(res != RES_OK) goto error;
diff --git a/src/ssol_draw_pt.c b/src/ssol_draw_pt.c
@@ -19,6 +19,7 @@
#include "ssol_draw.h"
#include "ssol_material_c.h"
#include "ssol_object_c.h"
+#include "ssol_ranst_sun_wl.h"
#include "ssol_scene_c.h"
#include "ssol_shape_c.h"
#include "ssol_sun_c.h"
@@ -37,6 +38,7 @@
struct thread_context {
struct ssp_rng* rng;
struct ssf_bsdf* bsdf;
+ struct ranst_sun_wl* ran_wl;
};
static void
@@ -45,6 +47,7 @@ thread_context_release(struct thread_context* ctx)
ASSERT(ctx);
if(ctx->rng) SSP(rng_ref_put(ctx->rng));
if(ctx->bsdf) SSF(bsdf_ref_put(ctx->bsdf));
+ if(ctx->ran_wl) ranst_sun_wl_ref_put(ctx->ran_wl);
}
static res_T
@@ -67,12 +70,15 @@ error:
static void
thread_context_setup
(struct thread_context* ctx,
- struct ssp_rng* rng)
+ struct ssp_rng* rng,
+ struct ranst_sun_wl* ran_wl)
{
- ASSERT(ctx && rng);
+ ASSERT(ctx && rng && ran_wl);
if(ctx->rng) SSP(rng_ref_put(ctx->rng));
SSP(rng_ref_get(rng));
+ ranst_sun_wl_ref_get(ran_wl);
ctx->rng = rng;
+ ctx->ran_wl = ran_wl;
}
/* Declare the container of the per thread contexts */
@@ -144,6 +150,7 @@ Li(struct ssol_scene* scn,
double R;
double pdf;
double cos_wi_Ng;
+ double wl;
const float ray_range[2] = {0, FLT_MAX};
float ray_org[3];
float ray_dir[3];
@@ -159,12 +166,14 @@ Li(struct ssol_scene* scn,
f3_set(ray_org, org);
f3_set(ray_dir, dir);
+ wl = ranst_sun_wl_get(ctx->ran_wl, ctx->rng);
+
for(;;) {
double absorptivity;
S3D(scene_view_trace_ray
(view, ray_org, ray_dir, ray_range, &ray_data, &hit));
- absorptivity = ssol_data_get_value(&medium.absorptivity, 1/*Wavelength*/);
+ absorptivity = ssol_data_get_value(&medium.absorptivity, wl);
if(absorptivity > 0) {
throughput *= exp(-absorptivity * hit.distance);
}
@@ -206,14 +215,14 @@ Li(struct ssol_scene* scn,
}
surface_fragment_setup(&frag, o, wo, N, &hit.prim, hit.uv);
- material_shade_normal(mtl, &frag, 1/*TODO wlen*/, N);
+ material_shade_normal(mtl, &frag, wl, N);
/* Shaded normal may look backward the outgoing direction */
if(d3_dot(N, wo) > 0) break;
SSF(bsdf_clear(ctx->bsdf));
res = material_setup_bsdf
- (mtl, &frag, 1/*TODO wavelength*/, &medium, 1/*Rendering*/, ctx->bsdf);
+ (mtl, &frag, wl, &medium, 1/*Rendering*/, ctx->bsdf);
if(res != RES_OK) goto error;
/* Update the ray */
@@ -341,19 +350,25 @@ ssol_draw_pt
{
struct darray_thread_context thread_ctxs;
struct ssp_rng_proxy* rng_proxy = NULL;
+ struct ranst_sun_wl* ran_sun_wl = NULL;
size_t i;
res_T res = RES_OK;
- if(!scn)
- return RES_BAD_ARG;
+ if(!scn) return RES_BAD_ARG;
darray_thread_context_init(scn->dev->allocator, &thread_ctxs);
+ res = scene_check(scn, FUNC_NAME);
+ if(res != RES_OK) goto error;
+
/* Create a RNG proxy */
res = ssp_rng_proxy_create
(scn->dev->allocator, &ssp_rng_threefry, scn->dev->nthreads, &rng_proxy);
if(res != RES_OK) goto error;
+ res = sun_create_wavelength_distribution(scn->sun, &ran_sun_wl);
+ if(res != RES_OK) goto error;
+
/* Create the thread contexts */
res = darray_thread_context_resize(&thread_ctxs, scn->dev->nthreads);
if(res != RES_OK) goto error;
@@ -366,7 +381,7 @@ ssol_draw_pt
res = ssp_rng_proxy_create_rng(rng_proxy, i, &rng);
if(res != RES_OK) goto error;
- thread_context_setup(ctx, rng);
+ thread_context_setup(ctx, rng, ran_sun_wl);
SSP(rng_ref_put(rng));
}
@@ -377,6 +392,7 @@ ssol_draw_pt
exit:
darray_thread_context_release(&thread_ctxs);
if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
+ if(ran_sun_wl) ranst_sun_wl_ref_put(ran_sun_wl);
return (res_T)res;
error:
goto exit;
diff --git a/src/ssol_scene.c b/src/ssol_scene.c
@@ -14,22 +14,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "ssol.h"
-#include "ssol_c.h"
#include "ssol_atmosphere_c.h"
-#include "ssol_scene_c.h"
-#include "ssol_sun_c.h"
+#include "ssol_c.h"
#include "ssol_device_c.h"
+#include "ssol_instance_c.h"
#include "ssol_material_c.h"
-#include "ssol_shape_c.h"
#include "ssol_object_c.h"
-#include "ssol_instance_c.h"
+#include "ssol_scene_c.h"
+#include "ssol_shape_c.h"
+#include "ssol_spectrum_c.h"
+#include "ssol_sun_c.h"
+#include <rsys/double3.h>
+#include <rsys/float2.h>
+#include <rsys/float3.h>
#include <rsys/list.h>
#include <rsys/mem_allocator.h>
#include <rsys/rsys.h>
-#include <rsys/float2.h>
-#include <rsys/float3.h>
-#include <rsys/double3.h>
/*******************************************************************************
* Helper functions
@@ -521,3 +522,37 @@ hit_filter_function
return 0;
}
+
+res_T
+scene_check(const struct ssol_scene* scene, const char* caller)
+{
+ ASSERT(scene && caller);
+
+ if(!scene->sun) {
+ log_error(scene->dev, "%s: no sun attached.\n", caller);
+ return RES_BAD_ARG;
+ }
+
+ if(!scene->sun->spectrum) {
+ log_error(scene->dev, "%s: sun's spectrum undefined.\n", caller);
+ return RES_BAD_ARG;
+ }
+
+ if(scene->sun->dni <= 0) {
+ log_error(scene->dev, "%s: sun's DNI undefined.\n", caller);
+ return RES_BAD_ARG;
+ }
+
+ if(scene->atmosphere) {
+ int i;
+ ASSERT(scene->atmosphere->type == ATMOS_UNIFORM);
+ i = spectrum_includes
+ (scene->atmosphere->data.uniform.spectrum, scene->sun->spectrum);
+ if(!i) {
+ log_error(scene->dev, "%s: sun/atmosphere spectra mismatch.\n", caller);
+ return RES_BAD_ARG;
+ }
+ }
+ return RES_OK;
+}
+
diff --git a/src/ssol_scene_c.h b/src/ssol_scene_c.h
@@ -60,5 +60,10 @@ scene_create_s3d_views
double* sampled_area, /* Area of the instance set as "samplable" */
double* sampled_area_proxy); /* Area of the sampled geometries */
+extern LOCAL_SYM res_T
+scene_check
+ (const struct ssol_scene* scene,
+ const char* caller);
+
#endif /* SSOL_SCENE_C_H */
diff --git a/src/ssol_solver.c b/src/ssol_solver.c
@@ -25,7 +25,6 @@
#include "ssol_object_c.h"
#include "ssol_sun_c.h"
#include "ssol_material_c.h"
-#include "ssol_spectrum_c.h"
#include "ssol_instance_c.h"
#include "ssol_ranst_sun_dir.h"
#include "ssol_ranst_sun_wl.h"
@@ -485,39 +484,6 @@ point_dump
/*******************************************************************************
* Helper functions
******************************************************************************/
-static FINLINE res_T
-check_scene(const struct ssol_scene* scene, const char* caller)
-{
- ASSERT(scene && caller);
-
- if(!scene->sun) {
- log_error(scene->dev, "%s: no sun attached.\n", caller);
- return RES_BAD_ARG;
- }
-
- if(!scene->sun->spectrum) {
- log_error(scene->dev, "%s: sun's spectrum undefined.\n", caller);
- return RES_BAD_ARG;
- }
-
- if(scene->sun->dni <= 0) {
- log_error(scene->dev, "%s: sun's DNI undefined.\n", caller);
- return RES_BAD_ARG;
- }
-
- if(scene->atmosphere) {
- int i;
- ASSERT(scene->atmosphere->type == ATMOS_UNIFORM);
- i = spectrum_includes
- (scene->atmosphere->data.uniform.spectrum, scene->sun->spectrum);
- if(!i) {
- log_error(scene->dev, "%s: sun/atmosphere spectra mismatch.\n", caller);
- return RES_BAD_ARG;
- }
- }
- return RES_OK;
-}
-
/* Compute an empirical length of the path segment coming from/going to the
* infinite, wrt the scene bounding box */
static INLINE double
@@ -963,14 +929,16 @@ ssol_solve
nrealisations = (int)realisations_count;
nthreads = (int) scn->dev->nthreads;
- res = check_scene(scn, FUNC_NAME);
+ res = scene_check(scn, FUNC_NAME);
if(res != RES_OK) goto error;
/* Create data structures shared by all threads */
res = scene_create_s3d_views(scn, &view_rt, &view_samp, &sampled_area,
&sampled_area_proxy);
if(res != RES_OK) goto error;
- res = sun_create_distributions(scn->sun, &ran_sun_dir, &ran_sun_wl);
+ res = sun_create_direction_distribution(scn->sun, &ran_sun_dir);
+ if(res != RES_OK) goto error;
+ res = sun_create_wavelength_distribution(scn->sun, &ran_sun_wl);
if(res != RES_OK) goto error;
/* Create a RNG proxy from the submitted RNG state */
diff --git a/src/ssol_sun.c b/src/ssol_sun.c
@@ -199,27 +199,13 @@ ssol_sun_set_buie_param
* Local function
******************************************************************************/
res_T
-sun_create_distributions
- (struct ssol_sun* sun,
- struct ranst_sun_dir** out_ran_dir,
- struct ranst_sun_wl** out_ran_wl)
+sun_create_direction_distribution
+ (struct ssol_sun* sun, struct ranst_sun_dir** out_ran_dir)
{
struct ranst_sun_dir* ran_dir = NULL;
- struct ranst_sun_wl* ran_wl = NULL;
res_T res = RES_OK;
- ASSERT(sun && out_ran_dir && out_ran_wl);
-
- /* Create and setup the spectrum distribution */
- res = ranst_sun_wl_create(sun->dev->allocator, &ran_wl);
- if(res != RES_OK) goto error;
-
- res = ranst_sun_wl_setup(ran_wl,
- darray_double_cdata_get(&sun->spectrum->wavelengths),
- darray_double_cdata_get(&sun->spectrum->intensities),
- darray_double_size_get(&sun->spectrum->wavelengths));
- if(res != RES_OK) goto error;
+ ASSERT(sun && out_ran_dir);
- /* Create and setup the the direction distribution */
res = ranst_sun_dir_create(sun->dev->allocator, &ran_dir);
if(res != RES_OK) goto error;
switch(sun->type) {
@@ -236,16 +222,10 @@ sun_create_distributions
break;
default: FATAL("Unreachable code\n"); break;
}
-
exit:
*out_ran_dir = ran_dir;
- *out_ran_wl = ran_wl;
return res;
error:
- if(ran_wl) {
- CHECK(ranst_sun_wl_ref_put(ran_wl), RES_OK);
- ran_wl = NULL;
- }
if(ran_dir) {
CHECK(ranst_sun_dir_ref_put(ran_dir), RES_OK);
ran_dir = NULL;
@@ -253,3 +233,30 @@ error:
goto exit;
}
+res_T
+sun_create_wavelength_distribution
+ (struct ssol_sun* sun, struct ranst_sun_wl** out_ran_wl)
+{
+ struct ranst_sun_wl* ran_wl = NULL;
+ res_T res = RES_OK;
+ ASSERT(sun && out_ran_wl);
+
+ res = ranst_sun_wl_create(sun->dev->allocator, &ran_wl);
+ if(res != RES_OK) goto error;
+
+ res = ranst_sun_wl_setup(ran_wl,
+ darray_double_cdata_get(&sun->spectrum->wavelengths),
+ darray_double_cdata_get(&sun->spectrum->intensities),
+ darray_double_size_get(&sun->spectrum->wavelengths));
+ if(res != RES_OK) goto error;
+
+exit:
+ *out_ran_wl = ran_wl;
+ return res;
+error:
+ if(ran_wl) {
+ CHECK(ranst_sun_wl_ref_put(ran_wl), RES_OK);
+ ran_wl = NULL;
+ }
+ goto exit;
+}
diff --git a/src/ssol_sun_c.h b/src/ssol_sun_c.h
@@ -54,9 +54,13 @@ struct ssol_sun {
};
extern LOCAL_SYM res_T
-sun_create_distributions
+sun_create_direction_distribution
+ (struct ssol_sun* sun,
+ struct ranst_sun_dir** out_ran_dir);
+
+extern LOCAL_SYM res_T
+sun_create_wavelength_distribution
(struct ssol_sun* sun,
- struct ranst_sun_dir** out_ran_dir,
struct ranst_sun_wl** out_ran_wl);
#endif /* SSOL_SUN_C_H */
diff --git a/src/test_ssol_draw.c b/src/test_ssol_draw.c
@@ -30,6 +30,17 @@
#define PITCH (WIDTH*sizeof(unsigned char[3]))
#define PROJ_RATIO ((double)WIDTH/(double)HEIGHT)
+static void
+get_wlen(const size_t i, double* wlen, double* data, void* ctx)
+{
+ double wavelengths[3] = { 1, 2, 3 };
+ double intensities[3] = { 1, 0.8, 1 };
+ CHECK(i < 3, 1);
+ (void)ctx;
+ *wlen = wavelengths[i];
+ *data = intensities[i];
+}
+
static res_T
write_RGB8
(void* data,
@@ -182,6 +193,7 @@ main(int argc, char** argv)
struct ssol_device* dev;
struct ssol_camera* cam;
struct ssol_scene* scn;
+ struct ssol_spectrum* spectrum;
struct ssol_sun* sun;
struct image img;
uint8_t* pixels;
@@ -303,6 +315,13 @@ main(int argc, char** argv)
CHECK(draw_func(NULL, NULL, WIDTH, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
CHECK(draw_func(scn, NULL, WIDTH, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
CHECK(draw_func(NULL, cam, WIDTH, WIDTH, 4, write_RGB8, pixels), RES_BAD_ARG);
+
+ /* No sun spectrum */
+ CHECK(draw_func(scn, cam, WIDTH, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
+
+ CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
+ CHECK(ssol_spectrum_setup(spectrum, get_wlen, 3, NULL), RES_OK);
+ CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK);
CHECK(draw_func(scn, cam, WIDTH, HEIGHT, 4, write_RGB8, pixels), RES_OK);
CHECK(image_write_ppm_stream(&img, 0, stdout), RES_OK);
@@ -311,6 +330,7 @@ main(int argc, char** argv)
CHECK(ssol_device_ref_put(dev), RES_OK);
CHECK(ssol_camera_ref_put(cam), RES_OK);
CHECK(ssol_scene_ref_put(scn), RES_OK);
+ CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
check_memory_allocator(&allocator);
diff --git a/src/test_ssol_solver1.c b/src/test_ssol_solver1.c
@@ -120,7 +120,6 @@ main(int argc, char** argv)
CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK);
CHECK(ssol_sun_set_dni(sun, 1000), RES_OK);
CHECK(ssol_scene_create(dev, &scene), RES_OK);
- CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
CHECK(ssol_solve(NULL, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
CHECK(ssol_solve(scene, NULL, 10, 0, NULL, &estimator), RES_BAD_ARG);
@@ -164,6 +163,13 @@ main(int argc, char** argv)
CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
+ /* No sun */
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
+
+ CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_OK);
+ CHECK(ssol_estimator_ref_put(estimator), RES_OK);
+
CHECK(ssol_solve
(scene, rng, 1, &SSOL_PATH_TRACKER_DEFAULT, NULL, &estimator), RES_OK);