solstice-solver

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

commit 8387a8776375f7e6ac91d2672bffc2544307ca95
parent a17d23562d7c3d7af70c9fdb63e4cb5b1a4b7371
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  7 Oct 2016 14:43:07 +0200

Add matrix transformation to the quadric data structure

This matrix transform the quadric in object space; i.e. in object space,
the quadric is not necessarily aligned with the axis.

Diffstat:
Msrc/ssol.h | 10++++++++--
Msrc/ssol_scene.c | 82++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/ssol_shape.c | 63+++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/ssol_solver.c | 33++++++++++++++++++++++++---------
Msrc/test_ssol_solver2.c | 2+-
Msrc/test_ssol_solver2b.c | 2+-
Msrc/test_ssol_solver3.c | 2+-
Msrc/test_ssol_solver3N.c | 2+-
Msrc/test_ssol_solver4.c | 2+-
Msrc/test_ssol_solver5.c | 2+-
10 files changed, 125 insertions(+), 75 deletions(-)

diff --git a/src/ssol.h b/src/ssol.h @@ -146,10 +146,16 @@ struct ssol_quadric { struct ssol_quadric_parabol parabol; struct ssol_quadric_parabolic_cylinder parabolic_cylinder; } data; + + /* 3x4 column major transformation of the quadric in object space */ + double transform[12]; }; -#define SSOL_QUADRIC_DEFAULT__ \ - {SSOL_QUADRIC_PLANE, {SSOL_QUADRIC_PLANE_DEFAULT__}} +#define SSOL_QUADRIC_DEFAULT__ { \ + SSOL_QUADRIC_PLANE, \ + {SSOL_QUADRIC_PLANE_DEFAULT__}, \ + {1,0,0, 0,1,0, 0,0,1, 0,0,0} \ +} static const struct ssol_quadric SSOL_QUADRIC_DEFAULT = SSOL_QUADRIC_DEFAULT__; /* Define the contour of a 2D polygon as well as the clipping operation to diff --git a/src/ssol_scene.c b/src/ssol_scene.c @@ -119,7 +119,7 @@ ssol_scene_attach_instance res_T res; if(!scene || !instance) return RES_BAD_ARG; - + /* Attach the instantiated s3d shape to ray-trace to the RT scene */ res = s3d_scene_attach_shape(scene->scn_rt, instance->shape_rt); if(res != RES_OK) return res; @@ -358,41 +358,51 @@ hit_filter_function shape = inst->object->shape; seg->on_punched = (shape->type == SHAPE_PUNCHED); switch (shape->type) { - case SHAPE_PUNCHED: { - /* hits on quadrics must be recomputed more accurately */ - double org_local[3], hit_pos_local[3], dir_local[3]; - const double* transform = inst->transform; - double tr[9]; - int valid; - d33_inverse(tr, transform); - - /* get org in local coordinate */ - d3_set(org_local, seg->org); - d3_sub(org_local, org_local, transform + 9); - d33_muld3(org_local, tr, org_local); - - /* get dir in local */ - d33_muld3(dir_local, tr, seg->dir); - /* recompute hit */ - valid = punched_shape_intersect_local(shape, org_local, dir_local, - hit->distance, hit_pos_local, seg->hit_normal, &seg->hit_distance); - if (!valid) return 1; - /* transform point to world */ - d33_muld3(seg->hit_pos, transform, hit_pos_local); - d3_add(seg->hit_pos, transform + 9, seg->hit_pos); - /* transform normal to world */ - d33_invtrans(tr, transform); - d33_muld3(seg->hit_normal, tr, seg->hit_normal); - break; - } - case SHAPE_MESH: { - d3_set_f3(seg->hit_normal, hit->normal); - /* use raytraced distance to fill hit_pos */ - d3_add(seg->hit_pos, seg->org, d3_muld(seg->hit_pos, seg->dir, hit->distance)); - seg->hit_distance = hit->distance; - break; - } - default: FATAL("Unreachable code.\n"); break; + case SHAPE_MESH: { + d3_set_f3(seg->hit_normal, hit->normal); + /* use raytraced distance to fill hit_pos */ + d3_add(seg->hit_pos, seg->org, d3_muld(seg->hit_pos, seg->dir, hit->distance)); + seg->hit_distance = hit->distance; + break; + } + case SHAPE_PUNCHED: { + /* hits on quadrics must be recomputed more accurately */ + double org_local[3], hit_pos_local[3], dir_local[3]; + double R[9]; /* Rotation matrix */ + double T[3]; /* Translation vector */ + double R_invtrans[9]; /* Inverse transpose rotation matrix */ + double T_inv[3]; /* Inverse of the translation vector */ + int valid; + + if(d33_is_identity(shape->quadric.transform)) { + d33_set(R, inst->transform); + d3_set (T, inst->transform+9); + } else { + d33_muld33(R, shape->quadric.transform, inst->transform); + d33_muld3 (T, shape->quadric.transform, inst->transform+9); + } + d33_invtrans(R_invtrans, R); + d3_minus(T_inv, T); + + /* get org in local coordinate */ + d3_set(org_local, seg->org); + d3_add(org_local, org_local, T_inv); + d3_muld33(org_local, org_local, R_invtrans); + + /* get dir in local */ + d3_muld33(dir_local, seg->dir, R_invtrans); + /* recompute hit */ + valid = punched_shape_intersect_local(shape, org_local, dir_local, + hit->distance, hit_pos_local, seg->hit_normal, &seg->hit_distance); + if (!valid) return 1; + /* transform point to world */ + d33_muld3(seg->hit_pos, R, hit_pos_local); + d3_add(seg->hit_pos, seg->hit_pos, T); + /* transform normal to world */ + d33_muld3(seg->hit_normal, R_invtrans, seg->hit_normal); + break; + } + default: FATAL("Unreachable code.\n"); break; } d3_normalize(seg->hit_normal, seg->hit_normal); diff --git a/src/ssol_shape.c b/src/ssol_shape.c @@ -18,10 +18,12 @@ #include "ssol_device_c.h" #include "ssol_shape_c.h" -#include <rsys/double3.h> #include <rsys/double2.h> +#include <rsys/double3.h> +#include <rsys/double33.h> #include <rsys/dynamic_array_double.h> #include <rsys/dynamic_array_size_t.h> +#include <rsys/float3.h> #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> #include <rsys/rsys.h> @@ -40,6 +42,7 @@ struct quadric_mesh_context { const double* coords; const size_t* ids; double focal; /* Use by parabol and parabolic cylinder quadrics */ + const double* transform; /* 3x4 column major matrix */ }; /******************************************************************************* @@ -171,10 +174,17 @@ quadric_mesh_plane_get_pos(const unsigned ivert, float pos[3], void* ctx) { const size_t i = ivert*2/*#coords per vertex*/; const struct quadric_mesh_context* msh = ctx; + double p[3]; /* Temporary quadric space position */ ASSERT(pos && ctx); - pos[0] = (float)msh->coords[i+0]; - pos[1] = (float)msh->coords[i+1]; - pos[2] = 0.f; + p[0] = (float)msh->coords[i+0]; + p[1] = (float)msh->coords[i+1]; + p[2] = 0.f; + + /* Transform the position in object space */ + d33_muld3(p, msh->transform, p); + d3_add(p, p, msh->transform+9); + + f3_set_d3(pos, p); } static void @@ -182,13 +192,17 @@ quadric_mesh_parabol_get_pos(const unsigned ivert, float pos[3], void* ctx) { const size_t i = ivert*2/*#coords per vertex*/; const struct quadric_mesh_context* msh = ctx; - double x, y; + double p[3]; /* Temporary quadric space position */ ASSERT(pos && ctx); - x = msh->coords[i+0]; - y = msh->coords[i+1]; - pos[0] = (float)x; - pos[1] = (float)y; - pos[2] = (float)((x*x + y*y) / (4.0*msh->focal)); + p[0] = msh->coords[i+0]; + p[1] = msh->coords[i+1]; + p[2] = (p[0]*p[0] + p[1]*p[1]) / (4.0*msh->focal); + + /* Transform the position in object space */ + d33_muld3(p, msh->transform, p); + d3_add(p, p, msh->transform+9); + + f3_set_d3(pos, p); } static void @@ -197,13 +211,17 @@ quadric_mesh_parabolic_cylinder_get_pos { const size_t i = ivert*2/*#coords per vertex*/; const struct quadric_mesh_context* msh = ctx; - double x, y; + double p[3]; /* Temporary quadric space position */ ASSERT(pos && ctx); - x = msh->coords[i+0]; - y = msh->coords[i+1]; - pos[0] = (float)x; - pos[1] = (float)y; - pos[2] = (float)((y*y) / (4.0*msh->focal)); + p[0] = msh->coords[i+0]; + p[1] = msh->coords[i+1]; + p[2] = ((p[1]*p[1]) / (4.0*msh->focal)); + + /* Transform the position in object space */ + d33_muld3(p, msh->transform, p); + d3_add(p, p, msh->transform+9); + + f3_set_d3(pos, p); } static FINLINE int @@ -425,6 +443,7 @@ quadric_setup_s3d_shape_rt ntris = (unsigned)darray_size_t_size_get(ids) / 3/*#ids per triangle*/; ctx.coords = darray_double_cdata_get(coords); ctx.ids = darray_size_t_cdata_get(ids); + ctx.transform = quadric->transform; vdata.usage = S3D_POSITION; vdata.type = S3D_FLOAT3; @@ -538,9 +557,9 @@ inject_same_sign(const double x, const double src) return ucast.d; } -/* solve a 2nd degree equation - hint is used to select among the 2 solutions (if applies) - the selected solution is then the closest to hint positive value */ +/* Solve a 2nd degree equation + * hint is used to select among the 2 solutions (if applies) + * the selected solution is then the closest to hint positive value */ static int quadric_solve_second (const double a, @@ -551,11 +570,11 @@ quadric_solve_second { ASSERT(dist); if (a != 0) { - /* standard case: 2nd degree */ + /* Standard case: 2nd degree */ const double delta = b * b - 4 * a * c; if (delta > 0) { const double sqrt_delta = sqrt(delta); - /* precise formula */ + /* Precise formula */ const double t1 = (-b - inject_same_sign(sqrt_delta, b)) / (2 * b); const double t2 = c / (a * t1); if (t1 < 0 && t2 < 0) return 0; /* no positive solution */ @@ -567,7 +586,7 @@ quadric_solve_second *dist = t1; /* t1 is the only positive solution */ return 1; } - /* both t1 and t2 are positive: choose the closest value to hint */ + /* Both t1 and t2 are positive: choose the closest value to hint */ *dist = fabs(t1 - hint) < fabs(t2 - hint) ? t1 : t2; return 1; } else if (delta == 0) { diff --git a/src/ssol_solver.c b/src/ssol_solver.c @@ -502,21 +502,36 @@ sample_starting_point(struct realisation* rs) break; } case SHAPE_PUNCHED: { - const double* transform = start->instance->transform; - double tr[9], pos_local[3]; + struct ssol_instance* inst = start->instance; + double pos_local[3]; + double R[9]; /* Rotation matrix */ + double T[3]; /* Translation vector */ + double R_invtrans[9]; /* Inverse transpose rotation matrix */ + double T_inv[3]; /* Inverse of the translation vector */ + + if(d33_is_identity(shape->quadric.transform)) { + d33_set(R, inst->transform); + d3_set (T, inst->transform+9); + } else { + d33_muld33(R, shape->quadric.transform, inst->transform); + d33_muld3 (T, shape->quadric.transform, inst->transform+9); + } + d33_invtrans(R_invtrans, R); + d3_minus(T_inv, T); + /* project the sampled point on the quadric */ - d33_inverse(tr, transform); - d3_sub(pos_local, start->pos, transform + 9); - d33_muld3(pos_local, tr, pos_local); + d3_set(pos_local, start->pos); + d3_add(pos_local, pos_local, T_inv); + d3_muld33(pos_local, pos_local, R_invtrans); + punched_shape_set_z_local(shape, pos_local); /* transform point to world */ - d33_muld3(start->pos, transform, pos_local); - d3_add(start->pos, transform + 9, start->pos); + d33_muld3(start->pos, R, pos_local); + d3_add(start->pos, start->pos, T); /* compute exact normal on the instance */ punched_shape_set_normal_local(shape, pos_local, start->rt_normal); /* transform normal to world */ - d33_invtrans(tr, transform); - d33_muld3(start->rt_normal, tr, start->rt_normal); + d33_muld3(start->rt_normal, R_invtrans, start->rt_normal); break; } default: FATAL("Unreachable code.\n"); break; diff --git a/src/test_ssol_solver2.c b/src/test_ssol_solver2.c @@ -56,7 +56,7 @@ main(int argc, char** argv) struct ssol_vertex_data attribs[1]; struct ssol_shape* quad_square; struct ssol_carving carving; - struct ssol_quadric quadric; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; struct ssol_punched_surface punched; struct ssol_material* m_mtl; struct ssol_material* v_mtl; diff --git a/src/test_ssol_solver2b.c b/src/test_ssol_solver2b.c @@ -56,7 +56,7 @@ main(int argc, char** argv) struct ssol_shape* quad_square; struct ssol_shape* quad_rect; struct ssol_carving carving; - struct ssol_quadric quadric; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; struct ssol_punched_surface punched; struct ssol_material* m_mtl; struct ssol_material* v_mtl; diff --git a/src/test_ssol_solver3.c b/src/test_ssol_solver3.c @@ -50,7 +50,7 @@ main(int argc, char** argv) struct ssol_vertex_data attribs[1]; struct ssol_shape* quad_square; struct ssol_carving carving; - struct ssol_quadric quadric; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; struct ssol_punched_surface punched; struct ssol_material* m_mtl; struct ssol_material* v_mtl; diff --git a/src/test_ssol_solver3N.c b/src/test_ssol_solver3N.c @@ -94,7 +94,7 @@ main(int argc, char** argv) struct ssol_vertex_data attribs[1]; struct ssol_shape* quad_square; struct ssol_carving carving; - struct ssol_quadric quadric; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; struct ssol_punched_surface punched; struct ssol_material* m_mtl; struct ssol_material* v_mtl; diff --git a/src/test_ssol_solver4.c b/src/test_ssol_solver4.c @@ -50,7 +50,7 @@ main(int argc, char** argv) struct ssol_vertex_data attribs[1]; struct ssol_shape* quad_square; struct ssol_carving carving; - struct ssol_quadric quadric; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; struct ssol_punched_surface punched; struct ssol_material* m_mtl; struct ssol_material* v_mtl; diff --git a/src/test_ssol_solver5.c b/src/test_ssol_solver5.c @@ -50,7 +50,7 @@ main(int argc, char** argv) struct ssol_vertex_data attribs[1]; struct ssol_shape* quad_square; struct ssol_carving carving; - struct ssol_quadric quadric; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; struct ssol_punched_surface punched; struct ssol_material* m_mtl; struct ssol_material* v_mtl;