Blender V2.61 - r43446

osl_shader.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "kernel_compat_cpu.h"
00020 #include "kernel_types.h"
00021 #include "kernel_globals.h"
00022 #include "kernel_object.h"
00023 
00024 #include "osl_services.h"
00025 #include "osl_shader.h"
00026 
00027 #include "util_foreach.h"
00028 
00029 #include <OSL/oslexec.h>
00030 #include <oslexec_pvt.h>
00031 
00032 CCL_NAMESPACE_BEGIN
00033 
00034 tls_ptr(OSLGlobals::ThreadData, OSLGlobals::thread_data);
00035 
00036 /* Threads */
00037 
00038 void OSLShader::thread_init(KernelGlobals *kg)
00039 {
00040     OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
00041 
00042     OSLGlobals::ThreadData *tdata = new OSLGlobals::ThreadData();
00043 
00044     memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
00045     tdata->thread_info = ssi->create_thread_info();
00046 
00047     tls_set(kg->osl.thread_data, tdata);
00048 
00049     ((OSLRenderServices*)ssi->renderer())->thread_init(kg);
00050 }
00051 
00052 void OSLShader::thread_free(KernelGlobals *kg)
00053 {
00054     OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
00055 
00056     OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
00057 
00058     ssi->destroy_thread_info(tdata->thread_info);
00059 
00060     delete tdata;
00061 }
00062 
00063 /* Globals */
00064 
00065 #define TO_VEC3(v) (*(OSL::Vec3*)&(v))
00066 #define TO_COLOR3(v) (*(OSL::Color3*)&(v))
00067 #define TO_FLOAT3(v) make_float3(v[0], v[1], v[2])
00068 
00069 static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
00070     int path_flag, OSL::ShaderGlobals *globals)
00071 {
00072     /* copy from shader data to shader globals */
00073     globals->P = TO_VEC3(sd->P);
00074     globals->dPdx = TO_VEC3(sd->dP.dx);
00075     globals->dPdy = TO_VEC3(sd->dP.dy);
00076     globals->I = TO_VEC3(sd->I);
00077     globals->dIdx = TO_VEC3(sd->dI.dx);
00078     globals->dIdy = TO_VEC3(sd->dI.dy);
00079     globals->N = TO_VEC3(sd->N);
00080     globals->Ng = TO_VEC3(sd->Ng);
00081     globals->u = sd->u;
00082     globals->dudx = sd->du.dx;
00083     globals->dudy = sd->du.dy;
00084     globals->v = sd->v;
00085     globals->dvdx = sd->dv.dx;
00086     globals->dvdy = sd->dv.dy;
00087     globals->dPdu = TO_VEC3(sd->dPdu);
00088     globals->dPdv = TO_VEC3(sd->dPdv);
00089     globals->surfacearea = (sd->object == ~0)? 1.0f: object_surface_area(kg, sd->object);
00090 
00091     /* booleans */
00092     globals->raytype = path_flag; /* todo: add our own ray types */
00093     globals->backfacing = (sd->flag & SD_BACKFACING);
00094 
00095     /* don't know yet if we need this */
00096     globals->flipHandedness = false;
00097     
00098     /* shader data to be used in services callbacks */
00099     globals->renderstate = sd; 
00100 
00101     /* hacky, we leave it to services to fetch actual object matrix */
00102     globals->shader2common = sd;
00103     globals->object2common = sd;
00104 
00105     /* must be set to NULL before execute */
00106     globals->Ci = NULL;
00107 }
00108 
00109 /* Surface */
00110 
00111 static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
00112     const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
00113 {
00114     /* OSL gives use a closure tree, we flatten it into arrays per
00115      * closure type, for evaluation, sampling, etc later on. */
00116 
00117     if(closure->type == OSL::ClosureColor::COMPONENT) {
00118         OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure;
00119         OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data();
00120 
00121         if(prim) {
00122             ShaderClosure sc;
00123             sc.prim = prim;
00124             sc.weight = weight;
00125 
00126             switch(prim->category()) {
00127                 case ClosurePrimitive::BSDF: {
00128                     if(sd->num_closure == MAX_CLOSURE)
00129                         return;
00130 
00131                     OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)prim;
00132                     ustring scattering = bsdf->scattering();
00133 
00134                     /* no caustics option */
00135                     if(no_glossy && scattering == OSL::Labels::GLOSSY)
00136                         return;
00137 
00138                     /* sample weight */
00139                     float albedo = bsdf->albedo(TO_VEC3(sd->I));
00140                     float sample_weight = fabsf(average(weight))*albedo;
00141                     float sample_sum = sd->osl_closure.bsdf_sample_sum + sample_weight;
00142 
00143                     sc.sample_weight = sample_weight;
00144                     sc.type = CLOSURE_BSDF_ID;
00145                     sd->osl_closure.bsdf_sample_sum = sample_sum;
00146 
00147                     /* scattering flags */
00148                     if(scattering == OSL::Labels::DIFFUSE)
00149                         sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL;
00150                     else if(scattering == OSL::Labels::GLOSSY)
00151                         sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
00152                     else
00153                         sd->flag |= SD_BSDF;
00154 
00155                     /* add */
00156                     sd->closure[sd->num_closure++] = sc;
00157                     break;
00158                 }
00159                 case ClosurePrimitive::Emissive: {
00160                     if(sd->num_closure == MAX_CLOSURE)
00161                         return;
00162 
00163                     /* sample weight */
00164                     float sample_weight = fabsf(average(weight));
00165                     float sample_sum = sd->osl_closure.emissive_sample_sum + sample_weight;
00166 
00167                     sc.sample_weight = sample_weight;
00168                     sc.type = CLOSURE_EMISSION_ID;
00169                     sd->osl_closure.emissive_sample_sum = sample_sum;
00170 
00171                     /* flag */
00172                     sd->flag |= SD_EMISSION;
00173 
00174                     sd->closure[sd->num_closure++] = sc;
00175                     break;
00176                 }
00177                 case ClosurePrimitive::Holdout:
00178                     if(sd->num_closure == MAX_CLOSURE)
00179                         return;
00180 
00181                     sc.sample_weight = 0.0f;
00182                     sc.type = CLOSURE_HOLDOUT_ID;
00183                     sd->flag |= SD_HOLDOUT;
00184                     sd->closure[sd->num_closure++] = sc;
00185                     break;
00186                 case ClosurePrimitive::BSSRDF:
00187                 case ClosurePrimitive::Debug:
00188                     break; /* not implemented */
00189                 case ClosurePrimitive::Background:
00190                 case ClosurePrimitive::Volume:
00191                     break; /* not relevant */
00192             }
00193         }
00194     }
00195     else if(closure->type == OSL::ClosureColor::MUL) {
00196         OSL::ClosureMul *mul = (OSL::ClosureMul*)closure;
00197         flatten_surface_closure_tree(sd, no_glossy, mul->closure, TO_FLOAT3(mul->weight) * weight);
00198     }
00199     else if(closure->type == OSL::ClosureColor::ADD) {
00200         OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure;
00201         flatten_surface_closure_tree(sd, no_glossy, add->closureA, weight);
00202         flatten_surface_closure_tree(sd, no_glossy, add->closureB, weight);
00203     }
00204 }
00205 
00206 void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
00207 {
00208     /* gather pointers */
00209     OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
00210     OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
00211     OSL::ShaderGlobals *globals = &tdata->globals;
00212     OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
00213 
00214     /* setup shader globals from shader data */
00215     sd->osl_ctx = ctx;
00216     shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
00217 
00218     /* execute shader for this point */
00219     int shader = sd->shader & SHADER_MASK;
00220 
00221     if(kg->osl.surface_state[shader])
00222         ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.surface_state[shader]), *globals);
00223 
00224     /* flatten closure tree */
00225     sd->num_closure = 0;
00226     sd->randb_closure = randb;
00227 
00228     if(globals->Ci) {
00229         bool no_glossy = (path_flag & PATH_RAY_DIFFUSE) && kernel_data.integrator.no_caustics;
00230         flatten_surface_closure_tree(sd, no_glossy, globals->Ci);
00231     }
00232 }
00233 
00234 /* Background */
00235 
00236 static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
00237 {
00238     /* OSL gives use a closure tree, if we are shading for background there
00239      * is only one supported closure type at the moment, which has no evaluation
00240      * functions, so we just sum the weights */
00241 
00242     if(closure->type == OSL::ClosureColor::COMPONENT) {
00243         OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure;
00244         OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data();
00245 
00246         if(prim && prim->category() == OSL::ClosurePrimitive::Background)
00247             return make_float3(1.0f, 1.0f, 1.0f);
00248     }
00249     else if(closure->type == OSL::ClosureColor::MUL) {
00250         OSL::ClosureMul *mul = (OSL::ClosureMul*)closure;
00251 
00252         return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
00253     }
00254     else if(closure->type == OSL::ClosureColor::ADD) {
00255         OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure;
00256 
00257         return flatten_background_closure_tree(add->closureA) +
00258             flatten_background_closure_tree(add->closureB);
00259     }
00260 
00261     return make_float3(0.0f, 0.0f, 0.0f);
00262 }
00263 
00264 float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
00265 {
00266     /* gather pointers */
00267     OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
00268     OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
00269     OSL::ShaderGlobals *globals = &tdata->globals;
00270     OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
00271 
00272     /* setup shader globals from shader data */
00273     sd->osl_ctx = ctx;
00274     shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
00275 
00276     /* execute shader for this point */
00277     if(kg->osl.background_state)
00278         ctx->execute(OSL::pvt::ShadUseSurface, *kg->osl.background_state, *globals);
00279 
00280     /* return background color immediately */
00281     if(globals->Ci)
00282         return flatten_background_closure_tree(globals->Ci);
00283 
00284     return make_float3(0.0f, 0.0f, 0.0f);
00285 }
00286 
00287 /* Volume */
00288 
00289 static void flatten_volume_closure_tree(ShaderData *sd,
00290     const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
00291 {
00292     /* OSL gives use a closure tree, we flatten it into arrays per
00293      * closure type, for evaluation, sampling, etc later on. */
00294 
00295     if(closure->type == OSL::ClosureColor::COMPONENT) {
00296         OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure;
00297         OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data();
00298 
00299         if(prim) {
00300             ShaderClosure sc;
00301             sc.prim = prim;
00302             sc.weight = weight;
00303 
00304             switch(prim->category()) {
00305                 case ClosurePrimitive::Volume: {
00306                     if(sd->num_closure == MAX_CLOSURE)
00307                         return;
00308 
00309                     /* sample weight */
00310                     float sample_weight = fabsf(average(weight));
00311                     float sample_sum = sd->osl_closure.volume_sample_sum + sample_weight;
00312 
00313                     sc.sample_weight = sample_weight;
00314                     sc.type = CLOSURE_VOLUME_ID;
00315                     sd->osl_closure.volume_sample_sum = sample_sum;
00316 
00317                     /* add */
00318                     sd->closure[sd->num_closure++] = sc;
00319                     break;
00320                 }
00321                 case ClosurePrimitive::Holdout:
00322                 case ClosurePrimitive::Debug:
00323                     break; /* not implemented */
00324                 case ClosurePrimitive::Background:
00325                 case ClosurePrimitive::BSDF:
00326                 case ClosurePrimitive::Emissive:
00327                 case ClosurePrimitive::BSSRDF:
00328                     break; /* not relevant */
00329             }
00330         }
00331     }
00332     else if(closure->type == OSL::ClosureColor::MUL) {
00333         OSL::ClosureMul *mul = (OSL::ClosureMul*)closure;
00334         flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
00335     }
00336     else if(closure->type == OSL::ClosureColor::ADD) {
00337         OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure;
00338         flatten_volume_closure_tree(sd, add->closureA, weight);
00339         flatten_volume_closure_tree(sd, add->closureB, weight);
00340     }
00341 }
00342 
00343 void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
00344 {
00345     /* gather pointers */
00346     OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
00347     OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
00348     OSL::ShaderGlobals *globals = &tdata->globals;
00349     OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
00350 
00351     /* setup shader globals from shader data */
00352     sd->osl_ctx = ctx;
00353     shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
00354 
00355     /* execute shader */
00356     int shader = sd->shader & SHADER_MASK;
00357 
00358     if(kg->osl.volume_state[shader])
00359         ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.volume_state[shader]), *globals);
00360 
00361     /* retrieve resulting closures */
00362     sd->osl_closure.volume_sample_sum = 0.0f;
00363     sd->osl_closure.num_volume = 0;
00364     sd->osl_closure.randb = randb;
00365 
00366     if(globals->Ci)
00367         flatten_volume_closure_tree(sd, globals->Ci);
00368 }
00369 
00370 /* Displacement */
00371 
00372 void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
00373 {
00374     /* gather pointers */
00375     OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
00376     OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
00377     OSL::ShaderGlobals *globals = &tdata->globals;
00378     OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
00379 
00380     /* setup shader globals from shader data */
00381     sd->osl_ctx = ctx;
00382     shaderdata_to_shaderglobals(kg, sd, 0, globals);
00383 
00384     /* execute shader */
00385     int shader = sd->shader & SHADER_MASK;
00386 
00387     if(kg->osl.displacement_state[shader])
00388         ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.displacement_state[shader]), *globals);
00389 
00390     /* get back position */
00391     sd->P = TO_FLOAT3(globals->P);
00392 }
00393 
00394 void OSLShader::release(KernelGlobals *kg, const ShaderData *sd)
00395 {
00396     OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
00397     OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
00398 
00399     ssi->release_context((OSL::pvt::ShadingContext*)sd->osl_ctx, tdata->thread_info);
00400 }
00401 
00402 /* BSDF Closure */
00403 
00404 int OSLShader::bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
00405 {
00406     OSL::BSDFClosure *sample_bsdf = (OSL::BSDFClosure*)sc->prim;
00407     int label = LABEL_NONE;
00408 
00409     pdf = 0.0f;
00410 
00411     /* sample BSDF closure */
00412     ustring ulabel;
00413 
00414     ulabel = sample_bsdf->sample(TO_VEC3(sd->Ng),
00415         TO_VEC3(sd->I), TO_VEC3(sd->dI.dx), TO_VEC3(sd->dI.dy),
00416         randu, randv,
00417         TO_VEC3(omega_in), TO_VEC3(domega_in.dx), TO_VEC3(domega_in.dy),
00418         pdf, TO_COLOR3(eval));
00419 
00420     /* convert OSL label */
00421     if(ulabel == OSL::Labels::REFLECT)
00422         label = LABEL_REFLECT;
00423     else if(ulabel == OSL::Labels::TRANSMIT)
00424         label = LABEL_TRANSMIT;
00425     else
00426         return LABEL_NONE; /* sampling failed */
00427 
00428     /* convert scattering to our bitflag label */
00429     ustring uscattering = sample_bsdf->scattering();
00430 
00431     if(uscattering == OSL::Labels::DIFFUSE)
00432         label |= LABEL_DIFFUSE;
00433     else if(uscattering == OSL::Labels::GLOSSY)
00434         label |= LABEL_GLOSSY;
00435     else if(uscattering == OSL::Labels::SINGULAR)
00436         label |= LABEL_SINGULAR;
00437     else
00438         label |= LABEL_TRANSPARENT;
00439 
00440     return label;
00441 }
00442 
00443 float3 OSLShader::bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3& omega_in, float& pdf)
00444 {
00445     OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)sc->prim;
00446     OSL::Color3 bsdf_eval;
00447 
00448     if(dot(sd->Ng, omega_in) >= 0.0f)
00449         bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf);
00450     else
00451         bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), pdf);
00452     
00453     return TO_FLOAT3(bsdf_eval);
00454 }
00455 
00456 /* Emissive Closure */
00457 
00458 float3 OSLShader::emissive_eval(const ShaderData *sd, const ShaderClosure *sc)
00459 {
00460     OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)sc->prim;
00461     OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I));
00462     eval += TO_FLOAT3(emissive_eval);
00463 
00464     return eval;
00465 }
00466 
00467 /* Volume Closure */
00468 
00469 float3 OSLShader::volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
00470 {
00471     OSL::VolumeClosure *volume = (OSL::VolumeClosure*)sc->prim;
00472     OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out));
00473     return TO_FLOAT3(volume_eval)*sc->weight;
00474 }
00475 
00476 CCL_NAMESPACE_END
00477