float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc) { OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure *)sc->prim; OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I)); return TO_FLOAT3(emissive_eval); }
float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf) { OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)sc->prim; OSL::Color3 bsdf_eval; if(dot(sd->Ng, omega_in) >= 0.0f) bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf); else bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf); return TO_FLOAT3(bsdf_eval); }
static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag, OSLThreadData *tdata) { OSL::ShaderGlobals *globals = &tdata->globals; /* copy from shader data to shader globals */ globals->P = TO_VEC3(sd->P); globals->dPdx = TO_VEC3(sd->dP.dx); globals->dPdy = TO_VEC3(sd->dP.dy); globals->I = TO_VEC3(sd->I); globals->dIdx = TO_VEC3(sd->dI.dx); globals->dIdy = TO_VEC3(sd->dI.dy); globals->N = TO_VEC3(sd->N); globals->Ng = TO_VEC3(sd->Ng); globals->u = sd->u; globals->dudx = sd->du.dx; globals->dudy = sd->du.dy; globals->v = sd->v; globals->dvdx = sd->dv.dx; globals->dvdy = sd->dv.dy; globals->dPdu = TO_VEC3(sd->dPdu); globals->dPdv = TO_VEC3(sd->dPdv); globals->surfacearea = (sd->object == OBJECT_NONE) ? 1.0f : object_surface_area(kg, sd->object); globals->time = sd->time; /* booleans */ globals->raytype = path_flag; globals->backfacing = (sd->flag & SD_BACKFACING); /* shader data to be used in services callbacks */ globals->renderstate = sd; /* hacky, we leave it to services to fetch actual object matrix */ globals->shader2common = sd; globals->object2common = sd; /* must be set to NULL before execute */ globals->Ci = NULL; /* clear trace data */ tdata->tracedata.init = false; /* used by renderservices */ sd->osl_globals = kg; sd->osl_path_state = state; }
static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd, int path_flag, OSL::ShaderGlobals *globals) { /* copy from shader data to shader globals */ globals->P = TO_VEC3(sd->P); globals->dPdx = TO_VEC3(sd->dP.dx); globals->dPdy = TO_VEC3(sd->dP.dy); globals->I = TO_VEC3(sd->I); globals->dIdx = TO_VEC3(sd->dI.dx); globals->dIdy = TO_VEC3(sd->dI.dy); globals->N = TO_VEC3(sd->N); globals->Ng = TO_VEC3(sd->Ng); globals->u = sd->u; globals->dudx = sd->du.dx; globals->dudy = sd->du.dy; globals->v = sd->v; globals->dvdx = sd->dv.dx; globals->dvdy = sd->dv.dy; globals->dPdu = TO_VEC3(sd->dPdu); globals->dPdv = TO_VEC3(sd->dPdv); globals->surfacearea = (sd->object == ~0)? 1.0f: object_surface_area(kg, sd->object); /* booleans */ globals->raytype = path_flag; /* todo: add our own ray types */ globals->backfacing = (sd->flag & SD_BACKFACING); /* don't know yet if we need this */ globals->flipHandedness = false; /* shader data to be used in services callbacks */ globals->renderstate = sd; /* hacky, we leave it to services to fetch actual object matrix */ globals->shader2common = sd; globals->object2common = sd; /* must be set to NULL before execute */ globals->Ci = NULL; }
int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf) { OSL::BSDFClosure *sample_bsdf = (OSL::BSDFClosure*)sc->prim; int label = LABEL_NONE; pdf = 0.0f; /* sample BSDF closure */ ustring ulabel; ulabel = sample_bsdf->sample(TO_VEC3(sd->Ng), TO_VEC3(sd->I), TO_VEC3(sd->dI.dx), TO_VEC3(sd->dI.dy), randu, randv, TO_VEC3(omega_in), TO_VEC3(domega_in.dx), TO_VEC3(domega_in.dy), pdf, TO_COLOR3(eval)); /* convert OSL label */ if(ulabel == OSL::Labels::REFLECT) label = LABEL_REFLECT; else if(ulabel == OSL::Labels::TRANSMIT) label = LABEL_TRANSMIT; else return LABEL_NONE; /* sampling failed */ /* convert scattering to our bitflag label */ ustring uscattering = sample_bsdf->scattering(); if(uscattering == OSL::Labels::DIFFUSE) label |= LABEL_DIFFUSE; else if(uscattering == OSL::Labels::GLOSSY) label |= LABEL_GLOSSY; else if(uscattering == OSL::Labels::SINGULAR) label |= LABEL_SINGULAR; else label |= LABEL_TRANSPARENT; return label; }
float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_in, const float3 omega_out) { OSL::VolumeClosure *volume = (OSL::VolumeClosure *)sc->prim; OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out)); return TO_FLOAT3(volume_eval) * sc->weight; }
static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy, const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f)) { /* OSL gives use a closure tree, we flatten it into arrays per * closure type, for evaluation, sampling, etc later on. */ if(closure->type == OSL::ClosureColor::COMPONENT) { OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure; OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data(); if(prim) { ShaderClosure sc; sc.prim = prim; sc.weight = weight; switch(prim->category()) { case ClosurePrimitive::BSDF: { if(sd->num_closure == MAX_CLOSURE) return; OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)prim; ustring scattering = bsdf->scattering(); /* no caustics option */ if(no_glossy && scattering == OSL::Labels::GLOSSY) return; /* sample weight */ float albedo = bsdf->albedo(TO_VEC3(sd->I)); float sample_weight = fabsf(average(weight))*albedo; float sample_sum = sd->osl_closure.bsdf_sample_sum + sample_weight; sc.sample_weight = sample_weight; sc.type = CLOSURE_BSDF_ID; sd->osl_closure.bsdf_sample_sum = sample_sum; /* scattering flags */ if(scattering == OSL::Labels::DIFFUSE) sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL; else if(scattering == OSL::Labels::GLOSSY) sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; else sd->flag |= SD_BSDF; /* add */ sd->closure[sd->num_closure++] = sc; break; } case ClosurePrimitive::Emissive: { if(sd->num_closure == MAX_CLOSURE) return; /* sample weight */ float sample_weight = fabsf(average(weight)); float sample_sum = sd->osl_closure.emissive_sample_sum + sample_weight; sc.sample_weight = sample_weight; sc.type = CLOSURE_EMISSION_ID; sd->osl_closure.emissive_sample_sum = sample_sum; /* flag */ sd->flag |= SD_EMISSION; sd->closure[sd->num_closure++] = sc; break; } case ClosurePrimitive::Holdout: if(sd->num_closure == MAX_CLOSURE) return; sc.sample_weight = 0.0f; sc.type = CLOSURE_HOLDOUT_ID; sd->flag |= SD_HOLDOUT; sd->closure[sd->num_closure++] = sc; break; case ClosurePrimitive::BSSRDF: case ClosurePrimitive::Debug: break; /* not implemented */ case ClosurePrimitive::Background: case ClosurePrimitive::Volume: break; /* not relevant */ } } } else if(closure->type == OSL::ClosureColor::MUL) { OSL::ClosureMul *mul = (OSL::ClosureMul*)closure; flatten_surface_closure_tree(sd, no_glossy, mul->closure, TO_FLOAT3(mul->weight) * weight); } else if(closure->type == OSL::ClosureColor::ADD) { OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure; flatten_surface_closure_tree(sd, no_glossy, add->closureA, weight); flatten_surface_closure_tree(sd, no_glossy, add->closureB, weight); } }
void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state, int path_flag) { /* setup shader globals from shader data */ OSLThreadData *tdata = kg->osl_tdata; shaderdata_to_shaderglobals(kg, sd, state, path_flag, tdata); /* execute shader for this point */ OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss; OSL::ShaderGlobals *globals = &tdata->globals; OSL::ShadingContext *octx = tdata->context; int shader = sd->shader & SHADER_MASK; /* automatic bump shader */ if(kg->osl->bump_state[shader]) { /* save state */ float3 P = sd->P; float3 dPdx = sd->dP.dx; float3 dPdy = sd->dP.dy; /* set state as if undisplaced */ if(sd->flag & SD_HAS_DISPLACEMENT) { float data[9]; bool found = kg->osl->services->get_attribute(sd, true, OSLRenderServices::u_empty, TypeDesc::TypeVector, OSLRenderServices::u_geom_undisplaced, data); (void)found; assert(found); memcpy(&sd->P, data, sizeof(float)*3); memcpy(&sd->dP.dx, data+3, sizeof(float)*3); memcpy(&sd->dP.dy, data+6, sizeof(float)*3); object_position_transform(kg, sd, &sd->P); object_dir_transform(kg, sd, &sd->dP.dx); object_dir_transform(kg, sd, &sd->dP.dy); globals->P = TO_VEC3(sd->P); globals->dPdx = TO_VEC3(sd->dP.dx); globals->dPdy = TO_VEC3(sd->dP.dy); } /* execute bump shader */ ss->execute(octx, *(kg->osl->bump_state[shader]), *globals); /* reset state */ sd->P = P; sd->dP.dx = dPdx; sd->dP.dy = dPdy; globals->P = TO_VEC3(P); globals->dPdx = TO_VEC3(dPdx); globals->dPdy = TO_VEC3(dPdy); } /* surface shader */ if(kg->osl->surface_state[shader]) { ss->execute(octx, *(kg->osl->surface_state[shader]), *globals); } /* flatten closure tree */ if(globals->Ci) flatten_surface_closure_tree(sd, path_flag, globals->Ci); }