/*----------------------------------------------------------------------------- * geofeather.c * * demonstrates how to build a feather object in a geometry shader using hair * primitives, with a callback. * * (C) mental images 2003 *---------------------------------------------------------------------------*/ #include #include /* * geofeather struct. */ struct geofeather { int example; int nbarbs; }; /* * function protoypes. */ DLLEXPORT miBoolean geofeather_cb(miTag tag, void *args); /* * version function. */ DLLEXPORT miInteger geofeather_version( miState *state, struct geofeather *paras, miBoolean *inst_init_req) { return 1; } /* * geofeather shader. */ DLLEXPORT miBoolean geofeather( miTag *result, miState *state, struct geofeather *paras) { miTag tag; miObject *obj = mi_api_object_begin(mi_mem_strdup("geofeather")); mi_api_object_callback(geofeather_cb, (void *)paras); obj->visible = obj->trace = obj->shadow = miTRUE; obj->bbox_min.x = -0.5f; obj->bbox_min.y = 0.0f; obj->bbox_min.z = -0.1f; obj->bbox_max.x = 0.5f; obj->bbox_max.y = 2.0f; obj->bbox_max.z = 0.1f; tag = mi_api_object_end(); mi_geoshader_add_result(result, tag); obj = (miObject *)mi_scene_edit(tag); obj->geo.placeholder_list.type = miOBJECT_HAIR; mi_scene_edit_end(tag); return miTRUE; } /* * geofeather callback. expands placeholder to a full feather object when the * bounding box of the instance is intersected by a ray, or scanline * rendered. */ DLLEXPORT miBoolean geofeather_cb( miTag tag, void *args) { const char *name; miObject *obj; miHair_list *hair; miScalar *sarray; miGeoIndex *harray; struct geofeather *paras = (struct geofeather *)args; int i = 0; int h; int hcount = 41; /* when using the nbarbs parameter, instead of default here of 41 ... */ /* int hcount = paras->nbarbs; */ name = mi_api_tag_lookup(tag); mi_api_incremental(miTRUE); obj = mi_api_object_begin(mi_mem_strdup(name)); obj->visible = obj->trace = obj->shadow = miTRUE; hair = mi_api_hair_begin(); hair->approx = 5; hair->degree = 3; /* cubic */ mi_api_hair_info(0, 'r', 1); /* per-hair radius */ mi_api_hair_info(1, 't', 4); /* per-vertex textures (4) */ mi_api_hair_info(1, 'm', 3); /* per-vertex motion vector */ /* here we add the geometry data. in a real program, this would be a very clever part. i just use numbers from a sample mi file i have. */ sarray = mi_api_hair_scalars_begin(41*(hcount*2+1)); i = 0; /* hair 1 is spine of feather */ /* per-hair data for hair 1, here just the radius. */ sarray[i++] = 0.01f; /* hair 1 control points 1-4, incuding per-vertex data. */ sarray[i++] = 0.0f; sarray[i++] = 0.0f; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 1.0f; sarray[i++] = 1.0f; sarray[i++] = 1.0f; sarray[i++] = 1.0f; /* texture */ sarray[i++] = 0.0f; sarray[i++] = 0.0f; sarray[i++] = 0.0f; /* motion */ sarray[i++] = 0.0f; sarray[i++] = 0.33f; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 1.0f; sarray[i++] = 1.0f; sarray[i++] = 1.0f; sarray[i++] = 0.9f; /* texture */ sarray[i++] = 0.0f; sarray[i++] = 0.33f; sarray[i++] = 0.0f; /* motion */ sarray[i++] = 0.0f; sarray[i++] = 0.67f; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 1.0f; sarray[i++] = 1.0f; sarray[i++] = 1.0f; sarray[i++] = 0.8f; /* texture */ sarray[i++] = 0.0f; sarray[i++] = 0.67f; sarray[i++] = 0.0f; /* motion */ sarray[i++] = 0.0f; sarray[i++] = 1.0f; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 1.0f; sarray[i++] = 1.0f; sarray[i++] = 1.0f; sarray[i++] = 0.7f; /* texture */ sarray[i++] = 0.0f; sarray[i++] = 1.0f; sarray[i++] = 0.0f; /* motion */ /* iterate for hairs along spine */ for (h=0; h < hcount; h++) { /* per-hair data for hair 2, ie. radius. */ sarray[i++] = 0.006f; /* hair 2, 3, 4, ... control points 1-4, incuding per-vertex data. */ sarray[i++] = 0.01f; sarray[i++] = 0.2f + h * 0.02; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 0.0f; sarray[i++] = 0.6f; sarray[i++] = 0.8f; sarray[i++] = 0.4f; /* texture */ sarray[i++] = 0.01f; sarray[i++] = 0.2f + h * 0.02; sarray[i++] = 0.0f; /* motion */ sarray[i++] = 0.11f; sarray[i++] = 0.3f + h * 0.02; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 0.0f; sarray[i++] = 0.6f; sarray[i++] = 0.8f; sarray[i++] = 0.34f; /* texture */ sarray[i++] = 0.11f; sarray[i++] = 0.3f + h * 0.02; sarray[i++] = 0.0f; /* motion */ sarray[i++] = 0.21f; sarray[i++] = 0.38f + h * 0.02; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 0.0f; sarray[i++] = 0.6f; sarray[i++] = 0.8f; sarray[i++] = 0.26f; /* texture */ sarray[i++] = 0.21f; sarray[i++] = 0.38f + h * 0.02; sarray[i++] = 0.0f; /* motion */ sarray[i++] = 0.31f; sarray[i++] = 0.46f + h * 0.02; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 0.0f; sarray[i++] = 0.4f; sarray[i++] = 0.8f; sarray[i++] = 0.0f; /* texture */ sarray[i++] = 0.31f; sarray[i++] = 0.46f + h * 0.02; sarray[i++] = 0.0f; /* motion */ /* mirrored per-hair data for hair 2, ie. radius. */ sarray[i++] = 0.006f; /* mirror hair 2, 3, 4, ... control points 1-4, incuding per-vertex data. */ sarray[i++] = -0.01f; sarray[i++] = 0.2f + h * 0.02; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 0.0f; sarray[i++] = 0.6f; sarray[i++] = 0.8f; sarray[i++] = 0.4f; /* texture */ sarray[i++] = -0.01f; sarray[i++] = 0.2f + h * 0.02; sarray[i++] = 0.0f; /* motion */ sarray[i++] = -0.11f; sarray[i++] = 0.3f + h * 0.02; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 0.0f; sarray[i++] = 0.6f; sarray[i++] = 0.8f; sarray[i++] = 0.34f; /* texture */ sarray[i++] = -0.11f; sarray[i++] = 0.3f + h * 0.02; sarray[i++] = 0.0f; /* motion */ sarray[i++] = -0.21f; sarray[i++] = 0.38f + h * 0.02; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 0.0f; sarray[i++] = 0.6f; sarray[i++] = 0.8f; sarray[i++] = 0.26f; /* texture */ sarray[i++] = -0.21f; sarray[i++] = 0.38f + h * 0.02; sarray[i++] = 0.0f; /* motion */ sarray[i++] = -0.31f; sarray[i++] = 0.46f + h * 0.02; sarray[i++] = 0.0f; /* vertex */ sarray[i++] = 0.0f; sarray[i++] = 0.4f; sarray[i++] = 0.8f; sarray[i++] = 0.20f; /* texture */ sarray[i++] = -0.31f; sarray[i++] = 0.46f + h * 0.02; sarray[i++] = 0.0f; /* motion */ } mi_api_hair_scalars_end( 41 * (hcount*2 + 1) ); /* there are just the two hairs, ie. three numbers describe the sizes. */ harray = mi_api_hair_hairs_begin(hcount*2 + 1 + 1); for (h=0; h < hcount*2 + 1 + 1; h++) { harray[h] = h * 41; } mi_api_hair_hairs_end(); mi_api_hair_end(); mi_api_object_end(); return miTRUE; } /* * hair texture shader. */ struct feathertex { miColor ambient; /* ambient colour */ }; DLLEXPORT int feathertex_version() { return 1; } DLLEXPORT miBoolean feathertex( miColor *result, miState *state, struct feathertex *paras) { miColor *ambient = mi_eval_color(¶s->ambient); miColor *haircol = (miColor *)&state->tex_list[0]; /* check if we are a shadow shader */ if (state->type == miRAY_SHADOW) { miScalar f, omf; miScalar opacity = haircol->a; miScalar transp = 1 - haircol->a; /* this filters hair color into shadow; term in parens goes rgb->1s, as transp 0->1 * so the transp factor makes rgb go from 0->1 as transp 0->1 */ result->r *= transp * (haircol->r + transp * (1 - haircol->r)); result->g *= transp * (haircol->g + transp * (1 - haircol->g)); result->b *= transp * (haircol->b + transp * (1 - haircol->b)); return miTRUE; } result->r = ambient->r + haircol->r; result->g = ambient->g + haircol->g; result->b = ambient->b + haircol->b; result->a = haircol->a; if (result->a < 0.9999) { miScalar alphafactor; miColor col = {0.0, 0.0, 0.0, 0.0}; mi_trace_transparent(&col, state); alphafactor = 1.0f - result->a; result->r = alphafactor * col.r + result->a * result->r; result->g = alphafactor * col.g + result->a * result->g; result->b = alphafactor * col.b + result->a * result->b; result->a += alphafactor * col.a; } return miTRUE; }