/****************************************************************************** * Module: zbump.cpp * Version: 1 * Created: 20-Jun-05 * Author: This file was generated by the XSI shader wizard v1.0 * * This file contains the definition for zbump. * Description: * ******************************************************************************/ #include #include #include "zbump.h" // state saving preprocessor macros from S. Januzzo, thanks! #define _DECL_STATE_VARS \ miVector saveme_saveme_point; \ miVector saveme_saveme_dir; \ miVector saveme_saveme_normal; \ miVector saveme_saveme_normal_geom; \ double saveme_saveme_dist; \ miScalar saveme_saveme_dot_nd; \ void *saveme_saveme_pri; \ void *saveme_saveme_cache; \ miVector *saveme_saveme_tex_list #define _SAVE_STATE( s ) \ saveme_saveme_point = s->point; \ saveme_saveme_dir = s->dir; \ saveme_saveme_normal = s->normal; \ saveme_saveme_normal_geom = s->normal_geom; \ saveme_saveme_dist = s->dist; \ saveme_saveme_dot_nd = state->dot_nd; \ saveme_saveme_pri = s->pri; \ saveme_saveme_cache = s->cache; \ saveme_saveme_tex_list = s->tex_list #define _RESTORE_STATE( s ) \ s->point = saveme_saveme_point; \ s->dir = saveme_saveme_dir; \ s->normal = saveme_saveme_normal; \ s->normal_geom = saveme_saveme_normal_geom; \ s->dist = saveme_saveme_dist; \ s->dot_nd = saveme_saveme_dot_nd; \ s->pri = saveme_saveme_pri; \ s->cache = saveme_saveme_cache; \ s->tex_list = saveme_saveme_tex_list DLLEXPORT int zbump_version(void) { return 1; } /* * Shader initialization function */ DLLEXPORT void zbump_init( miState * state, zbump_params * in_pParams, miBoolean *inst_req) { if(!in_pParams) { // Set this to miTRUE if you want instance specific initialization. *inst_req = miFALSE; /* add global init code here */ } else { /* add instance-specific init code here */ } } DLLEXPORT miBoolean zbump ( miVector * out_pResult, miState * state, zbump_params * in_pParams ) { miBoolean trace_on = state->options->trace; if ( !trace_on ) // raytracing turned off so can't use zbump algorithm, check for passthrough { miVector passthrough = *mi_eval_vector(&in_pParams->passthrough); if ( passthrough.x == 0.0f && passthrough.y == 0.0f && passthrough.z == 0.0f ) // nothing attached, or bad result from { //passthrough shader so just return unchanged normal *out_pResult = state->normal; return miTRUE; } else // passthrough providing result { *out_pResult = passthrough; return miTRUE; } } miScalar step = *mi_eval_scalar(&in_pParams->m_step); //read inputs miScalar factor = *mi_eval_scalar(&in_pParams->m_factor); miScalar factor2 = *mi_eval_scalar(&in_pParams->m_factor2); miBoolean secondbump = *mi_eval_boolean(&in_pParams->m_secondbump); miVector s; miVector t; miVector basis[4]; miVector dsppt[4], dsppt2[4]; miVector norm = state->normal; miVector nnorm = norm; miVector nnorm2 = norm; miVector ppoint = state->point; miVector dsppoint; miInteger i; miVector probe; miColor input; miScalar dsp; //displacement factor miScalar dsp2[4]; miVector cross_s, cross_t; _DECL_STATE_VARS; _SAVE_STATE(state); miInteger num_textures, k; miBoolean texquery = mi_query(miQ_NUM_TEXTURES, state, miNULLTAG, &num_textures); miVector Texture[MAX_TEX]; for(k = 0; k < num_textures; k++) { Texture[k] = state->tex_list[k]; //store } //set up basis vectors mi_vector_prod(&s,&nnorm,&ppoint); //first basis - arbitrary vector perpendicular to normal (cross prod normal and position) if(mi_vector_norm(&s)==0.0) //if nnorm happens to be parallel to ppoint { ppoint.x += (float)0.01; mi_vector_prod(&s,&nnorm,&ppoint); ppoint = state->point; } mi_vector_prod(&t,&s,&nnorm); //second basis (cross prod normal and first basis) mi_vector_normalize(&s); mi_vector_normalize(&t); basis[0] = s; mi_vector_neg(&s); basis[1] = s; // will move out in 4 directions to probe surface ( + & - each basis vector ) basis[2] = t; mi_vector_neg(&t); basis[3] = t; mi_vector_mul(&nnorm,step); mi_vector_add(&dsppoint,&nnorm,&ppoint); // move up "step" distance away from surface along normal (to "dsppoint") state->pri = 0; // needed to allow for self-intersections by probe rays bool probe_missed = false; for(i=0;i<=3;i++) // one probe for each of 4 directions { nnorm = norm; mi_vector_neg(&nnorm); mi_vector_mul(&basis[i],step); mi_vector_add(&probe,&dsppoint,&basis[i]); // now move out along basis direction (to "probe" point) mi_flush_cache(state); if(mi_trace_probe(state,&nnorm,&probe)) // drop a probe ray back to the surface along negative normal direction { if ( state->child->instance != state->instance ) // make sure probe hits same object ( ? should use "label" ) { probe_missed = true; break; } state->point = state->child->point; // set point to probe intersection point for(k = 0; k < num_textures; k++) { state->tex_list[k] = state->child->tex_list[k]; } input = *mi_eval_color(&in_pParams->m_input); // get color data of input at probe intersection point dsp = factor*((input.r + input.g + input.b)/3-0.5f); // translate this to a scalar nnorm = norm; mi_vector_mul(&nnorm,dsp); mi_vector_add(&dsppt[i],&nnorm,&probe); // creat a set of 4 displaced points from these values if(secondbump) { input = *mi_eval_color(&in_pParams->m_input2); dsp2[i] = factor2*((input.r + input.g + input.b)/3-0.5f); } } else // probe ray hit nothing { probe_missed = true; break; } } if (probe_missed) // just return unchanged normal { _RESTORE_STATE(state); // restore for(k = 0; k < num_textures; k++) { state->tex_list[k] = Texture[k]; //restore } *out_pResult = state->normal; return miTRUE; } mi_vector_sub(&cross_s,&dsppt[0],&dsppt[1]); // use opposite pairs of displaced points to create vectors mi_vector_sub(&cross_t,&dsppt[2],&dsppt[3]); mi_vector_prod(&nnorm,&cross_s,&cross_t); // and use their cross product to get the new normal vector mi_vector_normalize(&nnorm); if(mi_vector_dot(&nnorm,&norm)<0) mi_vector_neg(&nnorm); if(secondbump) { for(i=0;i<=3;i++) { nnorm2 = nnorm; mi_vector_mul(&nnorm2,dsp2[i]); mi_vector_add(&dsppt2[i],&nnorm2,&dsppt[i]); } mi_vector_sub(&cross_s,&dsppt2[0],&dsppt2[1]); mi_vector_sub(&cross_t,&dsppt2[2],&dsppt2[3]); mi_vector_prod(&nnorm2,&cross_s,&cross_t); mi_vector_normalize(&nnorm2); if(mi_vector_dot(&nnorm2,&nnorm)<0) mi_vector_neg(&nnorm2); nnorm = nnorm2; } _RESTORE_STATE(state); // restore for(k = 0; k < num_textures; k++) { state->tex_list[k] = Texture[k]; //restore } *out_pResult = nnorm; return miTRUE; } /* * Shader cleanup function */ DLLEXPORT void zbump_exit( miState * state, zbump_params * in_pParams) { if(!in_pParams) { /* add global exit code here */ } else { /* add instance-specific exit code here */ } }