star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.fr/star-3d.git
Log | Files | Refs | README | LICENSE

commit af4bd70e24d11df5c83fb85bc0612a382ff405b4
parent fed683466778f5706b32676c12cfb7bf71365500
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 18 Jan 2018 13:54:42 +0100

Handle the spherical shapes in s3d_primitive_get_attrib function

Diffstat:
Msrc/s3d_primitive.c | 194++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
1 file changed, 142 insertions(+), 52 deletions(-)

diff --git a/src/s3d_primitive.c b/src/s3d_primitive.c @@ -42,73 +42,36 @@ /******************************************************************************* * Helper functions ******************************************************************************/ -static int -check_primitive(const struct s3d_primitive* prim) -{ - return prim - && prim->geom_id != S3D_INVALID_ID - && prim->prim_id != S3D_INVALID_ID - && prim->shape__ != NULL - && (prim->inst_id != S3D_INVALID_ID || prim->inst__ == NULL); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -s3d_primitive_get_attrib - (const struct s3d_primitive* prim, +static res_T +mesh_get_primitive_attrib + (const struct geometry* geom, + const float* transform, /* Can be NULL => no transform */ + const char flip_surface, + const struct s3d_primitive* prim, const enum s3d_attrib_usage usage, const float uv[2], struct s3d_attrib* attrib) { const uint32_t* ids; - struct geometry* geom_shape = NULL; - const float* transform = NULL; - char flip_surface = 0; float w; res_T res = RES_OK; + ASSERT(geom && geom->type == GEOM_MESH && prim && prim->shape__ == geom); + ASSERT(uv && attrib); - if(!check_primitive(prim) || usage == S3D_ATTRIBS_COUNT__ || !uv || !attrib) - return RES_BAD_ARG; - - /* Unormalized barycentric coordinates */ w = CLAMP(1.f - uv[0] - uv[1], 0.f, 1.f); - if(uv[0] < 0.f || uv[1] < 0.f || uv[0] > 1.f || uv[1] > 1.f - || !eq_epsf(w + uv[0] + uv[1], 1.f, 1.e-3f)) - return RES_BAD_ARG; - - if(prim->inst__ == NULL) { - geom_shape = (struct geometry*)prim->shape__; - flip_surface = geom_shape->flip_surface; - } else { - const struct geometry* geom_inst = (const struct geometry*)prim->inst__; - ASSERT(geom_inst->type == GEOM_INSTANCE); - ASSERT(prim->inst_id == geom_inst->name); - geom_shape = (struct geometry*)prim->shape__; - transform = geom_inst->data.instance->transform; - ASSERT(geom_shape); - flip_surface = geom_inst->flip_surface ^ geom_shape->flip_surface; - } - ASSERT(prim->geom_id == geom_shape->name); - - if(geom_shape->type == GEOM_SPHERE) { /* TODO */ - log_error(geom_shape->dev, "%s: unsupported sphere primitive.\n", FUNC_NAME); - return RES_BAD_ARG; - } /* The mesh haven't the required mesh attrib */ - if(usage != S3D_GEOMETRY_NORMAL && !geom_shape->data.mesh->attribs[usage]) { + if(usage != S3D_GEOMETRY_NORMAL && !geom->data.mesh->attribs[usage]) { res = RES_BAD_ARG; goto error; } /* Out of bound primitive index */ - if(prim->prim_id >= mesh_get_ntris(geom_shape->data.mesh)) { + if(prim->prim_id >= mesh_get_ntris(geom->data.mesh)) { res = RES_BAD_ARG; goto error; } - ids = mesh_get_ids(geom_shape->data.mesh) + prim->prim_id * 3/*#triangle ids*/; + ids = mesh_get_ids(geom->data.mesh) + prim->prim_id * 3/*#triangle ids*/; attrib->usage = usage; if(usage == S3D_POSITION || usage == S3D_GEOMETRY_NORMAL) { @@ -116,7 +79,7 @@ s3d_primitive_get_attrib const float* pos; attrib->type = S3D_FLOAT3; /* Fetch data */ - pos = mesh_get_pos(geom_shape->data.mesh); + pos = mesh_get_pos(geom->data.mesh); v0 = pos + ids[0] * 3; v1 = pos + ids[1] * 3; v2 = pos + ids[2] * 3; @@ -150,10 +113,10 @@ s3d_primitive_get_attrib const float* attr; const float* v0, *v1, *v2; unsigned i, dim; - attrib->type = geom_shape->data.mesh->attribs_type[usage]; + attrib->type = geom->data.mesh->attribs_type[usage]; /* Fetch attrib data */ dim = s3d_type_get_dimension(attrib->type); - attr = mesh_get_attr(geom_shape->data.mesh, usage); + attr = mesh_get_attr(geom->data.mesh, usage); v0 = attr + ids[0] * dim; v1 = attr + ids[1] * dim; v2 = attr + ids[2] * dim; @@ -169,6 +132,133 @@ error: goto exit; } +static res_T +sphere_get_attrib + (const struct geometry* geom, + const float* transform, /* Can be NULL => no transform */ + const char flip_surface, + const struct s3d_primitive* prim, + const enum s3d_attrib_usage usage, + const float uv[2], + struct s3d_attrib* attrib) +{ + res_T res = RES_OK; + double phi, cos_theta, sin_theta; + float P[3]; + float N[3]; + ASSERT(geom && geom->type == GEOM_MESH && prim && prim->shape__ == geom); + ASSERT(uv && attrib); + + /* Only position and geometry normal are valid sphere attribs */ + if(usage != S3D_GEOMETRY_NORMAL || usage != S3D_POSITION) { + res = RES_BAD_ARG; + goto error; + } + + /* Compute the sampled position on the unit sphere that is actually equal to + * the normal at this position. */ + phi = uv[0] * 2*PI; + cos_theta = 1 - 2 * uv[1]; + sin_theta = 2 * sqrtf(uv[1] * (1 - uv[1])); + N[0] = (float)(cos(phi) * sin_theta); + N[1] = (float)(sin(phi) * sin_theta); + N[2] = (float)cos_theta; + + if(usage == S3D_GEOMETRY_NORMAL) { + if(flip_surface) f3_minus(N, N); + if(transform) { /* Transform the normal from local to world space */ + float invtrans[9]; + f33_invtrans(invtrans, transform); + f33_mulf3(attrib->value, invtrans, N); + } + f3_set(attrib->value, N); + } else { + ASSERT(usage == S3D_POSITION); + /* Compute the sampled position in local space */ + f3_mulf(P, N, geom->data.sphere->radius); + f3_add(P, P, geom->data.sphere->pos); + if(transform) { /* Transform the position from local to world space */ + f33_mulf3(P, transform, P); /* Affine */ + f3_add(P, P, transform + 9); /* Linear */ + } + f3_set(attrib->value, P); + } + +exit: + return res; +error: + goto exit; +} + +static int +check_primitive(const struct s3d_primitive* prim) +{ + return prim + && prim->geom_id != S3D_INVALID_ID + && prim->prim_id != S3D_INVALID_ID + && prim->shape__ != NULL + && (prim->inst_id != S3D_INVALID_ID || prim->inst__ == NULL); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +s3d_primitive_get_attrib + (const struct s3d_primitive* prim, + const enum s3d_attrib_usage usage, + const float uv[2], + struct s3d_attrib* attrib) +{ + struct geometry* geom_shape = NULL; + const float* transform = NULL; + char flip_surface = 0; + float w; + res_T res = RES_OK; + + if(!check_primitive(prim) || usage == S3D_ATTRIBS_COUNT__ || !uv || !attrib) { + res = RES_BAD_ARG; + goto error; + } + + /* Unormalized barycentric coordinates */ + w = CLAMP(1.f - uv[0] - uv[1], 0.f, 1.f); + if(uv[0] < 0.f || uv[1] < 0.f || uv[0] > 1.f || uv[1] > 1.f + || !eq_epsf(w + uv[0] + uv[1], 1.f, 1.e-3f)) { + res = RES_BAD_ARG; + goto error; + } + + if(prim->inst__ == NULL) { + geom_shape = (struct geometry*)prim->shape__; + flip_surface = geom_shape->flip_surface; + } else { + const struct geometry* geom_inst = (const struct geometry*)prim->inst__; + ASSERT(geom_inst->type == GEOM_INSTANCE); + ASSERT(prim->inst_id == geom_inst->name); + geom_shape = (struct geometry*)prim->shape__; + transform = geom_inst->data.instance->transform; + ASSERT(geom_shape); + flip_surface = geom_inst->flip_surface ^ geom_shape->flip_surface; + } + ASSERT(prim->geom_id == geom_shape->name); + + if(geom_shape->type == GEOM_SPHERE) { + res = sphere_get_attrib + (geom_shape, transform, flip_surface, prim, usage, uv, attrib); + } else { + ASSERT(geom_shape->type == GEOM_MESH); + res = mesh_get_primitive_attrib + (geom_shape, transform, flip_surface, prim, usage, uv, attrib); + } + if(res != RES_OK) goto error; + +exit: + return res; +error: + goto exit; +} + res_T s3d_primitive_has_attrib (const struct s3d_primitive* prim, @@ -218,7 +308,7 @@ s3d_primitive_sample st[1] = (float)(v * sqrt_u); break; case GEOM_SPHERE: - st[0] = (float)(u * 2*PI); + st[0] = u; st[1] = v; break; default: FATAL("Unreachable code\n"); break;