Cycles: better path termination for transparency.
[blender.git] / intern / cycles / kernel / closure / bsdf_util.h
1 /*
2  * Adapted from Open Shading Language with this license:
3  *
4  * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
5  * All Rights Reserved.
6  *
7  * Modifications Copyright 2011, Blender Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are
11  * met:
12  * * Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in the
16  *   documentation and/or other materials provided with the distribution.
17  * * Neither the name of Sony Pictures Imageworks nor the names of its
18  *   contributors may be used to endorse or promote products derived from
19  *   this software without specific prior written permission.
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #ifndef __BSDF_UTIL_H__
34 #define __BSDF_UTIL_H__
35
36 CCL_NAMESPACE_BEGIN
37
38 ccl_device float fresnel_dielectric(
39         float eta, const float3 N,
40         const float3 I, float3 *R, float3 *T,
41 #ifdef __RAY_DIFFERENTIALS__
42         const float3 dIdx, const float3 dIdy,
43         float3 *dRdx, float3 *dRdy,
44         float3 *dTdx, float3 *dTdy,
45 #endif
46         bool *is_inside)
47 {
48         float cos = dot(N, I), neta;
49         float3 Nn;
50
51         // check which side of the surface we are on
52         if(cos > 0) {
53                 // we are on the outside of the surface, going in
54                 neta = 1 / eta;
55                 Nn   = N;
56                 *is_inside = false;
57         }
58         else {
59                 // we are inside the surface
60                 cos  = -cos;
61                 neta = eta;
62                 Nn   = -N;
63                 *is_inside = true;
64         }
65         
66         // compute reflection
67         *R = (2 * cos)* Nn - I;
68 #ifdef __RAY_DIFFERENTIALS__
69         *dRdx = (2 * dot(Nn, dIdx)) * Nn - dIdx;
70         *dRdy = (2 * dot(Nn, dIdy)) * Nn - dIdy;
71 #endif
72         
73         float arg = 1 -(neta * neta *(1 -(cos * cos)));
74         if(arg < 0) {
75                 *T = make_float3(0.0f, 0.0f, 0.0f);
76 #ifdef __RAY_DIFFERENTIALS__
77                 *dTdx = make_float3(0.0f, 0.0f, 0.0f);
78                 *dTdy = make_float3(0.0f, 0.0f, 0.0f);
79 #endif
80                 return 1; // total internal reflection
81         }
82         else {
83                 float dnp = max(sqrtf(arg), 1e-7f);
84                 float nK = (neta * cos)- dnp;
85                 *T = -(neta * I)+(nK * Nn);
86 #ifdef __RAY_DIFFERENTIALS__
87                 *dTdx = -(neta * dIdx) + ((neta - neta * neta * cos / dnp) * dot(dIdx, Nn)) * Nn;
88                 *dTdy = -(neta * dIdy) + ((neta - neta * neta * cos / dnp) * dot(dIdy, Nn)) * Nn;
89 #endif
90                 // compute Fresnel terms
91                 float cosTheta1 = cos; // N.R
92                 float cosTheta2 = -dot(Nn, *T);
93                 float pPara = (cosTheta1 - eta * cosTheta2)/(cosTheta1 + eta * cosTheta2);
94                 float pPerp = (eta * cosTheta1 - cosTheta2)/(eta * cosTheta1 + cosTheta2);
95                 return 0.5f * (pPara * pPara + pPerp * pPerp);
96         }
97 }
98
99 ccl_device float fresnel_dielectric_cos(float cosi, float eta)
100 {
101         // compute fresnel reflectance without explicitly computing
102         // the refracted direction
103         float c = fabsf(cosi);
104         float g = eta * eta - 1 + c * c;
105         if(g > 0) {
106                 g = sqrtf(g);
107                 float A = (g - c)/(g + c);
108                 float B = (c *(g + c)- 1)/(c *(g - c)+ 1);
109                 return 0.5f * A * A *(1 + B * B);
110         }
111         return 1.0f; // TIR(no refracted component)
112 }
113
114 ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k)
115 {
116         float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi);
117         float3 one = make_float3(1.0f, 1.0f, 1.0f);
118         float3 tmp_f = eta * eta + k * k;
119         float3 tmp = tmp_f * cosi2;
120         float3 Rparl2 = (tmp - (2.0f * eta * cosi) + one) /
121                                         (tmp + (2.0f * eta * cosi) + one);
122         float3 Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) /
123                                         (tmp_f + (2.0f * eta * cosi) + cosi2);
124         return(Rparl2 + Rperp2) * 0.5f;
125 }
126
127 ccl_device float schlick_fresnel(float u)
128 {
129         float m = clamp(1.0f - u, 0.0f, 1.0f);
130         float m2 = m * m;
131         return m2 * m2 * m; // pow(m, 5)
132 }
133
134 ccl_device float smooth_step(float edge0, float edge1, float x)
135 {
136         float result;
137         if(x < edge0) result = 0.0f;
138         else if(x >= edge1) result = 1.0f;
139         else {
140                 float t = (x - edge0)/(edge1 - edge0);
141                 result = (3.0f-2.0f*t)*(t*t);
142         }
143         return result;
144 }
145
146 /* Calculate the fresnel color which is a blend between white and the F0 color (cspec0) */
147 ccl_device_forceinline float3 interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, float3 cspec0) {
148         /* Calculate the fresnel interpolation factor
149          * The value from fresnel_dielectric_cos(...) has to be normalized because
150          * the cspec0 keeps the F0 color
151         */
152         float F0_norm = 1.0f / (1.0f - F0);
153         float FH = (fresnel_dielectric_cos(dot(L, H), ior) - F0) * F0_norm;
154
155         /* Blend between white and a specular color with respect to the fresnel */
156         return cspec0 * (1.0f - FH) + make_float3(1.0f, 1.0f, 1.0f) * FH;
157 }
158
159 CCL_NAMESPACE_END
160
161 #endif /* __BSDF_UTIL_H__ */
162