diff options
Diffstat (limited to 'intern/cycles/kernel/svm')
36 files changed, 5697 insertions, 0 deletions
diff --git a/intern/cycles/kernel/svm/bsdf.h b/intern/cycles/kernel/svm/bsdf.h new file mode 100644 index 00000000000..18c1da73fbd --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf.h @@ -0,0 +1,135 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __OSL_BSDF_H__ +#define __OSL_BSDF_H__ + +CCL_NAMESPACE_BEGIN + +__device float fresnel_dielectric(float eta, const float3 N, + const float3 I, float3 *R, float3 *T, +#ifdef __RAY_DIFFERENTIALS__ + const float3 dIdx, const float3 dIdy, + float3 *dRdx, float3 *dRdy, + float3 *dTdx, float3 *dTdy, +#endif + bool *is_inside) +{ + float cos = dot(N, I), neta; + float3 Nn; + // compute reflection + *R =(2 * cos)* N - I; +#ifdef __RAY_DIFFERENTIALS__ + *dRdx = (2 * dot(N, dIdx)) * N - dIdx; + *dRdy = (2 * dot(N, dIdy)) * N - dIdy; +#endif + // check which side of the surface we are on + if(cos > 0) { + // we are on the outside of the surface, going in + neta = 1 / eta; + Nn = N; + *is_inside = false; + } else { + // we are inside the surface, + cos = -cos; + neta = eta; + Nn = -N; + *is_inside = true; + } + *R =(2 * cos)* Nn - I; + float arg = 1 -(neta * neta *(1 -(cos * cos))); + if(arg < 0) { + *T= make_float3(0.0f, 0.0f, 0.0f); +#ifdef __RAY_DIFFERENTIALS__ + *dTdx= make_float3(0.0f, 0.0f, 0.0f); + *dTdy= make_float3(0.0f, 0.0f, 0.0f); +#endif + return 1; // total internal reflection + } else { + float dnp = sqrtf(arg); + float nK =(neta * cos)- dnp; + *T = -(neta * I)+(nK * Nn); +#ifdef __RAY_DIFFERENTIALS__ + *dTdx = -(neta * dIdx) + ((neta - neta * neta * cos / dnp) * dot(dIdx, Nn)) * Nn; + *dTdy = -(neta * dIdy) + ((neta - neta * neta * cos / dnp) * dot(dIdy, Nn)) * Nn; +#endif + // compute Fresnel terms + float cosTheta1 = cos; // N.R + float cosTheta2 = -dot(Nn, *T); + float pPara =(cosTheta1 - eta * cosTheta2)/(cosTheta1 + eta * cosTheta2); + float pPerp =(eta * cosTheta1 - cosTheta2)/(eta * cosTheta1 + cosTheta2); + return 0.5f * (pPara * pPara + pPerp * pPerp); + } +} + +__device float fresnel_dielectric_cos(float cosi, float eta) +{ + // compute fresnel reflectance without explicitly computing + // the refracted direction + float c = fabsf(cosi); + float g = eta * eta - 1 + c * c; + if(g > 0) { + g = sqrtf(g); + float A =(g - c)/(g + c); + float B =(c *(g + c)- 1)/(c *(g - c)+ 1); + return 0.5f * A * A *(1 + B * B); + } + return 1.0f; // TIR(no refracted component) +} + +__device float fresnel_conductor(float cosi, float eta, float k) +{ + float tmp_f = eta * eta + k * k; + float tmp = tmp_f * cosi * cosi; + float Rparl2 =(tmp -(2.0f * eta * cosi)+ 1)/ + (tmp +(2.0f * eta * cosi)+ 1); + float Rperp2 =(tmp_f -(2.0f * eta * cosi)+ cosi * cosi)/ + (tmp_f +(2.0f * eta * cosi)+ cosi * cosi); + return(Rparl2 + Rperp2) * 0.5f; +} + +__device float smooth_step(float edge0, float edge1, float x) +{ + float result; + if(x < edge0) result = 0.0f; + else if(x >= edge1) result = 1.0f; + else { + float t = (x - edge0)/(edge1 - edge0); + result = (3.0f-2.0f*t)*(t*t); + } + return result; +} + +CCL_NAMESPACE_END + +#endif /* __OSL_BSDF_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h new file mode 100644 index 00000000000..e16efebf5bb --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h @@ -0,0 +1,152 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BSDF_ASHIKHMIN_VELVET_H__ +#define __BSDF_ASHIKHMIN_VELVET_H__ + +CCL_NAMESPACE_BEGIN + +typedef struct BsdfAshikhminVelvetClosure { + //float3 m_N; + float m_invsigma2; +} BsdfAshikhminVelvetClosure; + +__device void bsdf_ashikhmin_velvet_setup(ShaderData *sd, ShaderClosure *sc, float sigma) +{ + sigma = fmaxf(sigma, 0.01f); + + float m_invsigma2 = 1.0f/(sigma * sigma); + + sc->type = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; + sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL; + sc->data0 = m_invsigma2; +} + +__device void bsdf_ashikhmin_velvet_blur(ShaderClosure *sc, float roughness) +{ +} + +__device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float m_invsigma2 = sc->data0; + float3 m_N = sd->N; + + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO > 0 && cosNI > 0) { + float3 H = normalize(omega_in + I); + + float cosNH = dot(m_N, H); + float cosHO = fabsf(dot(I, H)); + + float cosNHdivHO = cosNH / cosHO; + cosNHdivHO = fmaxf(cosNHdivHO, 0.00001f); + + float fac1 = 2 * fabsf(cosNHdivHO * cosNO); + float fac2 = 2 * fabsf(cosNHdivHO * cosNI); + + float sinNH2 = 1 - cosNH * cosNH; + float sinNH4 = sinNH2 * sinNH2; + float cotangent2 = (cosNH * cosNH) / sinNH2; + + float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * M_1_PI_F / sinNH4; + float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically + + float out = 0.25f * (D * G) / cosNO; + + *pdf = 0.5f * M_1_PI_F; + return make_float3(out, out, out); + } + return make_float3(0, 0, 0); +} + +__device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_ashikhmin_velvet_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_ashikhmin_velvet_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float m_invsigma2 = sc->data0; + float3 m_N = sd->N; + + // we are viewing the surface from above - send a ray out with uniform + // distribution over the hemisphere + sample_uniform_hemisphere(m_N, randu, randv, omega_in, pdf); + + if(dot(sd->Ng, *omega_in) > 0) { + float3 H = normalize(*omega_in + sd->I); + + float cosNI = dot(m_N, *omega_in); + float cosNO = dot(m_N, sd->I); + float cosNH = dot(m_N, H); + float cosHO = fabsf(dot(sd->I, H)); + + float cosNHdivHO = cosNH / cosHO; + cosNHdivHO = fmaxf(cosNHdivHO, 0.00001f); + + float fac1 = 2 * fabsf(cosNHdivHO * cosNO); + float fac2 = 2 * fabsf(cosNHdivHO * cosNI); + + float sinNH2 = 1 - cosNH * cosNH; + float sinNH4 = sinNH2 * sinNH2; + float cotangent2 = (cosNH * cosNH) / sinNH2; + + float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * M_1_PI_F / sinNH4; + float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically + + float power = 0.25f * (D * G) / cosNO; + + *eval = make_float3(power, power, power); + +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the retroreflective bounce + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + *domega_in_dx *= 125.0f; + *domega_in_dy *= 125.0f; +#endif + } else + *pdf = 0.0f; + + return LABEL_REFLECT|LABEL_DIFFUSE; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_ASHIKHMIN_VELVET_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_diffuse.h b/intern/cycles/kernel/svm/bsdf_diffuse.h new file mode 100644 index 00000000000..e8a002cb84c --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_diffuse.h @@ -0,0 +1,156 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BSDF_DIFFUSE_H__ +#define __BSDF_DIFFUSE_H__ + +CCL_NAMESPACE_BEGIN + +/* DIFFUSE */ + +typedef struct BsdfDiffuseClosure { + //float3 m_N; +} BsdfDiffuseClosure; + +__device void bsdf_diffuse_setup(ShaderData *sd, ShaderClosure *sc) +{ + sc->type = CLOSURE_BSDF_DIFFUSE_ID; + sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL; +} + +__device void bsdf_diffuse_blur(ShaderClosure *sc, float roughness) +{ +} + +__device float3 bsdf_diffuse_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float3 m_N = sd->N; + + float cos_pi = fmaxf(dot(m_N, omega_in), 0.0f) * M_1_PI_F; + *pdf = cos_pi; + return make_float3(cos_pi, cos_pi, cos_pi); +} + +__device float3 bsdf_diffuse_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_diffuse_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_diffuse_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float3 m_N = sd->N; + + // distribution over the hemisphere + sample_cos_hemisphere(m_N, randu, randv, omega_in, pdf); + + if(dot(sd->Ng, *omega_in) > 0.0f) { + *eval = make_float3(*pdf, *pdf, *pdf); +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + *domega_in_dx *= 125.0f; + *domega_in_dy *= 125.0f; +#endif + } + else + *pdf = 0.0f; + + return LABEL_REFLECT|LABEL_DIFFUSE; +} + +/* TRANSLUCENT */ + +typedef struct BsdfTranslucentClosure { + //float3 m_N; +} BsdfTranslucentClosure; + +__device void bsdf_translucent_setup(ShaderData *sd, ShaderClosure *sc) +{ + sc->type = CLOSURE_BSDF_TRANSLUCENT_ID; + sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL; +} + +__device void bsdf_translucent_blur(ShaderClosure *sc, float roughness) +{ +} + +__device float3 bsdf_translucent_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float3 bsdf_translucent_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float3 m_N = sd->N; + + float cos_pi = fmaxf(-dot(m_N, omega_in), 0.0f) * M_1_PI_F; + *pdf = cos_pi; + return make_float3 (cos_pi, cos_pi, cos_pi); +} + +__device float bsdf_translucent_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_translucent_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float3 m_N = sd->N; + + // we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere (-m_N, randu, randv, omega_in, pdf); + if(dot(sd->Ng, *omega_in) < 0) { + *eval = make_float3(*pdf, *pdf, *pdf); +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + *domega_in_dx *= -125.0f; + *domega_in_dy *= -125.0f; +#endif + } else + *pdf = 0; + + return LABEL_TRANSMIT|LABEL_DIFFUSE; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_DIFFUSE_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_microfacet.h b/intern/cycles/kernel/svm/bsdf_microfacet.h new file mode 100644 index 00000000000..3acd3ba4c85 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_microfacet.h @@ -0,0 +1,503 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BSDF_MICROFACET_H__ +#define __BSDF_MICROFACET_H__ + +CCL_NAMESPACE_BEGIN + +/* GGX */ + +typedef struct BsdfMicrofacetGGXClosure { + //float3 m_N; + float m_ag; + float m_eta; +} BsdfMicrofacetGGXClosure; + +__device void bsdf_microfacet_ggx_setup(ShaderData *sd, ShaderClosure *sc, float ag, float eta, bool refractive) +{ + float m_ag = clamp(ag, 1e-5f, 1.0f); + float m_eta = eta; + + sc->data0 = m_ag; + sc->data1 = m_eta; + + if(refractive) + sc->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + else + sc->type = CLOSURE_BSDF_MICROFACET_GGX_ID; + + sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; +} + +__device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness) +{ + float m_ag = sc->data0; + m_ag = fmaxf(roughness, m_ag); + sc->data0 = m_ag; +} + +__device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float m_ag = sc->data0; + //float m_eta = sc->data1; + int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 m_N = sd->N; + + if(m_refractive) return make_float3 (0, 0, 0); + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNI > 0 && cosNO > 0) { + // get half vector + float3 Hr = normalize(omega_in + I); + // eq. 20: (F*G*D)/(4*in*on) + // eq. 33: first we calculate D(m) with m=Hr: + float alpha2 = m_ag * m_ag; + float cosThetaM = dot(m_N, Hr); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + float out = (G * D) * 0.25f / cosNO; + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + *pdf = pm * 0.25f / dot(Hr, I); + return make_float3 (out, out, out); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float m_ag = sc->data0; + float m_eta = sc->data1; + int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 m_N = sd->N; + + if(!m_refractive) return make_float3 (0, 0, 0); + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO <= 0 || cosNI >= 0) + return make_float3 (0, 0, 0); // vectors on same side -- not possible + // compute half-vector of the refraction (eq. 16) + float3 ht = -(m_eta * omega_in + I); + float3 Ht = normalize(ht); + float cosHO = dot(Ht, I); + + float cosHI = dot(Ht, omega_in); + // eq. 33: first we calculate D(m) with m=Ht: + float alpha2 = m_ag * m_ag; + float cosThetaM = dot(m_N, Ht); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // probability + float invHt2 = 1 / dot(ht, ht); + *pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2; + float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO; + return make_float3 (out, out, out); +} + +__device float bsdf_microfacet_ggx_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_microfacet_ggx_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float m_ag = sc->data0; + float m_eta = sc->data1; + int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + float3 m_N = sd->N; + + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { + float3 X, Y, Z = m_N; + make_orthonormals(Z, &X, &Y); + // generate a random microfacet normal m + // eq. 35,36: + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + //tttt and sin(atan(x)) == x/sqrt(1+x^2) + float alpha2 = m_ag * m_ag; + float tanThetaM2 = alpha2 * randu / (1 - randu); + float cosThetaM = 1 / sqrtf(1 + tanThetaM2); + float sinThetaM = cosThetaM * sqrtf(tanThetaM2); + float phiM = 2 * M_PI_F * randv; + float3 m = (cosf(phiM) * sinThetaM) * X + + (sinf(phiM) * sinThetaM) * Y + + cosThetaM * Z; + if(!m_refractive) { + float cosMO = dot(m, sd->I); + if(cosMO > 0) { + // eq. 39 - compute actual reflected direction + *omega_in = 2 * cosMO * m - sd->I; + if(dot(sd->Ng, *omega_in) > 0) { + // microfacet normal is visible to this ray + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + *pdf = pm * 0.25f / cosMO; + // eval BRDF*cosNI + float cosNI = dot(m_N, *omega_in); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // eq. 20: (F*G*D)/(4*in*on) + float out = (G * D) * 0.25f / cosNO; + *eval = make_float3(out, out, out); +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(m, sd->dI.dx)) * m - sd->dI.dx; + *domega_in_dy = (2 * dot(m, sd->dI.dy)) * m - sd->dI.dy; + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10.0f; + *domega_in_dy *= 10.0f; +#endif + } + } + } else { + // CAUTION: the i and o variables are inverted relative to the paper + // eq. 39 - compute actual refractive direction + float3 R, T; +#ifdef __RAY_DIFFERENTIALS__ + float3 dRdx, dRdy, dTdx, dTdy; +#endif + bool inside; + fresnel_dielectric(m_eta, m, sd->I, &R, &T, +#ifdef __RAY_DIFFERENTIALS__ + sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy, +#endif + &inside); + + if(!inside) { + *omega_in = T; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; +#endif + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + // eq. 24 + float pm = D * cosThetaM; + // eval BRDF*cosNI + float cosNI = dot(m_N, *omega_in); + // eq. 34: now calculate G1(i,m) and G1(o,m) + float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); + float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + float G = G1o * G1i; + // eq. 21 + float cosHI = dot(m, *omega_in); + float cosHO = dot(m, sd->I); + float Ht2 = m_eta * cosHI + cosHO; + Ht2 *= Ht2; + float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2); + // eq. 38 and eq. 17 + *pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2; + *eval = make_float3(out, out, out); +#ifdef __RAY_DIFFERENTIALS__ + // Since there is some blur to this refraction, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10.0f; + *domega_in_dy *= 10.0f; +#endif + } + } + } + return (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; +} + +/* BECKMANN */ + +typedef struct BsdfMicrofacetBeckmannClosure { + //float3 m_N; + float m_ab; + float m_eta; +} BsdfMicrofacetBeckmannClosure; + +__device void bsdf_microfacet_beckmann_setup(ShaderData *sd, ShaderClosure *sc, float ab, float eta, bool refractive) +{ + float m_ab = clamp(ab, 1e-5f, 1.0f); + float m_eta = eta; + + sc->data0 = m_ab; + sc->data1 = m_eta; + + if(refractive) + sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + else + sc->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; + + sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; +} + +__device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness) +{ + float m_ab = sc->data0; + m_ab = fmaxf(roughness, m_ab); + sc->data0 = m_ab; +} + +__device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float m_ab = sc->data0; + //float m_eta = sc->data1; + int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 m_N = sd->N; + + if(m_refractive) return make_float3 (0, 0, 0); + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO > 0 && cosNI > 0) { + // get half vector + float3 Hr = normalize(omega_in + I); + // eq. 20: (F*G*D)/(4*in*on) + // eq. 25: first we calculate D(m) with m=Hr: + float alpha2 = m_ab * m_ab; + float cosThetaM = dot(m_N, Hr); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + float out = (G * D) * 0.25f / cosNO; + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + *pdf = pm * 0.25f / dot(Hr, I); + return make_float3 (out, out, out); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float m_ab = sc->data0; + float m_eta = sc->data1; + int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 m_N = sd->N; + + if(!m_refractive) return make_float3 (0, 0, 0); + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO <= 0 || cosNI >= 0) + return make_float3 (0, 0, 0); + // compute half-vector of the refraction (eq. 16) + float3 ht = -(m_eta * omega_in + I); + float3 Ht = normalize(ht); + float cosHO = dot(Ht, I); + + float cosHI = dot(Ht, omega_in); + // eq. 33: first we calculate D(m) with m=Ht: + float alpha2 = m_ab * m_ab; + float cosThetaM = dot(m_N, Ht); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // probability + float invHt2 = 1 / dot(ht, ht); + *pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2; + float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO; + return make_float3 (out, out, out); +} + +__device float bsdf_microfacet_beckmann_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_microfacet_beckmann_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float m_ab = sc->data0; + float m_eta = sc->data1; + int m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 m_N = sd->N; + + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { + float3 X, Y, Z = m_N; + make_orthonormals(Z, &X, &Y); + // generate a random microfacet normal m + // eq. 35,36: + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + //tttt and sin(atan(x)) == x/sqrt(1+x^2) + float alpha2 = m_ab * m_ab; + float tanThetaM = sqrtf(-alpha2 * logf(1 - randu)); + float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM); + float sinThetaM = cosThetaM * tanThetaM; + float phiM = 2 * M_PI_F * randv; + float3 m = (cosf(phiM) * sinThetaM) * X + + (sinf(phiM) * sinThetaM) * Y + + cosThetaM * Z; + + if(!m_refractive) { + float cosMO = dot(m, sd->I); + if(cosMO > 0) { + // eq. 39 - compute actual reflected direction + *omega_in = 2 * cosMO * m - sd->I; + if(dot(sd->Ng, *omega_in) > 0) { + // microfacet normal is visible to this ray + // eq. 25 + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = tanThetaM * tanThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + // eq. 24 + float pm = D * cosThetaM; + // convert into pdf of the sampled direction + // eq. 38 - but see also: + // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + *pdf = pm * 0.25f / cosMO; + // Eval BRDF*cosNI + float cosNI = dot(m_N, *omega_in); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // eq. 20: (F*G*D)/(4*in*on) + float out = (G * D) * 0.25f / cosNO; + *eval = make_float3(out, out, out); +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(m, sd->dI.dx)) * m - sd->dI.dx; + *domega_in_dy = (2 * dot(m, sd->dI.dy)) * m - sd->dI.dy; + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10.0f; + *domega_in_dy *= 10.0f; +#endif + } + } + } else { + // CAUTION: the i and o variables are inverted relative to the paper + // eq. 39 - compute actual refractive direction + float3 R, T; +#ifdef __RAY_DIFFERENTIALS__ + float3 dRdx, dRdy, dTdx, dTdy; +#endif + bool inside; + fresnel_dielectric(m_eta, m, sd->I, &R, &T, +#ifdef __RAY_DIFFERENTIALS__ + sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy, +#endif + &inside); + + if(!inside) { + *omega_in = T; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; +#endif + + // eq. 33 + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = tanThetaM * tanThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + // eq. 24 + float pm = D * cosThetaM; + // eval BRDF*cosNI + float cosNI = dot(m_N, *omega_in); + // eq. 26, 27: now calculate G1(i,m) and G1(o,m) + float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); + float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); + float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; + float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G = G1o * G1i; + // eq. 21 + float cosHI = dot(m, *omega_in); + float cosHO = dot(m, sd->I); + float Ht2 = m_eta * cosHI + cosHO; + Ht2 *= Ht2; + float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2); + // eq. 38 and eq. 17 + *pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2; + *eval = make_float3(out, out, out); +#ifdef __RAY_DIFFERENTIALS__ + // Since there is some blur to this refraction, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10.0f; + *domega_in_dy *= 10.0f; +#endif + } + } + } + return (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_MICROFACET_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_reflection.h b/intern/cycles/kernel/svm/bsdf_reflection.h new file mode 100644 index 00000000000..f00b72c4869 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_reflection.h @@ -0,0 +1,93 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BSDF_REFLECTION_H__ +#define __BSDF_REFLECTION_H__ + +CCL_NAMESPACE_BEGIN + +/* REFLECTION */ + +typedef struct BsdfReflectionClosure { + //float3 m_N; +} BsdfReflectionClosure; + +__device void bsdf_reflection_setup(ShaderData *sd, ShaderClosure *sc) +{ + sc->type = CLOSURE_BSDF_REFLECTION_ID; + sd->flag |= SD_BSDF; +} + +__device void bsdf_reflection_blur(ShaderClosure *sc, float roughness) +{ +} + +__device float3 bsdf_reflection_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float3 bsdf_reflection_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_reflection_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_reflection_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + //const BsdfReflectionClosure *self = (const BsdfReflectionClosure*)sc->data; + float3 m_N = sd->N; + + // only one direction is possible + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { + *omega_in = (2 * cosNO) * m_N - sd->I; + if(dot(sd->Ng, *omega_in) > 0) { +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = 2 * dot(m_N, sd->dI.dx) * m_N - sd->dI.dx; + *domega_in_dy = 2 * dot(m_N, sd->dI.dy) * m_N - sd->dI.dy; +#endif + *pdf = 1; + *eval = make_float3(1, 1, 1); + } + } + return LABEL_REFLECT|LABEL_SINGULAR; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_REFLECTION_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_refraction.h b/intern/cycles/kernel/svm/bsdf_refraction.h new file mode 100644 index 00000000000..07ef8633e0d --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_refraction.h @@ -0,0 +1,102 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BSDF_REFRACTION_H__ +#define __BSDF_REFRACTION_H__ + +CCL_NAMESPACE_BEGIN + +/* REFRACTION */ + +typedef struct BsdfRefractionClosure { + float m_eta; +} BsdfRefractionClosure; + +__device void bsdf_refraction_setup(ShaderData *sd, ShaderClosure *sc, float eta) +{ + sc->data0 = eta; + + sc->type = CLOSURE_BSDF_REFRACTION_ID; + sd->flag |= SD_BSDF; +} + +__device void bsdf_refraction_blur(ShaderClosure *sc, float roughness) +{ +} + +__device float3 bsdf_refraction_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float3 bsdf_refraction_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_refraction_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_refraction_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float m_eta = sc->data0; + float3 m_N = sd->N; + + float3 R, T; +#ifdef __RAY_DIFFERENTIALS__ + float3 dRdx, dRdy, dTdx, dTdy; +#endif + bool inside; + fresnel_dielectric(m_eta, m_N, sd->I, &R, &T, +#ifdef __RAY_DIFFERENTIALS__ + sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy, +#endif + &inside); + + if(!inside) { + *pdf = 1; + *eval = make_float3(1.0f, 1.0f, 1.0f); + *omega_in = T; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = dTdx; + *domega_in_dy = dTdy; +#endif + } + return LABEL_TRANSMIT|LABEL_SINGULAR; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_REFRACTION_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_transparent.h b/intern/cycles/kernel/svm/bsdf_transparent.h new file mode 100644 index 00000000000..4425c4bf104 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_transparent.h @@ -0,0 +1,79 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BSDF_TRANSPARENT_H__ +#define __BSDF_TRANSPARENT_H__ + +CCL_NAMESPACE_BEGIN + +__device void bsdf_transparent_setup(ShaderData *sd, ShaderClosure *sc) +{ + sc->type = CLOSURE_BSDF_TRANSPARENT_ID; + sd->flag |= SD_BSDF; +} + +__device void bsdf_transparent_blur(ShaderClosure *sc, float roughness) +{ +} + +__device float3 bsdf_transparent_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float3 bsdf_transparent_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_transparent_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_transparent_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + // only one direction is possible + *omega_in = -sd->I; +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = -sd->dI.dx; + *domega_in_dy = -sd->dI.dy; +#endif + *pdf = 1; + *eval = make_float3(1, 1, 1); + return LABEL_TRANSMIT|LABEL_TRANSPARENT; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_TRANSPARENT_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_ward.h b/intern/cycles/kernel/svm/bsdf_ward.h new file mode 100644 index 00000000000..d46baf099a6 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_ward.h @@ -0,0 +1,200 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BSDF_WARD_H__ +#define __BSDF_WARD_H__ + +CCL_NAMESPACE_BEGIN + +/* WARD */ + +typedef struct BsdfWardClosure { + //float3 m_N; + //float3 m_T; + float m_ax; + float m_ay; +} BsdfWardClosure; + +__device void bsdf_ward_setup(ShaderData *sd, ShaderClosure *sc, float3 T, float ax, float ay) +{ + float m_ax = clamp(ax, 1e-5f, 1.0f); + float m_ay = clamp(ay, 1e-5f, 1.0f); + + sc->data0 = m_ax; + sc->data1 = m_ay; + + sc->type = CLOSURE_BSDF_WARD_ID; + sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; +} + +__device void bsdf_ward_blur(ShaderClosure *sc, float roughness) +{ + sc->data0 = fmaxf(roughness, sc->data0); + sc->data1 = fmaxf(roughness, sc->data1); +} + +__device float3 bsdf_ward_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float m_ax = sc->data0; + float m_ay = sc->data1; + float3 m_N = sd->N; + float3 m_T = normalize(sd->dPdu); + + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + + if(cosNI > 0 && cosNO > 0) { + // get half vector and get x,y basis on the surface for anisotropy + float3 H = normalize(omega_in + I); // normalize needed for pdf + float3 X, Y; + make_orthonormals_tangent(m_N, m_T, &X, &Y); + // eq. 4 + float dotx = dot(H, X) / m_ax; + float doty = dot(H, Y) / m_ay; + float dotn = dot(H, m_N); + float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); + float denom = (4 * M_PI_F * m_ax * m_ay * sqrtf(cosNO * cosNI)); + float exp_val = expf(-exp_arg); + float out = cosNI * exp_val / denom; + float oh = dot(H, I); + denom = 4 * M_PI_F * m_ax * m_ay * oh * dotn * dotn * dotn; + *pdf = exp_val / denom; + return make_float3 (out, out, out); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_ward_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_ward_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_ward_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float m_ax = sc->data0; + float m_ay = sc->data1; + float3 m_N = sd->N; + float3 m_T = normalize(sd->dPdu); + + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { + // get x,y basis on the surface for anisotropy + float3 X, Y; + make_orthonormals_tangent(m_N, m_T, &X, &Y); + // generate random angles for the half vector + // eq. 7 (taking care around discontinuities to keep + //ttoutput angle in the right quadrant) + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + //tttt and sin(atan(x)) == x/sqrt(1+x^2) + float alphaRatio = m_ay / m_ax; + float cosPhi, sinPhi; + if(randu < 0.25f) { + float val = 4 * randu; + float tanPhi = alphaRatio * tanf(M_PI_2_F * val); + cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = tanPhi * cosPhi; + } else if(randu < 0.5f) { + float val = 1 - 4 * (0.5f - randu); + float tanPhi = alphaRatio * tanf(M_PI_2_F * val); + // phi = M_PI_F - phi; + cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = -tanPhi * cosPhi; + } else if(randu < 0.75f) { + float val = 4 * (randu - 0.5f); + float tanPhi = alphaRatio * tanf(M_PI_2_F * val); + //phi = M_PI_F + phi; + cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = tanPhi * cosPhi; + } else { + float val = 1 - 4 * (1 - randu); + float tanPhi = alphaRatio * tanf(M_PI_2_F * val); + // phi = 2 * M_PI_F - phi; + cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi); + sinPhi = -tanPhi * cosPhi; + } + // eq. 6 + // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2) + //tttt and sin(atan(x)) == x/sqrt(1+x^2) + float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay); + float tanTheta2 = -logf(1 - randv) / thetaDenom; + float cosTheta = 1 / sqrtf(1 + tanTheta2); + float sinTheta = cosTheta * sqrtf(tanTheta2); + + float3 h; // already normalized becaused expressed from spherical coordinates + h.x = sinTheta * cosPhi; + h.y = sinTheta * sinPhi; + h.z = cosTheta; + // compute terms that are easier in local space + float dotx = h.x / m_ax; + float doty = h.y / m_ay; + float dotn = h.z; + // transform to world space + h = h.x * X + h.y * Y + h.z * m_N; + // generate the final sample + float oh = dot(h, sd->I); + *omega_in = 2.0f * oh * h - sd->I; + if(dot(sd->Ng, *omega_in) > 0) { + float cosNI = dot(m_N, *omega_in); + if(cosNI > 0) { + // eq. 9 + float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn); + float denom = 4 * M_PI_F * m_ax * m_ay * oh * dotn * dotn * dotn; + *pdf = expf(-exp_arg) / denom; + // compiler will reuse expressions already computed + denom = (4 * M_PI_F * m_ax * m_ay * sqrtf(cosNO * cosNI)); + float power = cosNI * expf(-exp_arg) / denom; + *eval = make_float3(power, power, power); +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // roughness but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10.0f; + *domega_in_dy *= 10.0f; +#endif + } + } + } + return LABEL_REFLECT|LABEL_GLOSSY; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_WARD_H__ */ + diff --git a/intern/cycles/kernel/svm/bsdf_westin.h b/intern/cycles/kernel/svm/bsdf_westin.h new file mode 100644 index 00000000000..21e5018c489 --- /dev/null +++ b/intern/cycles/kernel/svm/bsdf_westin.h @@ -0,0 +1,207 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __BSDF_WESTIN_H__ +#define __BSDF_WESTIN_H__ + +CCL_NAMESPACE_BEGIN + +/* WESTIN BACKSCATTER */ + +typedef struct BsdfWestinBackscatterClosure { + //float3 m_N; + float m_invroughness; +} BsdfWestinBackscatterClosure; + +__device void bsdf_westin_backscatter_setup(ShaderData *sd, ShaderClosure *sc, float roughness) +{ + roughness = clamp(roughness, 1e-5f, 1.0f); + float m_invroughness = 1.0f/roughness; + + sc->type = CLOSURE_BSDF_WESTIN_BACKSCATTER_ID; + sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; + sc->data0 = m_invroughness; +} + +__device void bsdf_westin_backscatter_blur(ShaderClosure *sc, float roughness) +{ + float m_invroughness = sc->data0; + m_invroughness = min(1.0f/roughness, m_invroughness); + sc->data0 = m_invroughness; +} + +__device float3 bsdf_westin_backscatter_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float m_invroughness = sc->data0; + float3 m_N = sd->N; + + // pdf is implicitly 0 (no indirect sampling) + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO > 0 && cosNI > 0) { + float cosine = dot(I, omega_in); + *pdf = cosine > 0 ? (m_invroughness + 1) * powf(cosine, m_invroughness) : 0; + *pdf *= 0.5f * M_1_PI_F; + return make_float3 (*pdf, *pdf, *pdf); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_westin_backscatter_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_westin_backscatter_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_westin_backscatter_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float m_invroughness = sc->data0; + float3 m_N = sd->N; + + float cosNO = dot(m_N, sd->I); + if(cosNO > 0) { +#ifdef __RAY_DIFFERENTIALS__ + *domega_in_dx = sd->dI.dx; + *domega_in_dy = sd->dI.dy; +#endif + float3 T, B; + make_orthonormals (sd->I, &T, &B); + float phi = 2 * M_PI_F * randu; + float cosTheta = powf(randv, 1 / (m_invroughness + 1)); + float sinTheta2 = 1 - cosTheta * cosTheta; + float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0; + *omega_in = (cosf(phi) * sinTheta) * T + + (sinf(phi) * sinTheta) * B + + (cosTheta) * sd->I; + if(dot(sd->Ng, *omega_in) > 0) + { + // common terms for pdf and eval + float cosNI = dot(m_N, *omega_in); + // make sure the direction we chose is still in the right hemisphere + if(cosNI > 0) + { + *pdf = 0.5f * M_1_PI_F * powf(cosTheta, m_invroughness); + *pdf = (m_invroughness + 1) * (*pdf); + *eval = make_float3(*pdf, *pdf, *pdf); +#ifdef __RAY_DIFFERENTIALS__ + // Since there is some blur to this reflection, make the + // derivatives a bit bigger. In theory this varies with the + // exponent but the exact relationship is complex and + // requires more ops than are practical. + *domega_in_dx *= 10.0f; + *domega_in_dy *= 10.0f; +#endif + } + } + } + return LABEL_REFLECT|LABEL_GLOSSY; +} + +/* WESTIN SHEEN */ + +typedef struct BsdfWestinSheenClosure { + //float3 m_N; + float m_edginess; +} BsdfWestinSheenClosure; + +__device void bsdf_westin_sheen_setup(ShaderData *sd, ShaderClosure *sc, float edginess) +{ + sc->type = CLOSURE_BSDF_WESTIN_SHEEN_ID; + sd->flag |= SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY; + sc->data0 = edginess; +} + +__device void bsdf_westin_sheen_blur(ShaderClosure *sc, float roughness) +{ +} + +__device float3 bsdf_westin_sheen_eval_reflect(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + float m_edginess = sc->data0; + float3 m_N = sd->N; + + // pdf is implicitly 0 (no indirect sampling) + float cosNO = dot(m_N, I); + float cosNI = dot(m_N, omega_in); + if(cosNO > 0 && cosNI > 0) { + float sinNO2 = 1 - cosNO * cosNO; + *pdf = cosNI * M_1_PI_F; + float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * (*pdf) : 0; + return make_float3 (westin, westin, westin); + } + return make_float3 (0, 0, 0); +} + +__device float3 bsdf_westin_sheen_eval_transmit(const ShaderData *sd, const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) +{ + return make_float3(0.0f, 0.0f, 0.0f); +} + +__device float bsdf_westin_sheen_albedo(const ShaderData *sd, const ShaderClosure *sc, const float3 I) +{ + return 1.0f; +} + +__device int bsdf_westin_sheen_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf) +{ + float m_edginess = sc->data0; + float3 m_N = sd->N; + + // we are viewing the surface from the right side - send a ray out with cosine + // distribution over the hemisphere + sample_cos_hemisphere(m_N, randu, randv, omega_in, pdf); + if(dot(sd->Ng, *omega_in) > 0) { + // TODO: account for sheen when sampling + float cosNO = dot(m_N, sd->I); + float sinNO2 = 1 - cosNO * cosNO; + float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * (*pdf) : 0; + *eval = make_float3(westin, westin, westin); +#ifdef __RAY_DIFFERENTIALS__ + // TODO: find a better approximation for the diffuse bounce + *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx; + *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy; + *domega_in_dx *= 125.0f; + *domega_in_dy *= 125.0f; +#endif + } else + pdf = 0; + return LABEL_REFLECT|LABEL_DIFFUSE; +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_WESTIN_H__ */ + diff --git a/intern/cycles/kernel/svm/emissive.h b/intern/cycles/kernel/svm/emissive.h new file mode 100644 index 00000000000..e3f99e9b729 --- /dev/null +++ b/intern/cycles/kernel/svm/emissive.h @@ -0,0 +1,60 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +CCL_NAMESPACE_BEGIN + +/* EMISSION CLOSURE */ + +__device float3 emissive_eval(const float3 Ng, const float3 I) +{ + float cosNO = fabsf(dot(Ng, I)); + float res = (cosNO > 0.0f)? 1.0f: 0.0f; + + return make_float3(res, res, res); +} + +/// Return the probability distribution function in the direction I, +/// given the parameters and the light's surface normal. This MUST match +/// the PDF computed by sample(). +__device float emissive_pdf(const float3 Ng, const float3 I) +{ + float cosNO = fabsf(dot(Ng, I)); + return (cosNO > 0.0f)? 1.0f: 0.0f; +} + +__device float3 svm_emissive_eval(ShaderData *sd, ShaderClosure *sc) +{ + return emissive_eval(sd->Ng, sd->I); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h new file mode 100644 index 00000000000..2615272691c --- /dev/null +++ b/intern/cycles/kernel/svm/svm.h @@ -0,0 +1,312 @@ +/* + * 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. + */ + +#ifndef __SVM_H__ +#define __SVM_H__ + +/* Shader Virtual Machine + * + * A shader is a list of nodes to be executed. These are simply read one after + * the other and executed, using an node counter. Each node and it's associated + * data is encoded as one or more uint4's in a 1D texture. If the data is larger + * than an uint4, the node can increase the node counter to compensate for this. + * Floats are encoded as int and then converted to float again. + * + * Nodes write their output into a stack. All stack data in the stack is + * floats, since it's all factors, colors and vectors. The stack will be stored + * in local memory on the GPU, as it would take too many register and indexes in + * ways not known at compile time. This seems the only solution even though it + * may be slow, with two positive factors. If the same shader is being executed, + * memory access will be coalesced, and on fermi cards, memory will actually be + * cached. + * + * The result of shader execution will be a single closure. This means the + * closure type, associated label, data and weight. Sampling from multiple + * closures is supported through the mix closure node, the logic for that is + * mostly taken care of in the SVM compiler. + */ + +#include "svm_types.h" + +CCL_NAMESPACE_BEGIN + +/* Stack */ + +__device_inline float3 stack_load_float3(float *stack, uint a) +{ + kernel_assert(a+2 < SVM_STACK_SIZE); + + return make_float3(stack[a+0], stack[a+1], stack[a+2]); +} + +__device_inline void stack_store_float3(float *stack, uint a, float3 f) +{ + kernel_assert(a+2 < SVM_STACK_SIZE); + + stack[a+0] = f.x; + stack[a+1] = f.y; + stack[a+2] = f.z; +} + +__device_inline float stack_load_float(float *stack, uint a) +{ + kernel_assert(a < SVM_STACK_SIZE); + + return stack[a]; +} + +__device_inline float stack_load_float_default(float *stack, uint a, uint value) +{ + return (a == (uint)SVM_STACK_INVALID)? __int_as_float(value): stack_load_float(stack, a); +} + +__device_inline void stack_store_float(float *stack, uint a, float f) +{ + kernel_assert(a < SVM_STACK_SIZE); + + stack[a] = f; +} + +__device_inline bool stack_valid(uint a) +{ + return a != (uint)SVM_STACK_INVALID; +} + +/* Reading Nodes */ + +__device_inline uint4 read_node(KernelGlobals *kg, int *offset) +{ + uint4 node = kernel_tex_fetch(__svm_nodes, *offset); + (*offset)++; + return node; +} + +__device_inline float4 read_node_float(KernelGlobals *kg, int *offset) +{ + uint4 node = kernel_tex_fetch(__svm_nodes, *offset); + float4 f = make_float4(__int_as_float(node.x), __int_as_float(node.y), __int_as_float(node.z), __int_as_float(node.w)); + (*offset)++; + return f; +} + +__device_inline void decode_node_uchar4(uint i, uint *x, uint *y, uint *z, uint *w) +{ + if(x) *x = (i & 0xFF); + if(y) *y = ((i >> 8) & 0xFF); + if(z) *z = ((i >> 16) & 0xFF); + if(w) *w = ((i >> 24) & 0xFF); +} + +CCL_NAMESPACE_END + +/* Nodes */ + +#include "svm_noise.h" +#include "svm_texture.h" + +#include "svm_attribute.h" +#include "svm_gradient.h" +#include "svm_closure.h" +#include "svm_noisetex.h" +#include "svm_convert.h" +#include "svm_displace.h" +#include "svm_fresnel.h" +#include "svm_geometry.h" +#include "svm_image.h" +#include "svm_light_path.h" +#include "svm_magic.h" +#include "svm_mapping.h" +#include "svm_wave.h" +#include "svm_math.h" +#include "svm_mix.h" +#include "svm_musgrave.h" +#include "svm_sky.h" +#include "svm_tex_coord.h" +#include "svm_value.h" +#include "svm_voronoi.h" + +CCL_NAMESPACE_BEGIN + +/* Main Interpreter Loop */ + +__device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderType type, float randb, int path_flag) +{ + float stack[SVM_STACK_SIZE]; + float closure_weight = 1.0f; + int offset = sd->shader & SHADER_MASK; + +#ifdef __MULTI_CLOSURE__ + sd->num_closure = 0; + sd->randb_closure = randb; +#else + sd->closure.type = NBUILTIN_CLOSURES; +#endif + + while(1) { + uint4 node = read_node(kg, &offset); + + switch(node.x) { + case NODE_SHADER_JUMP: { + if(type == SHADER_TYPE_SURFACE) offset = node.y; + else if(type == SHADER_TYPE_VOLUME) offset = node.z; + else if(type == SHADER_TYPE_DISPLACEMENT) offset = node.w; + else return; + break; + } + case NODE_CLOSURE_BSDF: + svm_node_closure_bsdf(kg, sd, stack, node, randb, path_flag); + break; + case NODE_CLOSURE_EMISSION: + svm_node_closure_emission(sd, stack, node); + break; + case NODE_CLOSURE_BACKGROUND: + svm_node_closure_background(sd, stack, node); + break; + case NODE_CLOSURE_HOLDOUT: + svm_node_closure_holdout(sd, stack, node); + break; + case NODE_CLOSURE_VOLUME: + svm_node_closure_volume(kg, sd, stack, node, path_flag); + break; + case NODE_CLOSURE_SET_WEIGHT: + svm_node_closure_set_weight(sd, node.y, node.z, node.w); + break; + case NODE_CLOSURE_WEIGHT: + svm_node_closure_weight(sd, stack, node.y); + break; + case NODE_EMISSION_WEIGHT: + svm_node_emission_weight(kg, sd, stack, node); + break; + case NODE_MIX_CLOSURE: + svm_node_mix_closure(sd, stack, node, &offset, &randb); + break; + case NODE_ADD_CLOSURE: + svm_node_add_closure(sd, stack, node.y, node.z, &offset, &randb, &closure_weight); + break; + case NODE_JUMP: + offset = node.y; + break; +#ifdef __TEXTURES__ + case NODE_TEX_IMAGE: + svm_node_tex_image(kg, sd, stack, node); + break; + case NODE_TEX_ENVIRONMENT: + svm_node_tex_environment(kg, sd, stack, node); + break; + case NODE_TEX_SKY: + svm_node_tex_sky(kg, sd, stack, node.y, node.z); + break; + case NODE_TEX_GRADIENT: + svm_node_tex_gradient(sd, stack, node); + break; + case NODE_TEX_NOISE: + svm_node_tex_noise(kg, sd, stack, node, &offset); + break; + case NODE_TEX_VORONOI: + svm_node_tex_voronoi(kg, sd, stack, node, &offset); + break; + case NODE_TEX_MUSGRAVE: + svm_node_tex_musgrave(kg, sd, stack, node, &offset); + break; + case NODE_TEX_WAVE: + svm_node_tex_wave(kg, sd, stack, node, &offset); + break; + case NODE_TEX_MAGIC: + svm_node_tex_magic(kg, sd, stack, node, &offset); + break; +#endif + case NODE_GEOMETRY: + svm_node_geometry(sd, stack, node.y, node.z); + break; + case NODE_GEOMETRY_BUMP_DX: + svm_node_geometry_bump_dx(sd, stack, node.y, node.z); + break; + case NODE_GEOMETRY_BUMP_DY: + svm_node_geometry_bump_dy(sd, stack, node.y, node.z); + break; + case NODE_LIGHT_PATH: + svm_node_light_path(sd, stack, node.y, node.z, path_flag); + break; + case NODE_CONVERT: + svm_node_convert(sd, stack, node.y, node.z, node.w); + break; + case NODE_VALUE_F: + svm_node_value_f(kg, sd, stack, node.y, node.z); + break; + case NODE_VALUE_V: + svm_node_value_v(kg, sd, stack, node.y, &offset); + break; + case NODE_MIX: + svm_node_mix(kg, sd, stack, node.y, node.z, node.w, &offset); + break; + case NODE_ATTR: + svm_node_attr(kg, sd, stack, node); + break; + case NODE_ATTR_BUMP_DX: + svm_node_attr_bump_dx(kg, sd, stack, node); + break; + case NODE_ATTR_BUMP_DY: + svm_node_attr_bump_dy(kg, sd, stack, node); + break; + case NODE_FRESNEL: + svm_node_fresnel(sd, stack, node.y, node.z, node.w); + break; + case NODE_LAYER_WEIGHT: + svm_node_layer_weight(sd, stack, node); + break; + case NODE_SET_DISPLACEMENT: + svm_node_set_displacement(sd, stack, node.y); + break; + case NODE_SET_BUMP: + svm_node_set_bump(sd, stack, node.y, node.z, node.w); + break; + case NODE_MATH: + svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset); + break; + case NODE_VECTOR_MATH: + svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, &offset); + break; + case NODE_MAPPING: + svm_node_mapping(kg, sd, stack, node.y, node.z, &offset); + break; + case NODE_TEX_COORD: + svm_node_tex_coord(kg, sd, stack, node.y, node.z); + break; + case NODE_TEX_COORD_BUMP_DX: + svm_node_tex_coord_bump_dx(kg, sd, stack, node.y, node.z); + break; + case NODE_TEX_COORD_BUMP_DY: + svm_node_tex_coord_bump_dy(kg, sd, stack, node.y, node.z); + break; + case NODE_EMISSION_SET_WEIGHT_TOTAL: + svm_node_emission_set_weight_total(kg, sd, node.y, node.z, node.w); + break; + case NODE_END: + default: +#ifndef __MULTI_CLOSURE__ + sd->closure.weight *= closure_weight; +#endif + return; + } + } +} + +CCL_NAMESPACE_END + +#endif /* __SVM_H__ */ + diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h new file mode 100644 index 00000000000..3a94f08d42f --- /dev/null +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -0,0 +1,154 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Attribute Node */ + +__device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd, + uint4 node, NodeAttributeType *type, + NodeAttributeType *mesh_type, AttributeElement *elem, uint *offset, uint *out_offset) +{ + if(sd->object != ~0) { + /* find attribute by unique id */ + uint id = node.y; + uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; + uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + + while(attr_map.x != id) + attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset); + + /* return result */ + *elem = (AttributeElement)attr_map.y; + *offset = attr_map.z; + *mesh_type = (NodeAttributeType)attr_map.w; + } + else { + /* background */ + *elem = ATTR_ELEMENT_NONE; + *offset = 0; + *mesh_type = (NodeAttributeType)node.w; + } + + *out_offset = node.z; + *type = (NodeAttributeType)node.w; +} + +__device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + NodeAttributeType type, mesh_type; + AttributeElement elem; + uint offset, out_offset; + + svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); + + /* fetch and store attribute */ + if(type == NODE_ATTR_FLOAT) { + if(mesh_type == NODE_ATTR_FLOAT) { + float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + stack_store_float(stack, out_offset, f); + } + else { + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + stack_store_float(stack, out_offset, average(f)); + } + } + else { + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + stack_store_float3(stack, out_offset, f); + } + else { + float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + stack_store_float3(stack, out_offset, make_float3(f, f, f)); + } + } +} + +__device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + NodeAttributeType type, mesh_type; + AttributeElement elem; + uint offset, out_offset; + + svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); + + /* fetch and store attribute */ + if(type == NODE_ATTR_FLOAT) { + if(mesh_type == NODE_ATTR_FLOAT) { + float dx; + float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + stack_store_float(stack, out_offset, f+dx); + } + else { + float3 dx; + float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + stack_store_float(stack, out_offset, average(f+dx)); + } + } + else { + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 dx; + float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + stack_store_float3(stack, out_offset, f+dx); + } + else { + float dx; + float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx)); + } + } +} + +__device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + NodeAttributeType type, mesh_type; + AttributeElement elem; + uint offset, out_offset; + + svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset); + + /* fetch and store attribute */ + if(type == NODE_ATTR_FLOAT) { + if(mesh_type == NODE_ATTR_FLOAT) { + float dy; + float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + stack_store_float(stack, out_offset, f+dy); + } + else { + float3 dy; + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + stack_store_float(stack, out_offset, average(f+dy)); + } + } + else { + if(mesh_type == NODE_ATTR_FLOAT3) { + float3 dy; + float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + stack_store_float3(stack, out_offset, f+dy); + } + else { + float dy; + float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy)); + } + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_bsdf.h b/intern/cycles/kernel/svm/svm_bsdf.h new file mode 100644 index 00000000000..411efc8be8f --- /dev/null +++ b/intern/cycles/kernel/svm/svm_bsdf.h @@ -0,0 +1,232 @@ +/* + * 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. + */ + +#include "bsdf_ashikhmin_velvet.h" +#include "bsdf_diffuse.h" +#include "bsdf_microfacet.h" +#include "bsdf_reflection.h" +#include "bsdf_refraction.h" +#include "bsdf_transparent.h" +#ifdef __DPDU__ +#include "bsdf_ward.h" +#endif +#include "bsdf_westin.h" + +CCL_NAMESPACE_BEGIN + +__device int svm_bsdf_sample(const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) +{ + int label; + + switch(sc->type) { + case CLOSURE_BSDF_DIFFUSE_ID: + label = bsdf_diffuse_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; +#ifdef __SVM__ + case CLOSURE_BSDF_TRANSLUCENT_ID: + label = bsdf_translucent_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_REFLECTION_ID: + label = bsdf_reflection_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_REFRACTION_ID: + label = bsdf_refraction_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + label = bsdf_transparent_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + label = bsdf_microfacet_ggx_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + label = bsdf_microfacet_beckmann_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: + label = bsdf_ward_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + label = bsdf_ashikhmin_velvet_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID: + label = bsdf_westin_backscatter_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; + case CLOSURE_BSDF_WESTIN_SHEEN_ID: + label = bsdf_westin_sheen_sample(sd, sc, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; +#endif + default: + label = LABEL_NONE; + break; + } + + return label; +} + +__device float3 svm_bsdf_eval(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) +{ + float3 eval; + + if(dot(sd->Ng, omega_in) >= 0.0f) { + switch(sc->type) { + case CLOSURE_BSDF_DIFFUSE_ID: + eval = bsdf_diffuse_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; +#ifdef __SVM__ + case CLOSURE_BSDF_TRANSLUCENT_ID: + eval = bsdf_translucent_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFLECTION_ID: + eval = bsdf_reflection_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFRACTION_ID: + eval = bsdf_refraction_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + eval = bsdf_transparent_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + eval = bsdf_microfacet_ggx_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + eval = bsdf_microfacet_beckmann_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: + eval = bsdf_ward_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + eval = bsdf_ashikhmin_velvet_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID: + eval = bsdf_westin_backscatter_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_WESTIN_SHEEN_ID: + eval = bsdf_westin_sheen_eval_reflect(sd, sc, sd->I, omega_in, pdf); + break; +#endif + default: + eval = make_float3(0.0f, 0.0f, 0.0f); + break; + } + } + else { + switch(sc->type) { + case CLOSURE_BSDF_DIFFUSE_ID: + eval = bsdf_diffuse_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; +#ifdef __SVM__ + case CLOSURE_BSDF_TRANSLUCENT_ID: + eval = bsdf_translucent_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFLECTION_ID: + eval = bsdf_reflection_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_REFRACTION_ID: + eval = bsdf_refraction_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + eval = bsdf_transparent_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + eval = bsdf_microfacet_ggx_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + eval = bsdf_microfacet_beckmann_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: + eval = bsdf_ward_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + eval = bsdf_ashikhmin_velvet_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID: + eval = bsdf_westin_backscatter_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; + case CLOSURE_BSDF_WESTIN_SHEEN_ID: + eval = bsdf_westin_sheen_eval_transmit(sd, sc, sd->I, omega_in, pdf); + break; +#endif + default: + eval = make_float3(0.0f, 0.0f, 0.0f); + break; + } + } + + return eval; +} + +__device void svm_bsdf_blur(ShaderClosure *sc, float roughness) +{ + switch(sc->type) { + case CLOSURE_BSDF_DIFFUSE_ID: + bsdf_diffuse_blur(sc, roughness); + break; +#ifdef __SVM__ + case CLOSURE_BSDF_TRANSLUCENT_ID: + bsdf_translucent_blur(sc, roughness); + break; + case CLOSURE_BSDF_REFLECTION_ID: + bsdf_reflection_blur(sc, roughness); + break; + case CLOSURE_BSDF_REFRACTION_ID: + bsdf_refraction_blur(sc, roughness); + break; + case CLOSURE_BSDF_TRANSPARENT_ID: + bsdf_transparent_blur(sc, roughness); + break; + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + bsdf_microfacet_ggx_blur(sc, roughness); + break; + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: + bsdf_microfacet_beckmann_blur(sc, roughness); + break; +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: + bsdf_ward_blur(sc, roughness); + break; +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: + bsdf_ashikhmin_velvet_blur(sc, roughness); + break; + case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID: + bsdf_westin_backscatter_blur(sc, roughness); + break; + case CLOSURE_BSDF_WESTIN_SHEEN_ID: + bsdf_westin_sheen_blur(sc, roughness); + break; +#endif + default: + break; + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h new file mode 100644 index 00000000000..fcda7ac6fe1 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -0,0 +1,424 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Closure Nodes */ + +__device void svm_node_glossy_setup(ShaderData *sd, ShaderClosure *sc, int type, float eta, float roughness, bool refract) +{ + if(type == CLOSURE_BSDF_REFRACTION_ID) { + if(refract) + bsdf_refraction_setup(sd, sc, eta); + else + bsdf_reflection_setup(sd, sc); + } + else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) { + bsdf_microfacet_beckmann_setup(sd, sc, roughness, eta, refract); + } + else + bsdf_microfacet_ggx_setup(sd, sc, roughness, eta, refract); +} + +__device_inline ShaderClosure *svm_node_closure_get(ShaderData *sd) +{ +#ifdef __MULTI_CLOSURE__ + ShaderClosure *sc = &sd->closure[sd->num_closure]; + + if(sd->num_closure < MAX_CLOSURE) + sd->num_closure++; + + return sc; +#else + return &sd->closure; +#endif +} + +__device_inline void svm_node_closure_set_mix_weight(ShaderClosure *sc, float mix_weight) +{ +#ifdef __MULTI_CLOSURE__ + sc->weight *= mix_weight; + sc->sample_weight = fabsf(average(sc->weight)); +#endif +} + +__device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, float randb, int path_flag) +{ + uint type, param1_offset, param2_offset; + +#ifdef __MULTI_CLOSURE__ + uint mix_weight_offset; + decode_node_uchar4(node.y, &type, ¶m1_offset, ¶m2_offset, &mix_weight_offset); + float mix_weight = (stack_valid(mix_weight_offset)? stack_load_float(stack, mix_weight_offset): 1.0f); + + if(mix_weight == 0.0f) + return; +#else + decode_node_uchar4(node.y, &type, ¶m1_offset, ¶m2_offset, NULL); + float mix_weight = 1.0f; +#endif + + float param1 = (stack_valid(param1_offset))? stack_load_float(stack, param1_offset): __int_as_float(node.z); + float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __int_as_float(node.w); + + switch(type) { + case CLOSURE_BSDF_DIFFUSE_ID: { + ShaderClosure *sc = svm_node_closure_get(sd); + svm_node_closure_set_mix_weight(sc, mix_weight); + bsdf_diffuse_setup(sd, sc); + break; + } + case CLOSURE_BSDF_TRANSLUCENT_ID: { + ShaderClosure *sc = svm_node_closure_get(sd); + svm_node_closure_set_mix_weight(sc, mix_weight); + bsdf_translucent_setup(sd, sc); + break; + } + case CLOSURE_BSDF_TRANSPARENT_ID: { + ShaderClosure *sc = svm_node_closure_get(sd); + svm_node_closure_set_mix_weight(sc, mix_weight); + bsdf_transparent_setup(sd, sc); + break; + } + case CLOSURE_BSDF_REFLECTION_ID: + case CLOSURE_BSDF_MICROFACET_GGX_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: { +#ifdef __CAUSTICS_TRICKS__ + if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE)) + break; +#endif + ShaderClosure *sc = svm_node_closure_get(sd); + svm_node_closure_set_mix_weight(sc, mix_weight); + + float roughness = param1; + + /* setup bsdf */ + if(type == CLOSURE_BSDF_REFLECTION_ID) + bsdf_reflection_setup(sd, sc); + else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) + bsdf_microfacet_beckmann_setup(sd, sc, roughness, 1.0f, false); + else + bsdf_microfacet_ggx_setup(sd, sc, roughness, 1.0f, false); + + break; + } + case CLOSURE_BSDF_REFRACTION_ID: + case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: { +#ifdef __CAUSTICS_TRICKS__ + if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE)) + break; +#endif + /* index of refraction */ + float eta = fmaxf(param2, 1.0f + 1e-5f); + eta = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta; + + /* fresnel */ + float cosNO = dot(sd->N, sd->I); + float fresnel = fresnel_dielectric_cos(cosNO, eta); + float roughness = param1; + +#ifdef __MULTI_CLOSURE__ + /* reflection */ + ShaderClosure *sc = svm_node_closure_get(sd); + + float3 weight = sc->weight; + float sample_weight = sc->sample_weight; + + svm_node_closure_set_mix_weight(sc, mix_weight*fresnel); + svm_node_glossy_setup(sd, sc, type, eta, roughness, false); + + /* refraction */ + sc = svm_node_closure_get(sd); + + sc->weight = weight; + sc->sample_weight = sample_weight; + + svm_node_closure_set_mix_weight(sc, mix_weight*(1.0f - fresnel)); + svm_node_glossy_setup(sd, sc, type, eta, roughness, true); +#else + ShaderClosure *sc = svm_node_closure_get(sd); + + bool refract = (randb > fresnel); + + svm_node_closure_set_mix_weight(sc, mix_weight); + svm_node_glossy_setup(sd, sc, type, eta, roughness, refract); +#endif + + break; + } +#ifdef __DPDU__ + case CLOSURE_BSDF_WARD_ID: { +#ifdef __CAUSTICS_TRICKS__ + if(kernel_data.integrator.no_caustics && (path_flag & PATH_RAY_DIFFUSE)) + break; +#endif + ShaderClosure *sc = svm_node_closure_get(sd); + svm_node_closure_set_mix_weight(sc, mix_weight); + + float roughness_u = param1; + float roughness_v = param2; + + bsdf_ward_setup(sd, sc, normalize(sd->dPdu), roughness_u, roughness_v); + break; + } +#endif + case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: { + ShaderClosure *sc = svm_node_closure_get(sd); + svm_node_closure_set_mix_weight(sc, mix_weight); + + /* sigma */ + float sigma = clamp(param1, 0.0f, 1.0f); + bsdf_ashikhmin_velvet_setup(sd, sc, sigma); + break; + } + default: + break; + } +} + +__device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int path_flag) +{ + uint type, param1_offset, param2_offset; + +#ifdef __MULTI_CLOSURE__ + uint mix_weight_offset; + decode_node_uchar4(node.y, &type, ¶m1_offset, ¶m2_offset, &mix_weight_offset); + float mix_weight = (stack_valid(mix_weight_offset)? stack_load_float(stack, mix_weight_offset): 1.0f); + + if(mix_weight == 0.0f) + return; +#else + decode_node_uchar4(node.y, &type, ¶m1_offset, ¶m2_offset, NULL); + float mix_weight = 1.0f; +#endif + + float param1 = (stack_valid(param1_offset))? stack_load_float(stack, param1_offset): __int_as_float(node.z); + //float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __int_as_float(node.w); + + switch(type) { + case CLOSURE_VOLUME_TRANSPARENT_ID: { + ShaderClosure *sc = svm_node_closure_get(sd); + svm_node_closure_set_mix_weight(sc, mix_weight); + + float density = param1; + volume_transparent_setup(sd, sc, density); + break; + } + case CLOSURE_VOLUME_ISOTROPIC_ID: { + ShaderClosure *sc = svm_node_closure_get(sd); + svm_node_closure_set_mix_weight(sc, mix_weight); + + float density = param1; + volume_isotropic_setup(sd, sc, density); + break; + } + default: + break; + } +} + +__device void svm_node_closure_emission(ShaderData *sd, float *stack, uint4 node) +{ +#ifdef __MULTI_CLOSURE__ + uint mix_weight_offset = node.y; + + if(stack_valid(mix_weight_offset)) { + float mix_weight = stack_load_float(stack, mix_weight_offset); + + if(mix_weight == 0.0f) + return; + + ShaderClosure *sc = svm_node_closure_get(sd); + sc->weight *= mix_weight; + sc->type = CLOSURE_EMISSION_ID; + } + else { + ShaderClosure *sc = svm_node_closure_get(sd); + sc->type = CLOSURE_EMISSION_ID; + } + +#else + ShaderClosure *sc = &sd->closure; + sc->type = CLOSURE_EMISSION_ID; +#endif + + sd->flag |= SD_EMISSION; +} + +__device void svm_node_closure_background(ShaderData *sd, float *stack, uint4 node) +{ +#ifdef __MULTI_CLOSURE__ + uint mix_weight_offset = node.y; + + if(stack_valid(mix_weight_offset)) { + float mix_weight = stack_load_float(stack, mix_weight_offset); + + if(mix_weight == 0.0f) + return; + + ShaderClosure *sc = svm_node_closure_get(sd); + sc->weight *= mix_weight; + sc->type = CLOSURE_BACKGROUND_ID; + } + else { + ShaderClosure *sc = svm_node_closure_get(sd); + sc->type = CLOSURE_BACKGROUND_ID; + } + +#else + ShaderClosure *sc = &sd->closure; + sc->type = CLOSURE_BACKGROUND_ID; +#endif +} + +__device void svm_node_closure_holdout(ShaderData *sd, float *stack, uint4 node) +{ +#ifdef __MULTI_CLOSURE__ + uint mix_weight_offset = node.y; + + if(stack_valid(mix_weight_offset)) { + float mix_weight = stack_load_float(stack, mix_weight_offset); + + if(mix_weight == 0.0f) + return; + + ShaderClosure *sc = svm_node_closure_get(sd); + sc->weight = make_float3(mix_weight, mix_weight, mix_weight); + sc->type = CLOSURE_HOLDOUT_ID; + } + else { + ShaderClosure *sc = svm_node_closure_get(sd); + sc->weight = make_float3(1.0f, 1.0f, 1.0f); + sc->type = CLOSURE_HOLDOUT_ID; + } +#else + ShaderClosure *sc = &sd->closure; + sc->type = CLOSURE_HOLDOUT_ID; +#endif + + sd->flag |= SD_HOLDOUT; +} + +/* Closure Nodes */ + +__device_inline void svm_node_closure_store_weight(ShaderData *sd, float3 weight) +{ +#ifdef __MULTI_CLOSURE__ + sd->closure[sd->num_closure].weight = weight; +#else + sd->closure.weight = weight; +#endif +} + +__device void svm_node_closure_set_weight(ShaderData *sd, uint r, uint g, uint b) +{ + float3 weight = make_float3(__int_as_float(r), __int_as_float(g), __int_as_float(b)); + svm_node_closure_store_weight(sd, weight); +} + +__device void svm_node_emission_set_weight_total(KernelGlobals *kg, ShaderData *sd, uint r, uint g, uint b) +{ + float3 weight = make_float3(__int_as_float(r), __int_as_float(g), __int_as_float(b)); + + if(sd->object != ~0) + weight /= object_surface_area(kg, sd->object); + + svm_node_closure_store_weight(sd, weight); +} + +__device void svm_node_closure_weight(ShaderData *sd, float *stack, uint weight_offset) +{ + float3 weight = stack_load_float3(stack, weight_offset); + + svm_node_closure_store_weight(sd, weight); +} + +__device void svm_node_emission_weight(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + uint color_offset = node.y; + uint strength_offset = node.z; + uint total_power = node.w; + + float strength = stack_load_float(stack, strength_offset); + float3 weight = stack_load_float3(stack, color_offset)*strength; + + if(total_power && sd->object != ~0) + weight /= object_surface_area(kg, sd->object); + + svm_node_closure_store_weight(sd, weight); +} + +__device void svm_node_mix_closure(ShaderData *sd, float *stack, + uint4 node, int *offset, float *randb) +{ +#ifdef __MULTI_CLOSURE__ + /* fetch weight from blend input, previous mix closures, + and write to stack to be used by closure nodes later */ + uint weight_offset, in_weight_offset, weight1_offset, weight2_offset; + decode_node_uchar4(node.y, &weight_offset, &in_weight_offset, &weight1_offset, &weight2_offset); + + float weight = stack_load_float(stack, weight_offset); + float in_weight = (stack_valid(in_weight_offset))? stack_load_float(stack, in_weight_offset): 1.0f; + + if(stack_valid(weight1_offset)) + stack_store_float(stack, weight1_offset, in_weight*(1.0f - weight)); + if(stack_valid(weight2_offset)) + stack_store_float(stack, weight2_offset, in_weight*weight); +#else + /* pick a closure and make the random number uniform over 0..1 again. + closure 1 starts on the next node, for closure 2 the start is at an + offset from the current node, so we jump */ + uint weight_offset = node.y; + uint node_jump = node.z; + float weight = stack_load_float(stack, weight_offset); + weight = clamp(weight, 0.0f, 1.0f); + + if(*randb < weight) { + *offset += node_jump; + *randb = *randb/weight; + } + else + *randb = (*randb - weight)/(1.0f - weight); +#endif +} + +__device void svm_node_add_closure(ShaderData *sd, float *stack, uint unused, + uint node_jump, int *offset, float *randb, float *closure_weight) +{ +#ifdef __MULTI_CLOSURE__ + /* nothing to do, handled in compiler */ +#else + /* pick one of the two closures with probability 0.5. sampling quality + is not going to be great, for that we'd need to evaluate the weights + of the two closures being added */ + float weight = 0.5f; + + if(*randb < weight) { + *offset += node_jump; + *randb = *randb/weight; + } + else + *randb = (*randb - weight)/(1.0f - weight); + + *closure_weight *= 2.0f; +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_convert.h b/intern/cycles/kernel/svm/svm_convert.h new file mode 100644 index 00000000000..188b0489d9e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_convert.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Conversion Nodes */ + +__device void svm_node_convert(ShaderData *sd, float *stack, uint type, uint from, uint to) +{ + switch(type) { + case NODE_CONVERT_FV: { + float f = stack_load_float(stack, from); + stack_store_float3(stack, to, make_float3(f, f, f)); + break; + } + case NODE_CONVERT_CF: { + float3 f = stack_load_float3(stack, from); + float g = linear_rgb_to_gray(f); + stack_store_float(stack, to, g); + break; + } + case NODE_CONVERT_VF: { + float3 f = stack_load_float3(stack, from); + float g = (f.x + f.y + f.z)*(1.0f/3.0f); + stack_store_float(stack, to, g); + break; + } + + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h new file mode 100644 index 00000000000..b1677f67eca --- /dev/null +++ b/intern/cycles/kernel/svm/svm_displace.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Bump Node */ + +__device void svm_node_set_bump(ShaderData *sd, float *stack, uint c_offset, uint x_offset, uint y_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float h_c = stack_load_float(stack, c_offset); + float h_x = stack_load_float(stack, x_offset); + float h_y = stack_load_float(stack, y_offset); + + float3 Rx = cross(sd->dP.dy, sd->N); + float3 Ry = cross(sd->N, sd->dP.dx); + + float det = dot(sd->dP.dx, Rx); + float3 surfgrad = (h_x - h_c)*Rx + (h_y - h_c)*Ry; + + surfgrad *= 0.1f; /* todo: remove this factor */ + + float absdet = fabsf(det); + sd->N = normalize(absdet*sd->N - signf(det)*surfgrad); +#endif +} + +/* Displacement Node */ + +__device void svm_node_set_displacement(ShaderData *sd, float *stack, uint fac_offset) +{ + float d = stack_load_float(stack, fac_offset); + sd->P += sd->N*d*0.1f; /* todo: get rid of this factor */ +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_fresnel.h b/intern/cycles/kernel/svm/svm_fresnel.h new file mode 100644 index 00000000000..7684eabeecb --- /dev/null +++ b/intern/cycles/kernel/svm/svm_fresnel.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Fresnel Node */ + +__device void svm_node_fresnel(ShaderData *sd, float *stack, uint ior_offset, uint ior_value, uint out_offset) +{ + float eta = (stack_valid(ior_offset))? stack_load_float(stack, ior_offset): __int_as_float(ior_value); + eta = fmaxf(eta, 1.0f + 1e-5f); + eta = (sd->flag & SD_BACKFACING)? 1.0f/eta: eta; + + float f = fresnel_dielectric_cos(dot(sd->I, sd->N), eta); + + stack_store_float(stack, out_offset, f); +} + +/* Blend Weight Node */ + +__device void svm_node_layer_weight(ShaderData *sd, float *stack, uint4 node) +{ + uint blend_offset = node.y; + uint blend_value = node.z; + float blend = (stack_valid(blend_offset))? stack_load_float(stack, blend_offset): __int_as_float(blend_value); + + uint type, out_offset; + decode_node_uchar4(node.w, &type, &out_offset, NULL, NULL); + + float f; + + if(type == NODE_LAYER_WEIGHT_FRESNEL) { + float eta = fmaxf(1.0f - blend, 1e-5f); + eta = (sd->flag & SD_BACKFACING)? eta: 1.0f/eta; + + f = fresnel_dielectric_cos(dot(sd->I, sd->N), eta); + } + else { + f = fabsf(dot(sd->I, sd->N)); + + if(blend != 0.5f) { + blend = clamp(blend, 0.0f, 1.0f); + blend = (blend < 0.5f)? 2.0f*blend: 0.5f/(1.0f - blend); + + f = powf(f, blend); + } + + f = 1.0f - f; + } + + stack_store_float(stack, out_offset, f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h new file mode 100644 index 00000000000..77fe26c809e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Geometry Node */ + +__device void svm_node_geometry(ShaderData *sd, float *stack, uint type, uint out_offset) +{ + float3 data; + + switch(type) { + case NODE_GEOM_P: data = sd->P; break; + case NODE_GEOM_N: data = sd->N; break; +#ifdef __DPDU__ + case NODE_GEOM_T: data = normalize(sd->dPdu); break; +#endif + case NODE_GEOM_I: data = sd->I; break; + case NODE_GEOM_Ng: data = sd->Ng; break; +#ifdef __UV__ + case NODE_GEOM_uv: data = make_float3(sd->u, sd->v, 0.0f); break; +#endif + } + + stack_store_float3(stack, out_offset, data); +} + +__device void svm_node_geometry_bump_dx(ShaderData *sd, float *stack, uint type, uint out_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float3 data; + + switch(type) { + case NODE_GEOM_P: data = sd->P + sd->dP.dx; break; + case NODE_GEOM_uv: data = make_float3(sd->u + sd->du.dx, sd->v + sd->dv.dx, 0.0f); break; + default: svm_node_geometry(sd, stack, type, out_offset); return; + } + + stack_store_float3(stack, out_offset, data); +#else + svm_node_geometry(sd, stack, type, out_offset); +#endif +} + +__device void svm_node_geometry_bump_dy(ShaderData *sd, float *stack, uint type, uint out_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float3 data; + + switch(type) { + case NODE_GEOM_P: data = sd->P + sd->dP.dy; break; + case NODE_GEOM_uv: data = make_float3(sd->u + sd->du.dy, sd->v + sd->dv.dy, 0.0f); break; + default: svm_node_geometry(sd, stack, type, out_offset); return; + } + + stack_store_float3(stack, out_offset, data); +#else + svm_node_geometry(sd, stack, type, out_offset); +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_gradient.h b/intern/cycles/kernel/svm/svm_gradient.h new file mode 100644 index 00000000000..c7013800d6b --- /dev/null +++ b/intern/cycles/kernel/svm/svm_gradient.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Gradient */ + +__device float svm_gradient(float3 p, NodeBlendType type) +{ + float x, y, z; + + x= p.x; + y= p.y; + z= p.z; + + if(type == NODE_BLEND_LINEAR) { + return x; + } + else if(type == NODE_BLEND_QUADRATIC) { + float r = fmaxf(x, 0.0f); + return r*r; + } + else if(type == NODE_BLEND_EASING) { + float r = fminf(fmaxf(x, 0.0f), 1.0f); + float t = r*r; + + return (3.0f*t - 2.0f*t*r); + } + else if(type == NODE_BLEND_DIAGONAL) { + return (x + y)/2.0f; + } + else if(type == NODE_BLEND_RADIAL) { + return atan2(y, x)/(2.0f*M_PI_F) + 0.5f; + } + else { + float r = fmaxf(1.0f - sqrtf(x*x + y*y + z*z), 0.0f); + + if(type == NODE_BLEND_QUADRATIC_SPHERE) + return r*r; + else if(type == NODE_BLEND_SPHERICAL) + return r; + } + + return 0.0f; +} + +__device void svm_node_tex_gradient(ShaderData *sd, float *stack, uint4 node) +{ + uint type, co_offset, color_offset, fac_offset; + + decode_node_uchar4(node.y, &type, &co_offset, &fac_offset, &color_offset); + + float3 co = stack_load_float3(stack, co_offset); + + float f = svm_gradient(co, (NodeBlendType)type); + f = clamp(f, 0.0f, 1.0f); + + if(stack_valid(fac_offset)) + stack_store_float(stack, fac_offset, f); + if(stack_valid(color_offset)) + stack_store_float3(stack, color_offset, make_float3(f, f, f)); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h new file mode 100644 index 00000000000..62e24166970 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_image.h @@ -0,0 +1,196 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y) +{ + float4 r; + + /* not particularly proud of this massive switch, what are the + alternatives? + - use a single big 1D texture, and do our own lookup/filtering + - group by size and use a 3d texture, performance impact + - group into larger texture with some padding for correct lerp + + also note that cuda has 128 textures limit, we use 100 now, since + we still need some for other storage */ + +#ifdef __KERNEL_OPENCL__ + r = make_float4(0.0f, 0.0f, 0.0f, 0.0f); /* todo */ +#else + switch(id) { + case 0: r = kernel_tex_image_interp(__tex_image_000, x, y); break; + case 1: r = kernel_tex_image_interp(__tex_image_001, x, y); break; + case 2: r = kernel_tex_image_interp(__tex_image_002, x, y); break; + case 3: r = kernel_tex_image_interp(__tex_image_003, x, y); break; + case 4: r = kernel_tex_image_interp(__tex_image_004, x, y); break; + case 5: r = kernel_tex_image_interp(__tex_image_005, x, y); break; + case 6: r = kernel_tex_image_interp(__tex_image_006, x, y); break; + case 7: r = kernel_tex_image_interp(__tex_image_007, x, y); break; + case 8: r = kernel_tex_image_interp(__tex_image_008, x, y); break; + case 9: r = kernel_tex_image_interp(__tex_image_009, x, y); break; + case 10: r = kernel_tex_image_interp(__tex_image_010, x, y); break; + case 11: r = kernel_tex_image_interp(__tex_image_011, x, y); break; + case 12: r = kernel_tex_image_interp(__tex_image_012, x, y); break; + case 13: r = kernel_tex_image_interp(__tex_image_013, x, y); break; + case 14: r = kernel_tex_image_interp(__tex_image_014, x, y); break; + case 15: r = kernel_tex_image_interp(__tex_image_015, x, y); break; + case 16: r = kernel_tex_image_interp(__tex_image_016, x, y); break; + case 17: r = kernel_tex_image_interp(__tex_image_017, x, y); break; + case 18: r = kernel_tex_image_interp(__tex_image_018, x, y); break; + case 19: r = kernel_tex_image_interp(__tex_image_019, x, y); break; + case 20: r = kernel_tex_image_interp(__tex_image_020, x, y); break; + case 21: r = kernel_tex_image_interp(__tex_image_021, x, y); break; + case 22: r = kernel_tex_image_interp(__tex_image_022, x, y); break; + case 23: r = kernel_tex_image_interp(__tex_image_023, x, y); break; + case 24: r = kernel_tex_image_interp(__tex_image_024, x, y); break; + case 25: r = kernel_tex_image_interp(__tex_image_025, x, y); break; + case 26: r = kernel_tex_image_interp(__tex_image_026, x, y); break; + case 27: r = kernel_tex_image_interp(__tex_image_027, x, y); break; + case 28: r = kernel_tex_image_interp(__tex_image_028, x, y); break; + case 29: r = kernel_tex_image_interp(__tex_image_029, x, y); break; + case 30: r = kernel_tex_image_interp(__tex_image_030, x, y); break; + case 31: r = kernel_tex_image_interp(__tex_image_031, x, y); break; + case 32: r = kernel_tex_image_interp(__tex_image_032, x, y); break; + case 33: r = kernel_tex_image_interp(__tex_image_033, x, y); break; + case 34: r = kernel_tex_image_interp(__tex_image_034, x, y); break; + case 35: r = kernel_tex_image_interp(__tex_image_035, x, y); break; + case 36: r = kernel_tex_image_interp(__tex_image_036, x, y); break; + case 37: r = kernel_tex_image_interp(__tex_image_037, x, y); break; + case 38: r = kernel_tex_image_interp(__tex_image_038, x, y); break; + case 39: r = kernel_tex_image_interp(__tex_image_039, x, y); break; + case 40: r = kernel_tex_image_interp(__tex_image_040, x, y); break; + case 41: r = kernel_tex_image_interp(__tex_image_041, x, y); break; + case 42: r = kernel_tex_image_interp(__tex_image_042, x, y); break; + case 43: r = kernel_tex_image_interp(__tex_image_043, x, y); break; + case 44: r = kernel_tex_image_interp(__tex_image_044, x, y); break; + case 45: r = kernel_tex_image_interp(__tex_image_045, x, y); break; + case 46: r = kernel_tex_image_interp(__tex_image_046, x, y); break; + case 47: r = kernel_tex_image_interp(__tex_image_047, x, y); break; + case 48: r = kernel_tex_image_interp(__tex_image_048, x, y); break; + case 49: r = kernel_tex_image_interp(__tex_image_049, x, y); break; + case 50: r = kernel_tex_image_interp(__tex_image_050, x, y); break; + case 51: r = kernel_tex_image_interp(__tex_image_051, x, y); break; + case 52: r = kernel_tex_image_interp(__tex_image_052, x, y); break; + case 53: r = kernel_tex_image_interp(__tex_image_053, x, y); break; + case 54: r = kernel_tex_image_interp(__tex_image_054, x, y); break; + case 55: r = kernel_tex_image_interp(__tex_image_055, x, y); break; + case 56: r = kernel_tex_image_interp(__tex_image_056, x, y); break; + case 57: r = kernel_tex_image_interp(__tex_image_057, x, y); break; + case 58: r = kernel_tex_image_interp(__tex_image_058, x, y); break; + case 59: r = kernel_tex_image_interp(__tex_image_059, x, y); break; + case 60: r = kernel_tex_image_interp(__tex_image_060, x, y); break; + case 61: r = kernel_tex_image_interp(__tex_image_061, x, y); break; + case 62: r = kernel_tex_image_interp(__tex_image_062, x, y); break; + case 63: r = kernel_tex_image_interp(__tex_image_063, x, y); break; + case 64: r = kernel_tex_image_interp(__tex_image_064, x, y); break; + case 65: r = kernel_tex_image_interp(__tex_image_065, x, y); break; + case 66: r = kernel_tex_image_interp(__tex_image_066, x, y); break; + case 67: r = kernel_tex_image_interp(__tex_image_067, x, y); break; + case 68: r = kernel_tex_image_interp(__tex_image_068, x, y); break; + case 69: r = kernel_tex_image_interp(__tex_image_069, x, y); break; + case 70: r = kernel_tex_image_interp(__tex_image_070, x, y); break; + case 71: r = kernel_tex_image_interp(__tex_image_071, x, y); break; + case 72: r = kernel_tex_image_interp(__tex_image_072, x, y); break; + case 73: r = kernel_tex_image_interp(__tex_image_073, x, y); break; + case 74: r = kernel_tex_image_interp(__tex_image_074, x, y); break; + case 75: r = kernel_tex_image_interp(__tex_image_075, x, y); break; + case 76: r = kernel_tex_image_interp(__tex_image_076, x, y); break; + case 77: r = kernel_tex_image_interp(__tex_image_077, x, y); break; + case 78: r = kernel_tex_image_interp(__tex_image_078, x, y); break; + case 79: r = kernel_tex_image_interp(__tex_image_079, x, y); break; + case 80: r = kernel_tex_image_interp(__tex_image_080, x, y); break; + case 81: r = kernel_tex_image_interp(__tex_image_081, x, y); break; + case 82: r = kernel_tex_image_interp(__tex_image_082, x, y); break; + case 83: r = kernel_tex_image_interp(__tex_image_083, x, y); break; + case 84: r = kernel_tex_image_interp(__tex_image_084, x, y); break; + case 85: r = kernel_tex_image_interp(__tex_image_085, x, y); break; + case 86: r = kernel_tex_image_interp(__tex_image_086, x, y); break; + case 87: r = kernel_tex_image_interp(__tex_image_087, x, y); break; + case 88: r = kernel_tex_image_interp(__tex_image_088, x, y); break; + case 89: r = kernel_tex_image_interp(__tex_image_089, x, y); break; + case 90: r = kernel_tex_image_interp(__tex_image_090, x, y); break; + case 91: r = kernel_tex_image_interp(__tex_image_091, x, y); break; + case 92: r = kernel_tex_image_interp(__tex_image_092, x, y); break; + case 93: r = kernel_tex_image_interp(__tex_image_093, x, y); break; + case 94: r = kernel_tex_image_interp(__tex_image_094, x, y); break; + case 95: r = kernel_tex_image_interp(__tex_image_095, x, y); break; + case 96: r = kernel_tex_image_interp(__tex_image_096, x, y); break; + case 97: r = kernel_tex_image_interp(__tex_image_097, x, y); break; + case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break; + case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break; + default: + kernel_assert(0); + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } +#endif + + return r; +} + +__device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + uint id = node.y; + uint co_offset, out_offset, alpha_offset, srgb; + + decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb); + + float3 co = stack_load_float3(stack, co_offset); + float4 f = svm_image_texture(kg, id, co.x, co.y); + float3 r = make_float3(f.x, f.y, f.z); + + if(srgb) { + r.x = color_srgb_to_scene_linear(r.x); + r.y = color_srgb_to_scene_linear(r.y); + r.z = color_srgb_to_scene_linear(r.z); + } + + if(stack_valid(out_offset)) + stack_store_float3(stack, out_offset, r); + if(stack_valid(alpha_offset)) + stack_store_float(stack, alpha_offset, f.w); +} + +__device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) +{ + uint id = node.y; + uint co_offset, out_offset, alpha_offset, srgb; + + decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb); + + float3 co = stack_load_float3(stack, co_offset); + float u = (atan2f(co.y, co.x) + M_PI_F)/(2*M_PI_F); + float v = atan2f(co.z, hypotf(co.x, co.y))/M_PI_F + 0.5f; + float4 f = svm_image_texture(kg, id, u, v); + float3 r = make_float3(f.x, f.y, f.z); + + if(srgb) { + r.x = color_srgb_to_scene_linear(r.x); + r.y = color_srgb_to_scene_linear(r.y); + r.z = color_srgb_to_scene_linear(r.z); + } + + if(stack_valid(out_offset)) + stack_store_float3(stack, out_offset, r); + if(stack_valid(alpha_offset)) + stack_store_float(stack, alpha_offset, f.w); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h new file mode 100644 index 00000000000..1b13fd93a0f --- /dev/null +++ b/intern/cycles/kernel/svm/svm_light_path.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Light Path Node */ + +__device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uint out_offset, int path_flag) +{ + float info = 0.0f; + + switch(type) { + case NODE_LP_camera: info = (path_flag & PATH_RAY_CAMERA)? 1.0f: 0.0f; break; + case NODE_LP_shadow: info = (path_flag & PATH_RAY_SHADOW)? 1.0f: 0.0f; break; + case NODE_LP_diffuse: info = (path_flag & PATH_RAY_DIFFUSE)? 1.0f: 0.0f; break; + case NODE_LP_glossy: info = (path_flag & PATH_RAY_GLOSSY)? 1.0f: 0.0f; break; + case NODE_LP_singular: info = (path_flag & PATH_RAY_SINGULAR)? 1.0f: 0.0f; break; + case NODE_LP_reflection: info = (path_flag & PATH_RAY_REFLECT)? 1.0f: 0.0f; break; + case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break; + case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break; + } + + stack_store_float(stack, out_offset, info); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_magic.h b/intern/cycles/kernel/svm/svm_magic.h new file mode 100644 index 00000000000..65d37937e1e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_magic.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Magic */ + +__device_noinline float3 svm_magic(float3 p, int n, float distortion) +{ + float x = sinf((p.x + p.y + p.z)*5.0f); + float y = cosf((-p.x + p.y - p.z)*5.0f); + float z = -cosf((-p.x - p.y + p.z)*5.0f); + + if(n > 0) { + x *= distortion; + y *= distortion; + z *= distortion; + y = -cosf(x-y+z); + y *= distortion; + + if(n > 1) { + x= cosf(x-y-z); + x *= distortion; + + if(n > 2) { + z= sinf(-x-y-z); + z *= distortion; + + if(n > 3) { + x= -cosf(-x+y-z); + x *= distortion; + + if(n > 4) { + y= -sinf(-x+y+z); + y *= distortion; + + if(n > 5) { + y= -cosf(-x+y+z); + y *= distortion; + + if(n > 6) { + x= cosf(x+y+z); + x *= distortion; + + if(n > 7) { + z= sinf(x+y-z); + z *= distortion; + + if(n > 8) { + x= -cosf(-x-y+z); + x *= distortion; + + if(n > 9) { + y= -sinf(x-y+z); + y *= distortion; + } + } + } + } + } + } + } + } + } + } + + if(distortion != 0.0f) { + distortion *= 2.0f; + x /= distortion; + y /= distortion; + z /= distortion; + } + + return make_float3(0.5f - x, 0.5f - y, 0.5f - z); +} + +__device void svm_node_tex_magic(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint depth; + uint scale_offset, distortion_offset, co_offset, fac_offset, color_offset; + + decode_node_uchar4(node.y, &depth, &color_offset, &fac_offset, NULL); + decode_node_uchar4(node.z, &co_offset, &scale_offset, &distortion_offset, NULL); + + uint4 node2 = read_node(kg, offset); + float3 co = stack_load_float3(stack, co_offset); + float scale = stack_load_float_default(stack, scale_offset, node2.x); + float distortion = stack_load_float_default(stack, distortion_offset, node2.y); + + float3 color = svm_magic(co*scale, depth, distortion); + + if(stack_valid(fac_offset)) + stack_store_float(stack, fac_offset, average(color)); + if(stack_valid(color_offset)) + stack_store_float3(stack, color_offset, color); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h new file mode 100644 index 00000000000..7633c3e783b --- /dev/null +++ b/intern/cycles/kernel/svm/svm_mapping.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Mapping Node */ + +__device void svm_node_mapping(KernelGlobals *kg, ShaderData *sd, float *stack, uint vec_offset, uint out_offset, int *offset) +{ + float3 v = stack_load_float3(stack, vec_offset); + + Transform tfm; + tfm.x = read_node_float(kg, offset); + tfm.y = read_node_float(kg, offset); + tfm.z = read_node_float(kg, offset); + tfm.w = read_node_float(kg, offset); + + float3 r = transform(&tfm, v); + stack_store_float3(stack, out_offset, r); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_math.h b/intern/cycles/kernel/svm/svm_math.h new file mode 100644 index 00000000000..bc2f774097e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_math.h @@ -0,0 +1,186 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device float safe_asinf(float a) +{ + if(a <= -1.0f) + return -M_PI_2_F; + else if(a >= 1.0f) + return M_PI_2_F; + + return asinf(a); +} + +__device float safe_acosf(float a) +{ + if(a <= -1.0f) + return M_PI_F; + else if(a >= 1.0f) + return 0.0f; + + return acosf(a); +} + +__device float safe_powf(float a, float b) +{ + if(b == 0.0f) + return 1.0f; + if(a == 0.0f) + return 0.0f; + if(a < 0.0f && b != (int)b) + return 0.0f; + + return powf(a, b); +} + +__device float safe_logf(float a, float b) +{ + if(a < 0.0f || b < 0.0f) + return 0.0f; + + return logf(a)/logf(b); +} + +__device float safe_divide(float a, float b) +{ + float result; + + if(b == 0.0f) + result = 0.0f; + else + result = a/b; + + return result; +} + +__device float svm_math(NodeMath type, float Fac1, float Fac2) +{ + float Fac; + + if(type == NODE_MATH_ADD) + Fac = Fac1 + Fac2; + else if(type == NODE_MATH_SUBTRACT) + Fac = Fac1 - Fac2; + else if(type == NODE_MATH_MULTIPLY) + Fac = Fac1*Fac2; + else if(type == NODE_MATH_DIVIDE) + Fac = safe_divide(Fac1, Fac2); + else if(type == NODE_MATH_SINE) + Fac = sinf(Fac1); + else if(type == NODE_MATH_COSINE) + Fac = cosf(Fac1); + else if(type == NODE_MATH_TANGENT) + Fac = tanf(Fac1); + else if(type == NODE_MATH_ARCSINE) + Fac = safe_asinf(Fac1); + else if(type == NODE_MATH_ARCCOSINE) + Fac = safe_acosf(Fac1); + else if(type == NODE_MATH_ARCTANGENT) + Fac = atanf(Fac1); + else if(type == NODE_MATH_POWER) + Fac = safe_powf(Fac1, Fac2); + else if(type == NODE_MATH_LOGARITHM) + Fac = safe_logf(Fac1, Fac2); + else if(type == NODE_MATH_MINIMUM) + Fac = fminf(Fac1, Fac2); + else if(type == NODE_MATH_MAXIMUM) + Fac = fmaxf(Fac1, Fac2); + else if(type == NODE_MATH_ROUND) + Fac = floorf(Fac1 + 0.5f); + else if(type == NODE_MATH_LESS_THAN) + Fac = Fac1 < Fac2; + else if(type == NODE_MATH_GREATER_THAN) + Fac = Fac1 > Fac2; + else + Fac = 0.0f; + + return Fac; +} + +__device float average_fac(float3 v) +{ + return (fabsf(v.x) + fabsf(v.y) + fabsf(v.z))/3.0f; +} + +__device void svm_vector_math(float *Fac, float3 *Vector, NodeVectorMath type, float3 Vector1, float3 Vector2) +{ + if(type == NODE_VECTOR_MATH_ADD) { + *Vector = Vector1 + Vector2; + *Fac = average_fac(*Vector); + } + else if(type == NODE_VECTOR_MATH_SUBTRACT) { + *Vector = Vector1 - Vector2; + *Fac = average_fac(*Vector); + } + else if(type == NODE_VECTOR_MATH_AVERAGE) { + *Fac = len(Vector1 + Vector2); + *Vector = normalize(Vector1 + Vector2); + } + else if(type == NODE_VECTOR_MATH_DOT_PRODUCT) { + *Fac = dot(Vector1, Vector2); + *Vector = make_float3(0.0f, 0.0f, 0.0f); + } + else if(type == NODE_VECTOR_MATH_CROSS_PRODUCT) { + float3 c = cross(Vector1, Vector2); + *Fac = len(c); + *Vector = normalize(c); + } + else if(type == NODE_VECTOR_MATH_NORMALIZE) { + *Fac = len(Vector1); + *Vector = normalize(Vector1); + } + else { + *Fac = 0.0f; + *Vector = make_float3(0.0f, 0.0f, 0.0f); + } +} + +/* Nodes */ + +__device void svm_node_math(KernelGlobals *kg, ShaderData *sd, float *stack, uint itype, uint f1_offset, uint f2_offset, int *offset) +{ + NodeMath type = (NodeMath)itype; + float f1 = stack_load_float(stack, f1_offset); + float f2 = stack_load_float(stack, f2_offset); + float f = svm_math(type, f1, f2); + + uint4 node1 = read_node(kg, offset); + + stack_store_float(stack, node1.y, f); +} + +__device void svm_node_vector_math(KernelGlobals *kg, ShaderData *sd, float *stack, uint itype, uint v1_offset, uint v2_offset, int *offset) +{ + NodeVectorMath type = (NodeVectorMath)itype; + float3 v1 = stack_load_float3(stack, v1_offset); + float3 v2 = stack_load_float3(stack, v2_offset); + float f; + float3 v; + + svm_vector_math(&f, &v, type, v1, v2); + + uint4 node1 = read_node(kg, offset); + + if(stack_valid(node1.y)) stack_store_float(stack, node1.y, f); + if(stack_valid(node1.z)) stack_store_float3(stack, node1.z, v); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h new file mode 100644 index 00000000000..c9e6cdf43b9 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_mix.h @@ -0,0 +1,395 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device float3 rgb_to_hsv(float3 rgb) +{ + float cmax, cmin, h, s, v, cdelta; + float3 c; + + cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z)); + cmin = min(rgb.x, min(rgb.y, rgb.z)); + cdelta = cmax - cmin; + + v = cmax; + + if(cmax != 0.0f) { + s = cdelta/cmax; + } + else { + s = 0.0f; + h = 0.0f; + } + + if(s == 0.0f) { + h = 0.0f; + } + else { + float3 cmax3 = make_float3(cmax, cmax, cmax); + c = (cmax3 - rgb)/cdelta; + + if(rgb.x == cmax) h = c.z - c.y; + else if(rgb.y == cmax) h = 2.0f + c.x - c.z; + else h = 4.0f + c.y - c.x; + + h /= 6.0f; + + if(h < 0.0f) + h += 1.0f; + } + + return make_float3(h, s, v); +} + +__device float3 hsv_to_rgb(float3 hsv) +{ + float i, f, p, q, t, h, s, v; + float3 rgb; + + h = hsv.x; + s = hsv.y; + v = hsv.z; + + if(s==0.0f) { + rgb = make_float3(v, v, v); + } + else { + if(h==1.0f) + h = 0.0f; + + h *= 6.0f; + i = floor(h); + f = h - i; + rgb = make_float3(f, f, f); + p = v*(1.0f-s); + q = v*(1.0f-(s*f)); + t = v*(1.0f-(s*(1.0f-f))); + + if(i == 0.0f) rgb = make_float3(v, t, p); + else if(i == 1.0f) rgb = make_float3(q, v, p); + else if(i == 2.0f) rgb = make_float3(p, v, t); + else if(i == 3.0f) rgb = make_float3(p, q, v); + else if(i == 4.0f) rgb = make_float3(t, p, v); + else rgb = make_float3(v, p, q); + } + + return rgb; +} + +__device float3 svm_lerp(const float3 a, const float3 b, float t) +{ + return (a * (1.0f - t) + b * t); +} + +__device float3 svm_mix_blend(float t, float3 col1, float3 col2) +{ + return svm_lerp(col1, col2, t); +} + +__device float3 svm_mix_add(float t, float3 col1, float3 col2) +{ + return svm_lerp(col1, col1 + col2, t); +} + +__device float3 svm_mix_mul(float t, float3 col1, float3 col2) +{ + return svm_lerp(col1, col1 * col2, t); +} + +__device float3 svm_mix_screen(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + float3 one = make_float3(1.0f, 1.0f, 1.0f); + float3 tm3 = make_float3(tm, tm, tm); + + return one - (tm3 + t*(one - col2))*(one - col1); +} + +__device float3 svm_mix_overlay(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(outcol.x < 0.5f) + outcol.x *= tm + 2.0f*t*col2.x; + else + outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x); + + if(outcol.y < 0.5f) + outcol.y *= tm + 2.0f*t*col2.y; + else + outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y); + + if(outcol.z < 0.5f) + outcol.z *= tm + 2.0f*t*col2.z; + else + outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z); + + return outcol; +} + +__device float3 svm_mix_sub(float t, float3 col1, float3 col2) +{ + return svm_lerp(col1, col1 - col2, t); +} + +__device float3 svm_mix_div(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x; + if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y; + if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z; + + return outcol; +} + +__device float3 svm_mix_diff(float t, float3 col1, float3 col2) +{ + return svm_lerp(col1, fabs(col1 - col2), t); +} + +__device float3 svm_mix_dark(float t, float3 col1, float3 col2) +{ + return min(col1, col2*t); +} + +__device float3 svm_mix_light(float t, float3 col1, float3 col2) +{ + return max(col1, col2*t); +} + +__device float3 svm_mix_dodge(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + if(outcol.x != 0.0f) { + float tmp = 1.0f - t*col2.x; + if(tmp <= 0.0f) + outcol.x = 1.0f; + else if((tmp = outcol.x/tmp) > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + } + if(outcol.y != 0.0f) { + float tmp = 1.0f - t*col2.y; + if(tmp <= 0.0f) + outcol.y = 1.0f; + else if((tmp = outcol.y/tmp) > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + } + if(outcol.z != 0.0f) { + float tmp = 1.0f - t*col2.z; + if(tmp <= 0.0f) + outcol.z = 1.0f; + else if((tmp = outcol.z/tmp) > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + } + + return outcol; +} + +__device float3 svm_mix_burn(float t, float3 col1, float3 col2) +{ + float tmp, tm = 1.0f - t; + + float3 outcol = col1; + + tmp = tm + t*col2.x; + if(tmp <= 0.0f) + outcol.x = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f) + outcol.x = 0.0f; + else if(tmp > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + + tmp = tm + t*col2.y; + if(tmp <= 0.0f) + outcol.y = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f) + outcol.y = 0.0f; + else if(tmp > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + + tmp = tm + t*col2.z; + if(tmp <= 0.0f) + outcol.z = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f) + outcol.z = 0.0f; + else if(tmp > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + + return outcol; +} + +__device float3 svm_mix_hue(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + float3 tmp = hsv_to_rgb(hsv); + + outcol = svm_lerp(outcol, tmp, t); + } + + return outcol; +} + +__device float3 svm_mix_sat(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + float3 hsv = rgb_to_hsv(outcol); + + if(hsv.y != 0.0f) { + float3 hsv2 = rgb_to_hsv(col2); + + hsv.y = tm*hsv.y + t*hsv2.y; + outcol = hsv_to_rgb(hsv); + } + + return outcol; +} + +__device float3 svm_mix_val(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 hsv = rgb_to_hsv(col1); + float3 hsv2 = rgb_to_hsv(col2); + + hsv.z = tm*hsv.z + t*hsv2.z; + + return hsv_to_rgb(hsv); +} + +__device float3 svm_mix_color(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + hsv.y = hsv2.y; + float3 tmp = hsv_to_rgb(hsv); + + outcol = svm_lerp(outcol, tmp, t); + } + + return outcol; +} + +__device float3 svm_mix_soft(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 one= make_float3(1.0f, 1.0f, 1.0f); + float3 scr= one - (one - col2)*(one - col1); + + return tm*col1 + t*((one - col1)*col2*col1 + col1*scr); +} + +__device float3 svm_mix_linear(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + if(col2.x > 0.5f) + outcol.x= col1.x + t*(2.0f*(col2.x - 0.5f)); + else + outcol.x= col1.x + t*(2.0f*(col2.x) - 1.0f); + + if(col2.y > 0.5f) + outcol.y= col1.y + t*(2.0f*(col2.y - 0.5f)); + else + outcol.y= col1.y + t*(2.0f*(col2.y) - 1.0f); + + if(col2.z > 0.5f) + outcol.z= col1.z + t*(2.0f*(col2.z - 0.5f)); + else + outcol.z= col1.z + t*(2.0f*(col2.z) - 1.0f); + + return outcol; +} + +__device float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) +{ + float t = clamp(fac, 0.0f, 1.0f); + + switch(type) { + case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); + case NODE_MIX_ADD: return svm_mix_add(t, c1, c2); + case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2); + case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2); + case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2); + case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2); + case NODE_MIX_DIV: return svm_mix_div(t, c1, c2); + case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2); + case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2); + case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2); + case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2); + case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2); + case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2); + case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2); + case NODE_MIX_VAL: return svm_mix_val (t, c1, c2); + case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2); + case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); + case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2); + } + + return make_float3(0.0f, 0.0f, 0.0f); +} + +/* Node */ + +__device void svm_node_mix(KernelGlobals *kg, ShaderData *sd, float *stack, uint fac_offset, uint c1_offset, uint c2_offset, int *offset) +{ + /* read extra data */ + uint4 node1 = read_node(kg, offset); + + float fac = stack_load_float(stack, fac_offset); + float3 c1 = stack_load_float3(stack, c1_offset); + float3 c2 = stack_load_float3(stack, c2_offset); + float3 result = svm_mix((NodeMix)node1.y, fac, c1, c2); + + stack_store_float3(stack, node1.z, result); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h new file mode 100644 index 00000000000..34cf7868f07 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_musgrave.h @@ -0,0 +1,240 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Musgrave fBm + * + * H: fractal increment parameter + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * + * from "Texturing and Modelling: A procedural approach" + */ + +__device_noinline float noise_musgrave_fBm(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves) +{ + float rmd; + float value = 0.0f; + float pwr = 1.0f; + float pwHL = pow(lacunarity, -H); + int i; + + for(i = 0; i < (int)octaves; i++) { + value += snoise(p) * pwr; + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0f) + value += rmd * snoise(p) * pwr; + + return value; +} + +/* Musgrave Multifractal + * + * H: highest fractal dimension + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + */ + +__device_noinline float noise_musgrave_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves) +{ + float rmd; + float value = 1.0f; + float pwr = 1.0f; + float pwHL = pow(lacunarity, -H); + int i; + + for(i = 0; i < (int)octaves; i++) { + value *= (pwr * snoise(p) + 1.0f); + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0f) + value *= (rmd * pwr * snoise(p) + 1.0f); /* correct? */ + + return value; +} + +/* Musgrave Heterogeneous Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +__device_noinline float noise_musgrave_hetero_terrain(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset) +{ + float value, increment, rmd; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + /* first unscaled octave of function; later octaves are scaled */ + value = offset + snoise(p); + p *= lacunarity; + + for(i = 1; i < (int)octaves; i++) { + increment = (snoise(p) + offset) * pwr * value; + value += increment; + pwr *= pwHL; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0f) { + increment = (snoise(p) + offset) * pwr * value; + value += rmd * increment; + } + + return value; +} + +/* Hybrid Additive/Multiplicative Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +__device_noinline float noise_musgrave_hybrid_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset, float gain) +{ + float result, signal, weight, rmd; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + result = snoise(p) + offset; + weight = gain * result; + p *= lacunarity; + + for(i = 1; (weight > 0.001f) && (i < (int)octaves); i++) { + if(weight > 1.0f) + weight = 1.0f; + + signal = (snoise(p) + offset) * pwr; + pwr *= pwHL; + result += weight * signal; + weight *= gain * signal; + p *= lacunarity; + } + + rmd = octaves - floor(octaves); + if(rmd != 0.0f) + result += rmd * ((snoise(p) + offset) * pwr); + + return result; +} + +/* Ridged Multifractal Terrain + * + * H: fractal dimension of the roughest area + * lacunarity: gap between successive frequencies + * octaves: number of frequencies in the fBm + * offset: raises the terrain from `sea level' + */ + +__device_noinline float noise_musgrave_ridged_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset, float gain) +{ + float result, signal, weight; + float pwHL = pow(lacunarity, -H); + float pwr = pwHL; + int i; + + signal = offset - fabsf(snoise(p)); + signal *= signal; + result = signal; + weight = 1.0f; + + for(i = 1; i < (int)octaves; i++) { + p *= lacunarity; + weight = clamp(signal * gain, 0.0f, 1.0f); + signal = offset - fabsf(snoise(p)); + signal *= signal; + signal *= weight; + result += signal * pwr; + pwr *= pwHL; + } + + return result; +} + +/* Shader */ + +__device float svm_musgrave(NodeMusgraveType type, float dimension, float lacunarity, float octaves, float offset, float intensity, float gain, float scale, float3 p) +{ + NodeNoiseBasis basis = NODE_NOISE_PERLIN; + p *= scale; + + if(type == NODE_MUSGRAVE_MULTIFRACTAL) + return intensity*noise_musgrave_multi_fractal(p, basis, dimension, lacunarity, octaves); + else if(type == NODE_MUSGRAVE_FBM) + return intensity*noise_musgrave_fBm(p, basis, dimension, lacunarity, octaves); + else if(type == NODE_MUSGRAVE_HYBRID_MULTIFRACTAL) + return intensity*noise_musgrave_hybrid_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain); + else if(type == NODE_MUSGRAVE_RIDGED_MULTIFRACTAL) + return intensity*noise_musgrave_ridged_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain); + else if(type == NODE_MUSGRAVE_HETERO_TERRAIN) + return intensity*noise_musgrave_hetero_terrain(p, basis, dimension, lacunarity, octaves, offset); + + return 0.0f; +} + +__device void svm_node_tex_musgrave(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint4 node2 = read_node(kg, offset); + uint4 node3 = read_node(kg, offset); + + uint type, co_offset, color_offset, fac_offset; + uint dimension_offset, lacunarity_offset, detail_offset, offset_offset; + uint gain_offset, scale_offset; + + decode_node_uchar4(node.y, &type, &co_offset, &color_offset, &fac_offset); + decode_node_uchar4(node.z, &dimension_offset, &lacunarity_offset, &detail_offset, &offset_offset); + decode_node_uchar4(node.z, &gain_offset, &scale_offset, NULL, NULL); + + float3 co = stack_load_float3(stack, co_offset); + float dimension = stack_load_float_default(stack, dimension_offset, node2.x); + float lacunarity = stack_load_float_default(stack, lacunarity_offset, node2.y); + float detail = stack_load_float_default(stack, detail_offset, node2.z); + float foffset = stack_load_float_default(stack, offset_offset, node2.w); + float gain = stack_load_float_default(stack, gain_offset, node3.x); + float scale = stack_load_float_default(stack, scale_offset, node3.y); + + dimension = fmaxf(dimension, 1e-5f); + detail = clamp(detail, 0.0f, 16.0f); + lacunarity = fmaxf(lacunarity, 1e-5f); + + float f = svm_musgrave((NodeMusgraveType)type, + dimension, lacunarity, detail, foffset, 1.0f, gain, scale, co); + + if(stack_valid(fac_offset)) + stack_store_float(stack, fac_offset, f); + if(stack_valid(color_offset)) + stack_store_float3(stack, color_offset, make_float3(f, f, f)); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h new file mode 100644 index 00000000000..28ad028ad0e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_noise.h @@ -0,0 +1,213 @@ +/* + * Adapted from Open Shading Language with this license: + * + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011, Blender Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Sony Pictures Imageworks nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +CCL_NAMESPACE_BEGIN + +__device int quick_floor(float x) +{ + return (int)x - ((x < 0) ? 1 : 0); +} + +__device float bits_to_01(uint bits) +{ + return bits * (1.0f/(float)0xFFFFFFFF); +} + +__device uint hash(uint kx, uint ky, uint kz) +{ + // define some handy macros +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + // now hash the data! + uint a, b, c, len = 3; + a = b = c = 0xdeadbeef + (len << 2) + 13; + + c += kz; + b += ky; + a += kx; + final(a, b, c); + + return c; + // macros not needed anymore +#undef rot +#undef final +} + +__device int imod(int a, int b) +{ + a %= b; + return a < 0 ? a + b : a; +} + +__device uint phash(int kx, int ky, int kz, int3 p) +{ + return hash(imod(kx, p.x), imod(ky, p.y), imod(kz, p.z)); +} + +__device float floorfrac(float x, int* i) +{ + *i = quick_floor(x); + return x - *i; +} + +__device float fade(float t) +{ + return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); +} + +__device float nerp(float t, float a, float b) +{ + return (1.0f - t) * a + t * b; +} + +__device float grad(int hash, float x, float y, float z) +{ + // use vectors pointing to the edges of the cube + int h = hash & 15; + float u = h<8 ? x : y; + float v = h<4 ? y : h==12||h==14 ? x : z; + return ((h&1) ? -u : u) + ((h&2) ? -v : v); +} + +__device float scale3(float result) +{ + return 0.9820f * result; +} + +__device_noinline float perlin(float x, float y, float z) +{ + int X; float fx = floorfrac(x, &X); + int Y; float fy = floorfrac(y, &Y); + int Z; float fz = floorfrac(z, &Z); + + float u = fade(fx); + float v = fade(fy); + float w = fade(fz); + + float result; + + result = nerp (w, nerp (v, nerp (u, grad (hash (X , Y , Z ), fx , fy , fz ), + grad (hash (X+1, Y , Z ), fx-1.0f, fy , fz )), + nerp (u, grad (hash (X , Y+1, Z ), fx , fy-1.0f, fz ), + grad (hash (X+1, Y+1, Z ), fx-1.0f, fy-1.0f, fz ))), + nerp (v, nerp (u, grad (hash (X , Y , Z+1), fx , fy , fz-1.0f ), + grad (hash (X+1, Y , Z+1), fx-1.0f, fy , fz-1.0f )), + nerp (u, grad (hash (X , Y+1, Z+1), fx , fy-1.0f, fz-1.0f ), + grad (hash (X+1, Y+1, Z+1), fx-1.0f, fy-1.0f, fz-1.0f )))); + return scale3(result); +} + +__device_noinline float perlin_periodic(float x, float y, float z, float3 pperiod) +{ + int X; float fx = floorfrac(x, &X); + int Y; float fy = floorfrac(y, &Y); + int Z; float fz = floorfrac(z, &Z); + + int3 p; + + p.x = max(quick_floor(pperiod.x), 1); + p.y = max(quick_floor(pperiod.y), 1); + p.z = max(quick_floor(pperiod.z), 1); + + float u = fade(fx); + float v = fade(fy); + float w = fade(fz); + + float result; + + result = nerp (w, nerp (v, nerp (u, grad (phash (X , Y , Z , p), fx , fy , fz ), + grad (phash (X+1, Y , Z , p), fx-1.0f, fy , fz )), + nerp (u, grad (phash (X , Y+1, Z , p), fx , fy-1.0f, fz ), + grad (phash (X+1, Y+1, Z , p), fx-1.0f, fy-1.0f, fz ))), + nerp (v, nerp (u, grad (phash (X , Y , Z+1, p), fx , fy , fz-1.0f ), + grad (phash (X+1, Y , Z+1, p), fx-1.0f, fy , fz-1.0f )), + nerp (u, grad (phash (X , Y+1, Z+1, p), fx , fy-1.0f, fz-1.0f ), + grad (phash (X+1, Y+1, Z+1, p), fx-1.0f, fy-1.0f, fz-1.0f )))); + return scale3(result); +} + +/* perlin noise in range 0..1 */ +__device float noise(float3 p) +{ + float r = perlin(p.x, p.y, p.z); + return 0.5f*r + 0.5f; +} + +/* perlin noise in range -1..1 */ +__device float snoise(float3 p) +{ + return perlin(p.x, p.y, p.z); +} + +/* cell noise */ +__device_noinline float cellnoise(float3 p) +{ + uint ix = quick_floor(p.x); + uint iy = quick_floor(p.y); + uint iz = quick_floor(p.z); + + return bits_to_01(hash(ix, iy, iz)); +} + +__device float3 cellnoise_color(float3 p) +{ + float r = cellnoise(p); + float g = cellnoise(make_float3(p.y, p.x, p.z)); + float b = cellnoise(make_float3(p.y, p.z, p.x)); + + return make_float3(r, g, b); +} + +/* periodic perlin noise in range 0..1 */ +__device float pnoise(float3 p, float3 pperiod) +{ + float r = perlin_periodic(p.x, p.y, p.z, pperiod); + return 0.5f*r + 0.5f; +} + +/* periodic perlin noise in range -1..1 */ +__device float psnoise(float3 p, float3 pperiod) +{ + return perlin_periodic(p.x, p.y, p.z, pperiod); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h new file mode 100644 index 00000000000..7421597040e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_noisetex.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Clouds */ + +__device_inline void svm_noise(float3 p, float scale, float detail, float distortion, float *fac, float3 *color) +{ + NodeNoiseBasis basis = NODE_NOISE_PERLIN; + int hard = 0; + + p *= scale; + + if(distortion != 0.0f) { + float3 r, offset = make_float3(13.5f, 13.5f, 13.5f); + + r.x = noise_basis(p + offset, basis) * distortion; + r.y = noise_basis(p, basis) * distortion; + r.z = noise_basis(p - offset, basis) * distortion; + + p += r; + } + + *fac = noise_turbulence(p, basis, detail, hard); + *color = make_float3(*fac, + noise_turbulence(make_float3(p.y, p.x, p.z), basis, detail, hard), + noise_turbulence(make_float3(p.y, p.z, p.x), basis, detail, hard)); +} + +__device void svm_node_tex_noise(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint co_offset, scale_offset, detail_offset, distortion_offset, fac_offset, color_offset; + + decode_node_uchar4(node.y, &co_offset, &scale_offset, &detail_offset, &distortion_offset); + + uint4 node2 = read_node(kg, offset); + + float scale = stack_load_float_default(stack, scale_offset, node2.x); + float detail = stack_load_float_default(stack, detail_offset, node2.y); + float distortion = stack_load_float_default(stack, distortion_offset, node2.z); + float3 co = stack_load_float3(stack, co_offset); + + float3 color; + float f; + + svm_noise(co, scale, detail, distortion, &f, &color); + + decode_node_uchar4(node.z, &color_offset, &fac_offset, NULL, NULL); + + if(stack_valid(fac_offset)) + stack_store_float(stack, fac_offset, f); + if(stack_valid(color_offset)) + stack_store_float3(stack, color_offset, color); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_sky.h b/intern/cycles/kernel/svm/svm_sky.h new file mode 100644 index 00000000000..eaba4d18365 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_sky.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +__device float3 xyY_to_xyz(float x, float y, float Y) +{ + float X, Z; + + if(y != 0.0f) X = (x / y) * Y; + else X = 0.0f; + + if(y != 0.0f && Y != 0.0f) Z = (1.0f - x - y) / y * Y; + else Z = 0.0f; + + return make_float3(X, Y, Z); +} + +__device float3 xyz_to_rgb(float x, float y, float z) +{ + return make_float3(3.240479f * x + -1.537150f * y + -0.498535f * z, + -0.969256f * x + 1.875991f * y + 0.041556f * z, + 0.055648f * x + -0.204043f * y + 1.057311f * z); +} + +/* + * "A Practical Analytic Model for Daylight" + * A. J. Preetham, Peter Shirley, Brian Smits + */ + +__device float sky_angle_between(float thetav, float phiv, float theta, float phi) +{ + float cospsi = sinf(thetav)*sinf(theta)*cosf(phi - phiv) + cosf(thetav)*cosf(theta); + return safe_acosf(cospsi); +} + +__device float sky_perez_function(__constant float *lam, float theta, float gamma) +{ + float ctheta = cosf(theta); + float cgamma = cosf(gamma); + + return (1.0f + lam[0]*expf(lam[1]/ctheta)) * (1.0f + lam[2]*expf(lam[3]*gamma) + lam[4]*cgamma*cgamma); +} + +__device float3 sky_radiance(KernelGlobals *kg, float3 dir) +{ + /* convert vector to spherical coordinates */ + float2 spherical = direction_to_spherical(dir); + float theta = spherical.x; + float phi = spherical.y; + + /* angle between sun direction and dir */ + float gamma = sky_angle_between(theta, phi, kernel_data.sunsky.theta, kernel_data.sunsky.phi); + + /* clamp theta to horizon */ + theta = min(theta, M_PI_2_F - 0.001f); + + /* compute xyY color space values */ + float x = kernel_data.sunsky.zenith_x * sky_perez_function(kernel_data.sunsky.perez_x, theta, gamma); + float y = kernel_data.sunsky.zenith_y * sky_perez_function(kernel_data.sunsky.perez_y, theta, gamma); + float Y = kernel_data.sunsky.zenith_Y * sky_perez_function(kernel_data.sunsky.perez_Y, theta, gamma); + + /* convert to RGB */ + float3 xyz = xyY_to_xyz(x, y, Y); + return xyz_to_rgb(xyz.x, xyz.y, xyz.z); +} + +__device void svm_node_tex_sky(KernelGlobals *kg, ShaderData *sd, float *stack, uint dir_offset, uint out_offset) +{ + float3 dir = stack_load_float3(stack, dir_offset); + float3 f = sky_radiance(kg, dir); + + stack_store_float3(stack, out_offset, f); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h new file mode 100644 index 00000000000..bcf3716ae57 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -0,0 +1,170 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Texture Coordinate Node */ + +__device float3 svm_background_offset(KernelGlobals *kg) +{ + Transform cameratoworld = kernel_data.cam.cameratoworld; + return make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w); +} + +__device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ + float3 data; + + switch(type) { + case NODE_TEXCO_OBJECT: { + if(sd->object != ~0) { + Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); + data = transform(&tfm, sd->P); + } + else + data = sd->P; + break; + } + case NODE_TEXCO_CAMERA: { + Transform tfm = kernel_data.cam.worldtocamera; + + if(sd->object != ~0) + data = transform(&tfm, sd->P); + else + data = transform(&tfm, sd->P + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_WINDOW: { + Transform tfm = kernel_data.cam.worldtondc; + + if(sd->object != ~0) + data = transform(&tfm, sd->P); + else + data = transform(&tfm, sd->P + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_REFLECTION: { + if(sd->object != ~0) + data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N; + else + data = sd->I; + break; + } + } + + stack_store_float3(stack, out_offset, data); +} + +__device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float3 data; + + switch(type) { + case NODE_TEXCO_OBJECT: { + if(sd->object != ~0) { + Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); + data = transform(&tfm, sd->P + sd->dP.dx); + } + else + data = sd->P + sd->dP.dx; + break; + } + case NODE_TEXCO_CAMERA: { + Transform tfm = kernel_data.cam.worldtocamera; + + if(sd->object != ~0) + data = transform(&tfm, sd->P + sd->dP.dx); + else + data = transform(&tfm, sd->P + sd->dP.dx + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_WINDOW: { + Transform tfm = kernel_data.cam.worldtondc; + + if(sd->object != ~0) + data = transform(&tfm, sd->P + sd->dP.dx); + else + data = transform(&tfm, sd->P + sd->dP.dx + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_REFLECTION: { + if(sd->object != ~0) + data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N; + else + data = sd->I; + break; + } + } + + stack_store_float3(stack, out_offset, data); +#else + svm_node_tex_coord(kg, sd, stack, type, out_offset); +#endif +} + +__device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ +#ifdef __RAY_DIFFERENTIALS__ + float3 data; + + switch(type) { + case NODE_TEXCO_OBJECT: { + if(sd->object != ~0) { + Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM); + data = transform(&tfm, sd->P + sd->dP.dy); + } + else + data = sd->P + sd->dP.dy; + break; + } + case NODE_TEXCO_CAMERA: { + Transform tfm = kernel_data.cam.worldtocamera; + + if(sd->object != ~0) + data = transform(&tfm, sd->P + sd->dP.dy); + else + data = transform(&tfm, sd->P + sd->dP.dy + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_WINDOW: { + Transform tfm = kernel_data.cam.worldtondc; + + if(sd->object != ~0) + data = transform(&tfm, sd->P + sd->dP.dy); + else + data = transform(&tfm, sd->P + sd->dP.dy + svm_background_offset(kg)); + break; + } + case NODE_TEXCO_REFLECTION: { + if(sd->object != ~0) + data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N; + else + data = sd->I; + break; + } + } + + stack_store_float3(stack, out_offset, data); +#else + svm_node_tex_coord(kg, sd, stack, type, out_offset); +#endif +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_texture.h b/intern/cycles/kernel/svm/svm_texture.h new file mode 100644 index 00000000000..82797018d74 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_texture.h @@ -0,0 +1,259 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Voronoi Distances */ + +__device float voronoi_distance(NodeDistanceMetric distance_metric, float3 d, float e) +{ + if(distance_metric == NODE_VORONOI_DISTANCE_SQUARED) + return dot(d, d); + if(distance_metric == NODE_VORONOI_ACTUAL_DISTANCE) + return len(d); + if(distance_metric == NODE_VORONOI_MANHATTAN) + return fabsf(d.x) + fabsf(d.y) + fabsf(d.z); + if(distance_metric == NODE_VORONOI_CHEBYCHEV) + return fmaxf(fabsf(d.x), fmaxf(fabsf(d.y), fabsf(d.z))); + if(distance_metric == NODE_VORONOI_MINKOVSKY_H) + return sqrtf(fabsf(d.x)) + sqrtf(fabsf(d.y)) + sqrtf(fabsf(d.y)); + if(distance_metric == NODE_VORONOI_MINKOVSKY_4) + return sqrtf(sqrtf(dot(d*d, d*d))); + if(distance_metric == NODE_VORONOI_MINKOVSKY) + return powf(powf(fabsf(d.x), e) + powf(fabsf(d.y), e) + powf(fabsf(d.z), e), 1.0f/e); + + return 0.0f; +} + +/* Voronoi / Worley like */ + +__device_noinline void voronoi(float3 p, NodeDistanceMetric distance_metric, float e, float da[4], float3 pa[4]) +{ + /* returns distances in da and point coords in pa */ + int xx, yy, zz, xi, yi, zi; + + xi = (int)floorf(p.x); + yi = (int)floorf(p.y); + zi = (int)floorf(p.z); + + da[0] = 1e10f; + da[1] = 1e10f; + da[2] = 1e10f; + da[3] = 1e10f; + + pa[0] = make_float3(0.0f, 0.0f, 0.0f); + pa[1] = make_float3(0.0f, 0.0f, 0.0f); + pa[2] = make_float3(0.0f, 0.0f, 0.0f); + pa[3] = make_float3(0.0f, 0.0f, 0.0f); + + for(xx = xi-1; xx <= xi+1; xx++) { + for(yy = yi-1; yy <= yi+1; yy++) { + for(zz = zi-1; zz <= zi+1; zz++) { + float3 ip = make_float3((float)xx, (float)yy, (float)zz); + float3 vp = cellnoise_color(ip); + float3 pd = p - (vp + ip); + float d = voronoi_distance(distance_metric, pd, e); + + vp += ip; + + if(d < da[0]) { + da[3] = da[2]; + da[2] = da[1]; + da[1] = da[0]; + da[0] = d; + + pa[3] = pa[2]; + pa[2] = pa[1]; + pa[1] = pa[0]; + pa[0] = vp; + } + else if(d < da[1]) { + da[3] = da[2]; + da[2] = da[1]; + da[1] = d; + + pa[3] = pa[2]; + pa[2] = pa[1]; + pa[1] = vp; + } + else if(d < da[2]) { + da[3] = da[2]; + da[2] = d; + + pa[3] = pa[2]; + pa[2] = vp; + } + else if(d < da[3]) { + da[3] = d; + pa[3] = vp; + } + } + } + } +} + +__device float voronoi_Fn(float3 p, int n) +{ + float da[4]; + float3 pa[4]; + + voronoi(p, NODE_VORONOI_DISTANCE_SQUARED, 0, da, pa); + + return da[n]; +} + +__device float voronoi_FnFn(float3 p, int n1, int n2) +{ + float da[4]; + float3 pa[4]; + + voronoi(p, NODE_VORONOI_DISTANCE_SQUARED, 0, da, pa); + + return da[n2] - da[n1]; +} + +__device float voronoi_F1(float3 p) { return voronoi_Fn(p, 0); } +__device float voronoi_F2(float3 p) { return voronoi_Fn(p, 1); } +__device float voronoi_F3(float3 p) { return voronoi_Fn(p, 2); } +__device float voronoi_F4(float3 p) { return voronoi_Fn(p, 3); } +__device float voronoi_F1F2(float3 p) { return voronoi_FnFn(p, 0, 1); } + +__device float voronoi_Cr(float3 p) +{ + /* crackle type pattern, just a scale/clamp of F2-F1 */ + float t = 10.0f*voronoi_F1F2(p); + return (t > 1.0f)? 1.0f: t; +} + +__device float voronoi_F1S(float3 p) { return 2.0f*voronoi_F1(p) - 1.0f; } +__device float voronoi_F2S(float3 p) { return 2.0f*voronoi_F2(p) - 1.0f; } +__device float voronoi_F3S(float3 p) { return 2.0f*voronoi_F3(p) - 1.0f; } +__device float voronoi_F4S(float3 p) { return 2.0f*voronoi_F4(p) - 1.0f; } +__device float voronoi_F1F2S(float3 p) { return 2.0f*voronoi_F1F2(p) - 1.0f; } +__device float voronoi_CrS(float3 p) { return 2.0f*voronoi_Cr(p) - 1.0f; } + +/* Noise Bases */ + +__device float noise_basis(float3 p, NodeNoiseBasis basis) +{ + /* Only Perlin enabled for now, others break CUDA compile by making kernel + too big, with compile using > 4GB, due to everything being inlined. */ + +#if 0 + if(basis == NODE_NOISE_PERLIN) +#endif + return noise(p); +#if 0 + if(basis == NODE_NOISE_VORONOI_F1) + return voronoi_F1S(p); + if(basis == NODE_NOISE_VORONOI_F2) + return voronoi_F2S(p); + if(basis == NODE_NOISE_VORONOI_F3) + return voronoi_F3S(p); + if(basis == NODE_NOISE_VORONOI_F4) + return voronoi_F4S(p); + if(basis == NODE_NOISE_VORONOI_F2_F1) + return voronoi_F1F2S(p); + if(basis == NODE_NOISE_VORONOI_CRACKLE) + return voronoi_CrS(p); + if(basis == NODE_NOISE_CELL_NOISE) + return cellnoise(p); + + return 0.0f; +#endif +} + +/* Soft/Hard Noise */ + +__device float noise_basis_hard(float3 p, NodeNoiseBasis basis, int hard) +{ + float t = noise_basis(p, basis); + return (hard)? fabsf(2.0f*t - 1.0f): t; +} + +/* Waves */ + +__device float noise_wave(NodeWaveType wave, float a) +{ + if(wave == NODE_WAVE_SINE) { + return 0.5f + 0.5f*sin(a); + } + else if(wave == NODE_WAVE_SAW) { + float b = 2.0f*M_PI_F; + int n = (int)(a / b); + a -= n*b; + if(a < 0.0f) a += b; + + return a / b; + } + else if(wave == NODE_WAVE_TRI) { + float b = 2.0f*M_PI_F; + float rmax = 1.0f; + + return rmax - 2.0f*fabsf(floorf((a*(1.0f/b))+0.5f) - (a*(1.0f/b))); + } + + return 0.0f; +} + +/* Turbulence */ + +__device_noinline float noise_turbulence(float3 p, NodeNoiseBasis basis, float octaves, int hard) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + int i, n; + + octaves = clamp(octaves, 0.0f, 16.0f); + n= (int)octaves; + + for(i = 0; i <= n; i++) { + float t = noise_basis(fscale*p, basis); + + if(hard) + t = fabsf(2.0f*t - 1.0f); + + sum += t*amp; + amp *= 0.5f; + fscale *= 2.0f; + } + + float rmd = octaves - floor(octaves); + + if(rmd != 0.0f) { + float t = noise_basis(fscale*p, basis); + + if(hard) + t = fabsf(2.0f*t - 1.0f); + + float sum2 = sum + t*amp; + + sum *= ((float)(1 << n)/(float)((1 << (n+1)) - 1)); + sum2 *= ((float)(1 << (n+1))/(float)((1 << (n+2)) - 1)); + + return (1.0f - rmd)*sum + rmd*sum2; + } + else { + sum *= ((float)(1 << n)/(float)((1 << (n+1)) - 1)); + return sum; + } +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h new file mode 100644 index 00000000000..89fc413c539 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_types.h @@ -0,0 +1,299 @@ +/* + * 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. + */ + +#ifndef __SVM_TYPES_H__ +#define __SVM_TYPES_H__ + +CCL_NAMESPACE_BEGIN + +/* Stack */ + +/* SVM stack has a fixed size */ +#define SVM_STACK_SIZE 64 +/* SVM stack offsets with this value indicate that it's not on the stack */ +#define SVM_STACK_INVALID 255 + +/* Nodes */ + +/* note that we do not simply use 0, 1, 2, .. as values for these. this works + * around an obscure CUDA bug that happens when compiling for fermi. why it + * happens i have no idea, but consecutive values are problematic, maybe it + * generates an incorrect jump table. */ + +typedef enum NodeType { + NODE_END = 0, + NODE_CLOSURE_BSDF = 100, + NODE_CLOSURE_EMISSION = 200, + NODE_CLOSURE_BACKGROUND = 300, + NODE_CLOSURE_SET_WEIGHT = 400, + NODE_CLOSURE_WEIGHT = 500, + NODE_MIX_CLOSURE = 600, + NODE_JUMP = 700, + NODE_TEX_IMAGE = 1000, + NODE_TEX_SKY = 1100, + NODE_GEOMETRY = 1200, + NODE_LIGHT_PATH = 1300, + NODE_VALUE_F = 1400, + NODE_VALUE_V = 1500, + NODE_MIX = 1600, + NODE_ATTR = 1700, + NODE_CONVERT = 1900, + NODE_FRESNEL = 2000, + NODE_EMISSION_WEIGHT = 2100, + NODE_TEX_GRADIENT = 2200, + NODE_TEX_VORONOI = 2300, + NODE_TEX_MUSGRAVE = 2400, + NODE_TEX_WAVE = 2500, + NODE_TEX_MAGIC = 2600, + NODE_TEX_NOISE = 3000, + NODE_SHADER_JUMP = 3100, + NODE_SET_DISPLACEMENT = 3200, + NODE_GEOMETRY_BUMP_DX = 3300, + NODE_GEOMETRY_BUMP_DY = 3400, + NODE_SET_BUMP = 3500, + NODE_MATH = 3600, + NODE_VECTOR_MATH = 3700, + NODE_MAPPING = 3800, + NODE_TEX_COORD = 3900, + NODE_TEX_COORD_BUMP_DX = 4000, + NODE_TEX_COORD_BUMP_DY = 4100, + NODE_ADD_CLOSURE = 4200, + NODE_EMISSION_SET_WEIGHT_TOTAL = 4300, + NODE_ATTR_BUMP_DX = 4400, + NODE_ATTR_BUMP_DY = 4500, + NODE_TEX_ENVIRONMENT = 4600, + NODE_CLOSURE_HOLDOUT = 4700, + NODE_LAYER_WEIGHT = 4800, + NODE_CLOSURE_VOLUME = 4900 +} NodeType; + +typedef enum NodeAttributeType { + NODE_ATTR_FLOAT = 0, + NODE_ATTR_FLOAT3 +} NodeAttributeType; + +typedef enum NodeGeometry { + NODE_GEOM_P = 0, + NODE_GEOM_N, + NODE_GEOM_T, + NODE_GEOM_I, + NODE_GEOM_Ng, + NODE_GEOM_uv +} NodeGeometry; + +typedef enum NodeLightPath { + NODE_LP_camera = 0, + NODE_LP_shadow, + NODE_LP_diffuse, + NODE_LP_glossy, + NODE_LP_singular, + NODE_LP_reflection, + NODE_LP_transmission, + NODE_LP_backfacing +} NodeLightPath; + +typedef enum NodeTexCoord { + NODE_TEXCO_OBJECT, + NODE_TEXCO_CAMERA, + NODE_TEXCO_WINDOW, + NODE_TEXCO_REFLECTION +} NodeTexCoord; + +typedef enum NodeMix { + NODE_MIX_BLEND = 0, + NODE_MIX_ADD, + NODE_MIX_MUL, + NODE_MIX_SUB, + NODE_MIX_SCREEN, + NODE_MIX_DIV, + NODE_MIX_DIFF, + NODE_MIX_DARK, + NODE_MIX_LIGHT, + NODE_MIX_OVERLAY, + NODE_MIX_DODGE, + NODE_MIX_BURN, + NODE_MIX_HUE, + NODE_MIX_SAT, + NODE_MIX_VAL, + NODE_MIX_COLOR, + NODE_MIX_SOFT, + NODE_MIX_LINEAR +} NodeMix; + +typedef enum NodeMath { + NODE_MATH_ADD, + NODE_MATH_SUBTRACT, + NODE_MATH_MULTIPLY, + NODE_MATH_DIVIDE, + NODE_MATH_SINE, + NODE_MATH_COSINE, + NODE_MATH_TANGENT, + NODE_MATH_ARCSINE, + NODE_MATH_ARCCOSINE, + NODE_MATH_ARCTANGENT, + NODE_MATH_POWER, + NODE_MATH_LOGARITHM, + NODE_MATH_MINIMUM, + NODE_MATH_MAXIMUM, + NODE_MATH_ROUND, + NODE_MATH_LESS_THAN, + NODE_MATH_GREATER_THAN +} NodeMath; + +typedef enum NodeVectorMath { + NODE_VECTOR_MATH_ADD, + NODE_VECTOR_MATH_SUBTRACT, + NODE_VECTOR_MATH_AVERAGE, + NODE_VECTOR_MATH_DOT_PRODUCT, + NODE_VECTOR_MATH_CROSS_PRODUCT, + NODE_VECTOR_MATH_NORMALIZE +} NodeVectorMath; + +typedef enum NodeConvert { + NODE_CONVERT_FV, + NODE_CONVERT_CF, + NODE_CONVERT_VF +} NodeConvert; + +typedef enum NodeDistanceMetric { + NODE_VORONOI_DISTANCE_SQUARED, + NODE_VORONOI_ACTUAL_DISTANCE, + NODE_VORONOI_MANHATTAN, + NODE_VORONOI_CHEBYCHEV, + NODE_VORONOI_MINKOVSKY_H, + NODE_VORONOI_MINKOVSKY_4, + NODE_VORONOI_MINKOVSKY +} NodeDistanceMetric; + +typedef enum NodeNoiseBasis { + NODE_NOISE_PERLIN, + NODE_NOISE_VORONOI_F1, + NODE_NOISE_VORONOI_F2, + NODE_NOISE_VORONOI_F3, + NODE_NOISE_VORONOI_F4, + NODE_NOISE_VORONOI_F2_F1, + NODE_NOISE_VORONOI_CRACKLE, + NODE_NOISE_CELL_NOISE +} NodeNoiseBasis; + +typedef enum NodeWaveType { + NODE_WAVE_SINE, + NODE_WAVE_SAW, + NODE_WAVE_TRI +} NodeWaveType; + +typedef enum NodeMusgraveType { + NODE_MUSGRAVE_MULTIFRACTAL, + NODE_MUSGRAVE_FBM, + NODE_MUSGRAVE_HYBRID_MULTIFRACTAL, + NODE_MUSGRAVE_RIDGED_MULTIFRACTAL, + NODE_MUSGRAVE_HETERO_TERRAIN +} NodeMusgraveType; + +typedef enum NodeWoodType { + NODE_WAVE_BANDS, + NODE_WAVE_RINGS +} NodeWoodType; + +typedef enum NodeBlendType { + NODE_BLEND_LINEAR, + NODE_BLEND_QUADRATIC, + NODE_BLEND_EASING, + NODE_BLEND_DIAGONAL, + NODE_BLEND_RADIAL, + NODE_BLEND_QUADRATIC_SPHERE, + NODE_BLEND_SPHERICAL +} NodeBlendType; + +typedef enum NodeBlendAxis { + NODE_BLEND_HORIZONTAL, + NODE_BLEND_VERTICAL +} NodeBlendAxis; + +typedef enum NodeMarbleType { + NODE_MARBLE_SOFT, + NODE_MARBLE_SHARP, + NODE_MARBLE_SHARPER +} NodeMarbleType; + +typedef enum NodeStucciType { + NODE_STUCCI_PLASTIC, + NODE_STUCCI_WALL_IN, + NODE_STUCCI_WALL_OUT +} NodeStucciType; + +typedef enum NodeVoronoiColoring { + NODE_VORONOI_INTENSITY, + NODE_VORONOI_CELLS +} NodeVoronoiColoring; + +typedef enum NodeBlendWeightType { + NODE_LAYER_WEIGHT_FRESNEL, + NODE_LAYER_WEIGHT_FACING +} NodeBlendWeightType; + +typedef enum ShaderType { + SHADER_TYPE_SURFACE, + SHADER_TYPE_VOLUME, + SHADER_TYPE_DISPLACEMENT +} ShaderType; + +/* Closure */ + +typedef enum ClosureType { + CLOSURE_BSDF_ID, + CLOSURE_BSDF_DIFFUSE_ID, + CLOSURE_BSDF_TRANSLUCENT_ID, + CLOSURE_BSDF_REFLECTION_ID, + CLOSURE_BSDF_REFRACTION_ID, + CLOSURE_BSDF_GLASS_ID, + CLOSURE_BSDF_TRANSPARENT_ID, + CLOSURE_BSDF_MICROFACET_GGX_ID, + CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, + CLOSURE_BSDF_MICROFACET_BECKMANN_ID, + CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, + CLOSURE_BSDF_WARD_ID, + CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, + CLOSURE_BSDF_WESTIN_BACKSCATTER_ID, + CLOSURE_BSDF_WESTIN_SHEEN_ID, + + CLOSURE_BSSRDF_CUBIC_ID, + CLOSURE_EMISSION_ID, + CLOSURE_DEBUG_ID, + CLOSURE_BACKGROUND_ID, + CLOSURE_HOLDOUT_ID, + CLOSURE_SUBSURFACE_ID, + + CLOSURE_VOLUME_ID, + CLOSURE_VOLUME_TRANSPARENT_ID, + CLOSURE_VOLUME_ISOTROPIC_ID, + + NBUILTIN_CLOSURES +} ClosureType; + +/* watch this, being lazy with memory usage */ +#define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_WESTIN_SHEEN_ID) +#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID) +#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID) +#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID) +#define CLOSURE_IS_BACKGROUND(type) (type == CLOSURE_BACKGROUND_ID) + +CCL_NAMESPACE_END + +#endif /* __SVM_TYPES_H__ */ + diff --git a/intern/cycles/kernel/svm/svm_value.h b/intern/cycles/kernel/svm/svm_value.h new file mode 100644 index 00000000000..80cb285f80c --- /dev/null +++ b/intern/cycles/kernel/svm/svm_value.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Value Nodes */ + +__device void svm_node_value_f(KernelGlobals *kg, ShaderData *sd, float *stack, uint ivalue, uint out_offset) +{ + stack_store_float(stack, out_offset, __int_as_float(ivalue)); +} + +__device void svm_node_value_v(KernelGlobals *kg, ShaderData *sd, float *stack, uint out_offset, int *offset) +{ + /* read extra data */ + uint4 node1 = read_node(kg, offset); + float3 p = make_float3(__int_as_float(node1.y), __int_as_float(node1.z), __int_as_float(node1.w)); + + stack_store_float3(stack, out_offset, p); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h new file mode 100644 index 00000000000..f5ee7851a51 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_voronoi.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Voronoi */ + +__device_noinline float4 svm_voronoi(NodeVoronoiColoring coloring, float scale, float3 p) +{ + /* compute distance and point coordinate of 4 nearest neighbours */ + float da[4]; + float3 pa[4]; + + voronoi(p*scale, NODE_VORONOI_DISTANCE_SQUARED, 1.0f, da, pa); + + /* output */ + float fac; + float3 color; + + if(coloring == NODE_VORONOI_INTENSITY) { + fac = fabsf(da[0]); + color = make_float3(fac, fac, fac); + } + else { + color = cellnoise_color(pa[0]); + fac= average(color); + } + + return make_float4(color.x, color.y, color.z, fac); +} + +__device void svm_node_tex_voronoi(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint coloring = node.y; + uint scale_offset, co_offset, fac_offset, color_offset; + + decode_node_uchar4(node.z, &scale_offset, &co_offset, &fac_offset, &color_offset); + + float3 co = stack_load_float3(stack, co_offset); + float scale = stack_load_float_default(stack, scale_offset, node.w); + + float4 result = svm_voronoi((NodeVoronoiColoring)coloring, scale, co); + float3 color = make_float3(result.x, result.y, result.z); + float f = result.w; + + if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f); + if(stack_valid(color_offset)) stack_store_float3(stack, color_offset, color); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h new file mode 100644 index 00000000000..8f2131156c4 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_wave.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Marble */ + +__device_noinline float svm_wave(NodeWoodType type, float3 p, float scale, float detail, float distortion, float dscale) +{ + float w, n; + + p *= scale; + + if(type == NODE_WAVE_BANDS) + n= (p.x + p.x + p.z)*10.0f; + else /* if(type == NODE_WAVE_RINGS) */ + n= len(p)*20.0f; + + if(distortion != 0.0f) + n += distortion * noise_turbulence(p*dscale, NODE_NOISE_PERLIN, detail, 0); + + w = noise_wave(NODE_WAVE_SINE, n); + + return w; +} + +__device void svm_node_tex_wave(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint4 node2 = read_node(kg, offset); + + uint type; + uint co_offset, scale_offset, detail_offset, dscale_offset, distortion_offset, color_offset, fac_offset; + + decode_node_uchar4(node.y, &type, &color_offset, &fac_offset, &dscale_offset); + decode_node_uchar4(node.z, &co_offset, &scale_offset, &detail_offset, &distortion_offset); + + float3 co = stack_load_float3(stack, co_offset); + float scale = stack_load_float_default(stack, scale_offset, node2.x); + float detail = stack_load_float_default(stack, detail_offset, node2.y); + float distortion = stack_load_float_default(stack, distortion_offset, node2.z); + float dscale = stack_load_float_default(stack, dscale_offset, node2.w); + + float f = svm_wave((NodeWoodType)type, co, scale, detail, distortion, dscale); + + if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f); + if(stack_valid(color_offset)) stack_store_float3(stack, color_offset, make_float3(f, f, f)); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/volume.h b/intern/cycles/kernel/svm/volume.h new file mode 100644 index 00000000000..86cb2dcc24e --- /dev/null +++ b/intern/cycles/kernel/svm/volume.h @@ -0,0 +1,74 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +/* note: the interfaces here are just as an example, need to figure + out the right functions and parameters to use */ + +/* ISOTROPIC VOLUME CLOSURE */ + +__device void volume_isotropic_setup(ShaderData *sd, ShaderClosure *sc, float density) +{ + sc->type = CLOSURE_VOLUME_ISOTROPIC_ID; + sd->flag |= SD_VOLUME; + sc->data0 = density; +} + +__device float3 volume_isotropic_eval_phase(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out) +{ + return make_float3(1.0f, 1.0f, 1.0f); +} + +/* TRANSPARENT VOLUME CLOSURE */ + +__device void volume_transparent_setup(ShaderData *sd, ShaderClosure *sc, float density) +{ + sc->type = CLOSURE_VOLUME_TRANSPARENT_ID; + sd->flag |= SD_VOLUME; + sc->data0 = density; +} + +__device float3 volume_transparent_eval_phase(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out) +{ + return make_float3(1.0f, 1.0f, 1.0f); +} + +/* VOLUME CLOSURE */ + +__device float3 volume_eval_phase(const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out) +{ + float3 eval; + + switch(sc->type) { + case CLOSURE_VOLUME_ISOTROPIC_ID: + eval = volume_isotropic_eval_phase(sd, sc, omega_in, omega_out); + break; + case CLOSURE_VOLUME_TRANSPARENT_ID: + eval = volume_transparent_eval_phase(sd, sc, omega_in, omega_out); + break; + default: + eval = make_float3(0.0f, 0.0f, 0.0f); + break; + } + + return eval; +} + +CCL_NAMESPACE_END + |