solstice-solver

Solver library of the solstice app
git clone git://git.meso-star.com/solstice-solver.git
Log | Files | Refs | README | LICENSE

commit 9f505552613ea999b476483243fc33387428a84c
parent 3facd56ef07381a0465c81deeef11e5ee083b61f
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon,  6 Mar 2017 16:39:22 +0100

Move the path-tracing rendering code into a specific file

Diffstat:
Mcmake/CMakeLists.txt | 2++
Msrc/ssol_draw.c | 190++++++++++++-------------------------------------------------------------------
Asrc/ssol_draw_pt.c | 237+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ssol_draw_pt.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_ssol_draw.c | 18++++++++++++++----
5 files changed, 346 insertions(+), 167 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -57,6 +57,7 @@ set(SSOL_FILES_SRC ssol_camera.c ssol_device.c ssol_draw.c + ssol_draw_pt.c ssol_estimator.c ssol_image.c ssol_material.c @@ -80,6 +81,7 @@ set(SSOL_FILES_INC ssol_c.h ssol_camera.h ssol_device_c.h + ssol_draw_pt.h ssol_estimator_c.h ssol_image_c.h ssol_material_c.h diff --git a/src/ssol_draw.c b/src/ssol_draw.c @@ -17,10 +17,12 @@ #include "ssol_c.h" #include "ssol_camera.h" #include "ssol_device_c.h" +#include "ssol_draw_pt.h" #include "ssol_material_c.h" #include "ssol_object_c.h" #include "ssol_scene_c.h" #include "ssol_shape_c.h" +#include "ssol_sun_c.h" #include <rsys/double2.h> #include <rsys/double3.h> @@ -35,53 +37,6 @@ STATIC_ASSERT(IS_POW2(TILE_SIZE), TILE_SIZE_must_be_a_power_of_2); /******************************************************************************* - * Thread context - ******************************************************************************/ -struct thread_context { - struct ssp_rng* rng; - struct ssf_bsdf* bsdf; -}; - -static void -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)); -} - -static res_T -thread_context_init(struct mem_allocator* allocator, struct thread_context* ctx) -{ - res_T res = RES_OK; - ASSERT(ctx); - memset(ctx, 0, sizeof(ctx[0])); - res = ssf_bsdf_create(allocator, &ctx->bsdf); - if(res != RES_OK) goto error; -exit: - return res; -error: - thread_context_release(ctx); - goto exit; -} - -static void -thread_context_setup(struct thread_context* ctx, struct ssp_rng* rng) -{ - ASSERT(ctx && rng); - if(ctx->rng) SSP(rng_ref_put(ctx->rng)); - SSP(rng_ref_get(rng)); - ctx->rng = rng; -} - -/* Declare the container of the per thread contexts */ -#define DARRAY_NAME thread_ctx -#define DARRAY_DATA struct thread_context -#define DARRAY_FUNCTOR_INIT thread_context_init -#define DARRAY_FUNCTOR_RELEASE thread_context_release -#include <rsys/dynamic_array.h> - -/******************************************************************************* * Helper function ******************************************************************************/ static FINLINE uint16_t @@ -98,7 +53,6 @@ morton2D_decode(const uint32_t u32) static void Li_basic (struct ssol_scene* scn, - struct thread_context* ctx, struct s3d_scene_view* view, const float org[3], const float dir[3], @@ -108,7 +62,6 @@ Li_basic struct ray_data ray_data = RAY_DATA_NULL; struct s3d_hit hit; ASSERT(scn && view && org && dir && val); - (void)ctx; ray_data.scn = scn; ray_data.discard_virtual_materials = 1; @@ -140,101 +93,9 @@ Li_basic } static void -Li_pt - (struct ssol_scene* scn, - struct thread_context* ctx, - struct s3d_scene_view* view, - const float org[3], - const float dir[3], - double val[3]) -{ - struct s3d_hit hit; - struct ray_data ray_data = RAY_DATA_NULL; - struct ssol_instance* inst; - struct ssol_material* mtl; - const struct shaded_shape* sshape; - struct surface_fragment frag; - size_t idepth; - size_t isshape; - double throughput = 1.0; - double cos_wi_N; - double wi[3], o[3], uv[3]; - double N[3]; - double L = 0; - double r; - double pdf; - const float ray_range[2] = {0, FLT_MAX}; - float ray_org[3]; - float ray_dir[3]; - enum ssol_side_flag side; - ASSERT(scn && view && org && dir && val); - - ray_data.scn = scn; - ray_data.discard_virtual_materials = 1; - - f3_set(ray_org, org); - f3_set(ray_dir, dir); - - FOR_EACH(idepth, 0, 32) { - - S3D(scene_view_trace_ray - (view, ray_org, ray_dir, ray_range, &ray_data, &hit)); - if(S3D_HIT_NONE(&hit)) { - /* TODO background lighting */ - if(ray_dir[2] > 0) L += throughput; - break; - } - - /* Retrieve the hit shaded shape */ - inst = *htable_instance_find(&scn->instances_rt, &hit.prim.inst_id); - isshape = *htable_shaded_shape_find - (&inst->object->shaded_shapes_rt, &hit.prim.geom_id); - sshape = darray_shaded_shape_cdata_get(&inst->object->shaded_shapes)+isshape; - - d3_set_f3(o, ray_org); - d3_set_f3(wi, ray_dir); - d2_set_f2(uv, hit.uv); - d3_set_f3(N, hit.normal); - d3_normalize(N, N); - d3_normalize(wi, wi); - - if(f3_dot(hit.normal, ray_dir) < 0) { - mtl = sshape->mtl_front; - side = SSOL_FRONT; - } else { - mtl = sshape->mtl_back; - side = SSOL_BACK; - d3_minus(N, N); - } - - surface_fragment_setup(&frag, o, wi, N, &hit.prim, hit.uv); - SSF(bsdf_clear(ctx->bsdf)); - CHECK(material_shade(mtl, &frag, 1/*TODO wavelength*/, ctx->bsdf), RES_OK); - - d3_minus(wi, wi); - cos_wi_N = d3_dot(wi, N); - - /*L += throughput * direct_lighting(); *//* TODO */ - - /* Update the ray */ - ray_data.prim_from = hit.prim; - ray_data.inst_from = inst; - ray_data.side_from = side; - f3_mulf(ray_dir, ray_dir, hit.distance); - f3_add(ray_org, ray_org, ray_dir); - r = ssf_bsdf_sample(ctx->bsdf, ctx->rng, wi, frag.Ns, wi, &pdf); - ASSERT(0 <= r && r <= 1); - f3_set_d3(ray_dir, wi); - - throughput *= r * cos_wi_N; - } - d3_splat(val, L); -} - -static void draw_tile (struct ssol_scene* scn, - struct thread_context* ctx, + struct draw_pt_thread_context* ctx, struct s3d_scene_view* view, const struct ssol_camera* cam, const size_t origin[2], /* Tile origin */ @@ -251,10 +112,7 @@ draw_tile npixels *= npixels; FOR_EACH(mcode, 0, npixels) { - const size_t NSAMPS = 1; - size_t isamp; size_t ipix[2]; - float org[3], dir[3], samp[2]; double* pixel; ipix[0] = morton2D_decode((uint32_t)(mcode>>0)); @@ -263,20 +121,23 @@ draw_tile if(ipix[1] >= size[1]) continue; pixel = pixels + (ipix[1]*size[0] + ipix[0])*3/*#channels*/; - ipix[0] = ipix[0] + origin[0]; ipix[1] = ipix[1] + origin[1]; - d3_splat(pixel, 0); - FOR_EACH(isamp, 0, NSAMPS) { - double L[3]; - samp[0] = ((float)ipix[0]+ssp_rng_canonical_float(ctx->rng))*pix_sz[0]; - samp[1] = ((float)ipix[1]+ssp_rng_canonical_float(ctx->rng))*pix_sz[1]; - camera_ray(cam, samp, org, dir); - Li_basic(scn, ctx, view, org, dir, L); - d3_add(pixel, pixel, L); +#if 0 + draw_pt(scn, cam, view, ipix, pix_sz, 64, ctx, pixel); +#else + { + float samp[2]; + float ray_org[3], ray_dir[3]; + + samp[0] = ((float)ipix[0] + 0.5f) * pix_sz[0]; + samp[1] = ((float)ipix[1] + 0.5f) * pix_sz[1]; + camera_ray(cam, samp, ray_org, ray_dir); + + Li_basic(scn, view, ray_org, ray_dir, pixel); } - d3_divd(pixel, pixel, (double)NSAMPS); +#endif } } @@ -292,7 +153,7 @@ ssol_draw ssol_write_pixels_T writer, void* data) { - struct darray_thread_ctx thread_ctxs; + struct darray_draw_pt_thread_context thread_ctxs; struct ssp_rng_proxy* rng_proxy = NULL; struct s3d_scene_view* view = NULL; struct darray_byte* tiles = NULL; @@ -305,23 +166,26 @@ ssol_draw if(!scn || !cam || !width || !height || !writer) return RES_BAD_ARG; + darray_draw_pt_thread_context_init(scn->dev->allocator, &thread_ctxs); + /* 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; /* Create the thread contexts */ - darray_thread_ctx_init(scn->dev->allocator, &thread_ctxs); - res = darray_thread_ctx_resize(&thread_ctxs, scn->dev->nthreads); + res = darray_draw_pt_thread_context_resize(&thread_ctxs, scn->dev->nthreads); if(res != RES_OK) goto error; FOR_EACH(i, 0, scn->dev->nthreads) { - struct thread_context* ctx = darray_thread_ctx_data_get(&thread_ctxs)+i; + struct draw_pt_thread_context* ctx; struct ssp_rng* rng; + ctx = darray_draw_pt_thread_context_data_get(&thread_ctxs)+i; + res = ssp_rng_proxy_create_rng(rng_proxy, i, &rng); if(res != RES_OK) goto error; - thread_context_setup(ctx, rng); + draw_pt_thread_context_setup(ctx, rng); SSP(rng_ref_put(rng)); } @@ -346,7 +210,7 @@ ssol_draw #pragma omp parallel for schedule(dynamic, 1/*chunck size*/) for(mcode=0; mcode<(int64_t)ntiles; ++mcode) { - struct thread_context* ctx; + struct draw_pt_thread_context* ctx; size_t tile_org[2]; size_t tile_sz[2]; const int ithread = omp_get_thread_num(); @@ -355,7 +219,7 @@ ssol_draw if(ATOMIC_GET(&res) != RES_OK) continue; - ctx = darray_thread_ctx_data_get(&thread_ctxs) + ithread; + ctx = darray_draw_pt_thread_context_data_get(&thread_ctxs) + ithread; tile_org[0] = morton2D_decode((uint32_t)(mcode>>0)); if(tile_org[0] >= ntiles_x) continue; @@ -379,7 +243,7 @@ ssol_draw } exit: - darray_thread_ctx_release(&thread_ctxs); + darray_draw_pt_thread_context_release(&thread_ctxs); if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy)); if(view) S3D(scene_view_ref_put(view)); return (res_T)res; diff --git a/src/ssol_draw_pt.c b/src/ssol_draw_pt.c @@ -0,0 +1,237 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "ssol_c.h" +#include "ssol_camera.h" +#include "ssol_draw_pt.h" +#include "ssol_material_c.h" +#include "ssol_object_c.h" +#include "ssol_scene_c.h" +#include "ssol_sun_c.h" + +#include <rsys/double2.h> +#include <rsys/double3.h> +#include <rsys/float3.h> + +#include <star/s3d.h> +#include <star/ssf.h> +#include <star/ssp.h> + +/******************************************************************************* + * Per thread draw_pt context + ******************************************************************************/ +res_T +draw_pt_thread_context_init + (struct mem_allocator* allocator, + struct draw_pt_thread_context* ctx) +{ + res_T res = RES_OK; + ASSERT(ctx); + memset(ctx, 0, sizeof(ctx[0])); + res = ssf_bsdf_create(allocator, &ctx->bsdf); + if(res != RES_OK) goto error; +exit: + return res; +error: + draw_pt_thread_context_release(ctx); + goto exit; +} + +void +draw_pt_thread_context_release(struct draw_pt_thread_context* ctx) +{ + ASSERT(ctx); + if(ctx->rng) SSP(rng_ref_put(ctx->rng)); + if(ctx->bsdf) SSF(bsdf_ref_put(ctx->bsdf)); +} + + +void +draw_pt_thread_context_setup + (struct draw_pt_thread_context* ctx, + struct ssp_rng* rng) +{ + ASSERT(ctx && rng); + if(ctx->rng) SSP(rng_ref_put(ctx->rng)); + SSP(rng_ref_get(rng)); + ctx->rng = rng; +} + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE double +sun_lighting + (struct ssol_sun* sun, + struct s3d_scene_view* view, + struct ray_data* ray_data, + struct ssf_bsdf* bsdf, + const double wo[3], + const double N[3], + const float ray_org[3]) +{ + struct s3d_hit hit; + const float ray_range[2] = {0, FLT_MAX}; + double wi[3]; + float ray_dir[3]; + double cos_wi_N; + double R; + ASSERT(sun && view && ray_data && bsdf && wo && N && ray_org); + ASSERT(d3_dot(wo, N) >= 0); /* Assume that wo point outward the surface */ + + d3_minus(wi, sun->direction); + R = ssf_bsdf_eval(bsdf, wo, N, wi); + if(R <= 0) return 0.0; + + cos_wi_N = d3_dot(wi, N); + + f3_set_d3(ray_dir, wi); + S3D(scene_view_trace_ray(view, ray_org, ray_dir, ray_range, ray_data, &hit)); + if(S3D_HIT_NONE(&hit)) return R * cos_wi_N; + return 0; +} + +static void +Li + (struct ssol_scene* scn, + struct draw_pt_thread_context* ctx, + struct s3d_scene_view* view, + const float org[3], + const float dir[3], + double val[3]) +{ + struct s3d_hit hit; + struct ray_data ray_data = RAY_DATA_NULL; + struct ssol_instance* inst; + struct ssol_material* mtl; + const struct shaded_shape* sshape; + struct surface_fragment frag; + size_t idepth; + size_t isshape; + double throughput = 1.0; + double wi[3], o[3], uv[3]; + double wo[3]; + double N[3]; + double L = 0; + double R; + double pdf; + const float ray_range[2] = {0, FLT_MAX}; + float ray_org[3]; + float ray_dir[3]; + enum ssol_side_flag side; + ASSERT(scn && view && org && dir && val); + + ray_data.scn = scn; + ray_data.discard_virtual_materials = 1; + + f3_set(ray_org, org); + f3_set(ray_dir, dir); + + FOR_EACH(idepth, 0, 4) { + + S3D(scene_view_trace_ray + (view, ray_org, ray_dir, ray_range, &ray_data, &hit)); + if(S3D_HIT_NONE(&hit)) { + /* TODO background lighting */ + if(ray_dir[2] > 0) L += throughput; + break; + } + + /* Retrieve the hit shaded shape */ + inst = *htable_instance_find(&scn->instances_rt, &hit.prim.inst_id); + isshape = *htable_shaded_shape_find + (&inst->object->shaded_shapes_rt, &hit.prim.geom_id); + sshape = darray_shaded_shape_cdata_get(&inst->object->shaded_shapes)+isshape; + + d3_set_f3(o, ray_org); + d3_set_f3(wo, ray_dir); + d2_set_f2(uv, hit.uv); + d3_set_f3(N, hit.normal); + d3_normalize(N, N); + d3_normalize(wo, wo); + + if(f3_dot(hit.normal, ray_dir) < 0) { + mtl = sshape->mtl_front; + side = SSOL_FRONT; + } else { + mtl = sshape->mtl_back; + side = SSOL_BACK; + d3_minus(N, N); + } + + surface_fragment_setup(&frag, o, wi, N, &hit.prim, hit.uv); + SSF(bsdf_clear(ctx->bsdf)); + CHECK(material_shade(mtl, &frag, 1/*TODO wavelength*/, ctx->bsdf), RES_OK); + + /* Update the ray */ + ray_data.prim_from = hit.prim; + ray_data.inst_from = inst; + ray_data.side_from = side; + f3_mulf(ray_dir, ray_dir, hit.distance); + f3_add(ray_org, ray_org, ray_dir); + + if(scn->sun) { + L += throughput * sun_lighting + (scn->sun, view, &ray_data, ctx->bsdf, wo, N, ray_org); + } + + d3_minus(wo, wo); + R = ssf_bsdf_sample(ctx->bsdf, ctx->rng, wo, frag.Ns, wi, &pdf); + ASSERT(0 <= R && R <= 1); + f3_set_d3(ray_dir, wi); + + throughput *= R * d3_dot(wi, N); + } + d3_splat(val, L); +} + +/******************************************************************************* + * Local function + ******************************************************************************/ +void +draw_pt + (struct ssol_scene* scn, + const struct ssol_camera* cam, + struct s3d_scene_view* view, + const size_t pix_coords[2], /* Image space pixel coordinates */ + const float pix_sz[2], /* Normalized pixel size */ + const size_t nsamples, + struct draw_pt_thread_context* ctx, + double pixel[3]) +{ + double L[3]; + size_t isample; + ASSERT(scn && cam && pix_coords && pix_sz && nsamples && ctx && pixel); + + d3_splat(pixel, 0); + FOR_EACH(isample, 0, nsamples) { + float samp[2]; /* Pixel sample */ + float ray_org[3], ray_dir[3]; + + /* Generate a sample into the pixel */ + samp[0] = ((float)pix_coords[0]+ssp_rng_canonical_float(ctx->rng))*pix_sz[0]; + samp[1] = ((float)pix_coords[1]+ssp_rng_canonical_float(ctx->rng))*pix_sz[1]; + + /* Generate a ray starting from the pinhole camera and passing through the + * pixel sample */ + camera_ray(cam, samp, ray_org, ray_dir); + + /* Compute the radiance arriving through the sampled camera ray */ + Li(scn, ctx, view, ray_org, ray_dir, L); + d3_add(pixel, pixel, L); + } + + d3_divd(pixel, pixel, (double)nsamples); +} diff --git a/src/ssol_draw_pt.h b/src/ssol_draw_pt.h @@ -0,0 +1,66 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SSOL_DRAW_PT_H +#define SSOL_DRAW_PT_H + +#include <rsys/dynamic_array.h> + +/* Forward declarations */ +struct s3d_scene_view; +struct ssol_camera; +struct ssol_scene; +struct ssf_bsdf; +struct ssp_rng; + +struct draw_pt_thread_context { + struct ssp_rng* rng; + struct ssf_bsdf* bsdf; +}; + +extern LOCAL_SYM res_T +draw_pt_thread_context_init + (struct mem_allocator* allocator, + struct draw_pt_thread_context* ctx); + +extern LOCAL_SYM void +draw_pt_thread_context_release + (struct draw_pt_thread_context* ctx); + +extern LOCAL_SYM void +draw_pt_thread_context_setup + (struct draw_pt_thread_context* ctx, + struct ssp_rng* rng); + +/* Declare the container of the per thread contexts */ +#define DARRAY_NAME draw_pt_thread_context +#define DARRAY_DATA struct draw_pt_thread_context +#define DARRAY_FUNCTOR_INIT draw_pt_thread_context_init +#define DARRAY_FUNCTOR_RELEASE draw_pt_thread_context_release +#include <rsys/dynamic_array.h> + +extern LOCAL_SYM void +draw_pt + (struct ssol_scene* scn, + const struct ssol_camera* cam, + struct s3d_scene_view* view, + const size_t pix_coords[2], + const float pix_sz[2], + const size_t nsamples, + struct draw_pt_thread_context* ctx, + double radiance[3]); + +#endif /* SSOL_DRAW_PT_H */ + diff --git a/src/test_ssol_draw.c b/src/test_ssol_draw.c @@ -18,6 +18,7 @@ #include "test_ssol_geometries.h" #include "test_ssol_materials.h" +#include <rsys/double3.h> #include <rsys/float3.h> #include <rsys/image.h> #include <rsys/math.h> @@ -114,7 +115,7 @@ setup_cornell_box(struct ssol_device* dev, struct ssol_scene* scn) struct ssol_object* obj; struct ssol_instance* inst; struct ssol_material* mtl; - struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL; + struct ssol_matte_shader shader = SSOL_MATTE_SHADER_NULL; struct ssol_vertex_data vdata; struct desc desc; float lower[3], upper[3]; @@ -122,9 +123,8 @@ setup_cornell_box(struct ssol_device* dev, struct ssol_scene* scn) shader.normal = get_shader_normal; shader.reflectivity = get_shader_reflectivity; - shader.roughness = get_shader_roughness; - CHECK(ssol_material_create_mirror(dev, &mtl), RES_OK); - CHECK(ssol_mirror_set_shader(mtl, &shader), RES_OK); + CHECK(ssol_material_create_matte(dev, &mtl), RES_OK); + CHECK(ssol_matte_set_shader(mtl, &shader), RES_OK); vdata.usage = SSOL_POSITION; vdata.get = get_position; @@ -180,10 +180,12 @@ main(int argc, char** argv) struct ssol_device* dev; struct ssol_camera* cam; struct ssol_scene* scn; + struct ssol_sun* sun; unsigned char* pixels = NULL; const double pos[3] = {278.0, -1000.0, 273.0}; const double tgt[3] = {278.0, 0.0, 273.0}; const double up[3] = {0.0, 0.0, 1.0}; + double dir[3]; (void)argc, (void)argv; CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); @@ -200,6 +202,13 @@ main(int argc, char** argv) CHECK(ssol_camera_set_fov(cam, PI/4.0), RES_OK); CHECK(ssol_camera_look_at(cam, pos, tgt, up), RES_OK); + d3(dir, 1, 1, -1); + d3_normalize(dir, dir); + CHECK(ssol_sun_create_directional(dev, &sun), RES_OK); + CHECK(ssol_sun_set_direction(sun, dir), RES_OK); + CHECK(ssol_sun_set_dni(sun, 1000), RES_OK); + CHECK(ssol_scene_attach_sun(scn, sun), RES_OK); + pixels = MEM_CALLOC(&allocator, HEIGHT, PITCH); NCHECK(pixels, NULL); @@ -242,6 +251,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_sun_ref_put(sun), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator);