465 lines
9.8 KiB
C
465 lines
9.8 KiB
C
/*
|
|
* Copyright 2011, Blender Foundation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/*
|
|
* ShaderData, used in four steps:
|
|
*
|
|
* Setup from incoming ray, sampled position and background.
|
|
* Execute for surface, volume or displacement.
|
|
* Evaluate one or more closures.
|
|
* Release.
|
|
*
|
|
*/
|
|
|
|
#include "svm/bsdf.h"
|
|
#include "svm/emissive.h"
|
|
#include "svm/volume.h"
|
|
#include "svm/svm_bsdf.h"
|
|
#include "svm/svm.h"
|
|
|
|
#ifdef WITH_OSL
|
|
#include "osl_shader.h"
|
|
#endif
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* ShaderData setup from incoming ray */
|
|
|
|
__device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
|
|
const Intersection *isect, const Ray *ray)
|
|
{
|
|
/* fetch triangle data */
|
|
int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
|
float4 Ns = kernel_tex_fetch(__tri_normal, prim);
|
|
float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
|
|
int shader = __float_as_int(Ns.w);
|
|
|
|
/* vectors */
|
|
sd->P = bvh_triangle_refine(kg, isect, ray);
|
|
sd->Ng = Ng;
|
|
sd->N = Ng;
|
|
sd->I = -ray->D;
|
|
sd->shader = shader;
|
|
sd->flag = 0;
|
|
|
|
/* triangle */
|
|
#ifdef __INSTANCING__
|
|
sd->object = isect->object;
|
|
#endif
|
|
sd->prim = prim;
|
|
#ifdef __UV__
|
|
sd->u = isect->u;
|
|
sd->v = isect->v;
|
|
#endif
|
|
|
|
/* smooth normal */
|
|
if(sd->shader < 0) {
|
|
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
|
|
sd->shader = -sd->shader;
|
|
}
|
|
|
|
#ifdef __DPDU__
|
|
/* dPdu/dPdv */
|
|
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
|
|
#endif
|
|
|
|
#ifdef __INSTANCING__
|
|
if(sd->object != ~0) {
|
|
/* instance transform */
|
|
object_normal_transform(kg, sd->object, &sd->N);
|
|
object_normal_transform(kg, sd->object, &sd->Ng);
|
|
#ifdef __DPDU__
|
|
object_dir_transform(kg, sd->object, &sd->dPdu);
|
|
object_dir_transform(kg, sd->object, &sd->dPdv);
|
|
#endif
|
|
}
|
|
else {
|
|
/* non-instanced object index */
|
|
sd->object = kernel_tex_fetch(__prim_object, isect->prim);
|
|
}
|
|
#endif
|
|
|
|
/* backfacing test */
|
|
bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
|
|
|
|
if(backfacing) {
|
|
sd->flag = SD_BACKFACING;
|
|
sd->Ng = -sd->Ng;
|
|
sd->N = -sd->N;
|
|
#ifdef __DPDU__
|
|
sd->dPdu = -sd->dPdu;
|
|
sd->dPdv = -sd->dPdv;
|
|
#endif
|
|
}
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
/* differentials */
|
|
differential_transfer(&sd->dP, ray->dP, ray->D, ray->dD, sd->Ng, isect->t);
|
|
differential_incoming(&sd->dI, ray->dD);
|
|
differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
|
|
#endif
|
|
}
|
|
|
|
/* ShaderData setup from position sampled on mesh */
|
|
|
|
__device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
|
|
const float3 P, const float3 Ng, const float3 I,
|
|
int shader, int object, int prim, float u, float v)
|
|
{
|
|
/* vectors */
|
|
sd->P = P;
|
|
sd->N = Ng;
|
|
sd->Ng = Ng;
|
|
sd->I = I;
|
|
sd->shader = shader;
|
|
sd->flag = 0;
|
|
|
|
/* primitive */
|
|
#ifdef __INSTANCING__
|
|
sd->object = object;
|
|
#endif
|
|
sd->prim = prim;
|
|
#ifdef __UV__
|
|
sd->u = u;
|
|
sd->v = v;
|
|
#endif
|
|
|
|
/* detect instancing, for non-instanced the object index is -object-1 */
|
|
#ifdef __INSTANCING__
|
|
bool instanced = false;
|
|
|
|
if(sd->prim != ~0) {
|
|
if(sd->object >= 0)
|
|
instanced = true;
|
|
else
|
|
#endif
|
|
sd->object = -sd->object-1;
|
|
#ifdef __INSTANCING__
|
|
}
|
|
#endif
|
|
|
|
/* smooth normal */
|
|
if(sd->shader < 0) {
|
|
sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
|
|
sd->shader = -sd->shader;
|
|
|
|
#ifdef __INSTANCING__
|
|
if(instanced)
|
|
object_normal_transform(kg, sd->object, &sd->N);
|
|
#endif
|
|
}
|
|
|
|
#ifdef __DPDU__
|
|
/* dPdu/dPdv */
|
|
if(sd->prim == ~0) {
|
|
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
|
|
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
|
|
}
|
|
else {
|
|
triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
|
|
|
|
#ifdef __INSTANCING__
|
|
if(instanced) {
|
|
object_dir_transform(kg, sd->object, &sd->dPdu);
|
|
object_dir_transform(kg, sd->object, &sd->dPdv);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/* backfacing test */
|
|
if(sd->prim != ~0) {
|
|
bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
|
|
|
|
if(backfacing) {
|
|
sd->flag = SD_BACKFACING;
|
|
sd->Ng = -sd->Ng;
|
|
sd->N = -sd->N;
|
|
#ifdef __DPDU__
|
|
sd->dPdu = -sd->dPdu;
|
|
sd->dPdv = -sd->dPdv;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
/* no ray differentials here yet */
|
|
sd->dP.dx = make_float3(0.0f, 0.0f, 0.0f);
|
|
sd->dP.dy = make_float3(0.0f, 0.0f, 0.0f);
|
|
sd->dI.dx = make_float3(0.0f, 0.0f, 0.0f);
|
|
sd->dI.dy = make_float3(0.0f, 0.0f, 0.0f);
|
|
sd->du.dx = 0.0f;
|
|
sd->du.dy = 0.0f;
|
|
sd->dv.dx = 0.0f;
|
|
sd->dv.dy = 0.0f;
|
|
#endif
|
|
}
|
|
|
|
/* ShaderData setup for displacement */
|
|
|
|
__device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
|
|
int object, int prim, float u, float v)
|
|
{
|
|
float3 P, Ng, I = make_float3(0.0f, 0.0f, 0.0f);
|
|
int shader;
|
|
|
|
P = triangle_point_MT(kg, prim, u, v);
|
|
Ng = triangle_normal_MT(kg, prim, &shader);
|
|
|
|
/* force smooth shading for displacement */
|
|
if(shader >= 0)
|
|
shader = -shader;
|
|
|
|
/* watch out: no instance transform currently */
|
|
|
|
shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v);
|
|
}
|
|
|
|
/* ShaderData setup from ray into background */
|
|
|
|
__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray)
|
|
{
|
|
/* vectors */
|
|
sd->P = ray->D;
|
|
sd->N = -sd->P;
|
|
sd->Ng = -sd->P;
|
|
sd->I = -sd->P;
|
|
sd->shader = kernel_data.background.shader;
|
|
sd->flag = 0;
|
|
|
|
#ifdef __INSTANCING__
|
|
sd->object = ~0;
|
|
#endif
|
|
sd->prim = ~0;
|
|
#ifdef __UV__
|
|
sd->u = 0.0f;
|
|
sd->v = 0.0f;
|
|
#endif
|
|
|
|
#ifdef __DPDU__
|
|
/* dPdu/dPdv */
|
|
sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
|
|
sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
|
|
#endif
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
/* differentials */
|
|
sd->dP = ray->dD;
|
|
differential_incoming(&sd->dI, sd->dP);
|
|
sd->du.dx = 0.0f;
|
|
sd->du.dy = 0.0f;
|
|
sd->dv.dx = 0.0f;
|
|
sd->dv.dy = 0.0f;
|
|
#endif
|
|
}
|
|
|
|
/* BSDF */
|
|
|
|
__device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
|
|
float randu, float randv, float3 *eval,
|
|
float3 *omega_in, differential3 *domega_in, float *pdf)
|
|
{
|
|
int label;
|
|
|
|
*pdf = 0.0f;
|
|
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use)
|
|
label = OSLShader::bsdf_sample(sd, randu, randv, *eval, *omega_in, *domega_in, *pdf);
|
|
else
|
|
#endif
|
|
label = svm_bsdf_sample(sd, randu, randv, eval, omega_in, domega_in, pdf);
|
|
|
|
return label;
|
|
}
|
|
|
|
__device float3 shader_bsdf_eval(KernelGlobals *kg, const ShaderData *sd,
|
|
const float3 omega_in, float *pdf)
|
|
{
|
|
float3 eval;
|
|
|
|
*pdf = 0.0f;
|
|
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use)
|
|
eval = OSLShader::bsdf_eval(sd, omega_in, *pdf);
|
|
else
|
|
#endif
|
|
eval = svm_bsdf_eval(sd, omega_in, pdf);
|
|
|
|
return eval;
|
|
}
|
|
|
|
__device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
|
|
{
|
|
#ifdef WITH_OSL
|
|
if(!kg->osl.use)
|
|
#endif
|
|
svm_bsdf_blur(sd, roughness);
|
|
}
|
|
|
|
/* Emission */
|
|
|
|
__device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
|
|
{
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use) {
|
|
return OSLShader::emissive_eval(sd);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
return svm_emissive_eval(sd);
|
|
}
|
|
}
|
|
|
|
__device void shader_emissive_sample(KernelGlobals *kg, ShaderData *sd,
|
|
float randu, float randv, float3 *eval, float3 *I, float *pdf)
|
|
{
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use) {
|
|
OSLShader::emissive_sample(sd, randu, randv, eval, I, pdf);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
svm_emissive_sample(sd, randu, randv, eval, I, pdf);
|
|
}
|
|
}
|
|
|
|
/* Surface Evaluation */
|
|
|
|
__device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
|
|
float randb, int path_flag)
|
|
{
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use) {
|
|
OSLShader::eval_surface(kg, sd, randb, path_flag);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef __SVM__
|
|
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, randb, path_flag);
|
|
#else
|
|
sd->svm_closure = CLOSURE_BSDF_DIFFUSE_ID;
|
|
sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f);
|
|
#endif
|
|
|
|
#ifdef __CAUSTICS_TRICKS__
|
|
/* caustic tricks */
|
|
if((path_flag & PATH_RAY_DIFFUSE) && (sd->flag & SD_BSDF_GLOSSY)) {
|
|
if(kernel_data.integrator.no_caustics) {
|
|
sd->flag &= ~(SD_BSDF_GLOSSY|SD_BSDF_HAS_EVAL|SD_EMISSION);
|
|
sd->svm_closure = NBUILTIN_CLOSURES;
|
|
sd->svm_closure_weight = make_float3(0.0f, 0.0f, 0.0f);
|
|
}
|
|
else if(kernel_data.integrator.blur_caustics > 0.0f)
|
|
shader_bsdf_blur(kg, sd, kernel_data.integrator.blur_caustics);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Background Evaluation */
|
|
|
|
__device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
|
|
{
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use) {
|
|
return OSLShader::eval_background(kg, sd, path_flag);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef __SVM__
|
|
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, 0.0f, path_flag);
|
|
#else
|
|
sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f);
|
|
#endif
|
|
|
|
return sd->svm_closure_weight;
|
|
}
|
|
}
|
|
|
|
/* Volume */
|
|
|
|
__device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
|
|
float3 omega_in, float3 omega_out)
|
|
{
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use) {
|
|
OSLShader::volume_eval_phase(sd, omega_in, omega_out);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
return volume_eval_phase(sd, omega_in, omega_out);
|
|
}
|
|
}
|
|
|
|
/* Volume Evaluation */
|
|
|
|
__device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
|
|
float randb, int path_flag)
|
|
{
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use) {
|
|
OSLShader::eval_volume(kg, sd, randb, path_flag);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef __SVM__
|
|
svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, randb, path_flag);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Displacement Evaluation */
|
|
|
|
__device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd)
|
|
{
|
|
/* this will modify sd->P */
|
|
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use) {
|
|
OSLShader::eval_displacement(kg, sd);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
#ifdef __SVM__
|
|
svm_eval_nodes(kg, sd, SHADER_TYPE_DISPLACEMENT, 0.0f, 0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Free ShaderData */
|
|
|
|
__device void shader_release(KernelGlobals *kg, ShaderData *sd)
|
|
{
|
|
#ifdef WITH_OSL
|
|
if(kg->osl.use)
|
|
OSLShader::release(kg, sd);
|
|
#endif
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|
|
|