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 2012, 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_PHONG_RAMP_H__
34 #define __BSDF_PHONG_RAMP_H__
35 
36 CCL_NAMESPACE_BEGIN
37 
38 #ifdef __OSL__
39 
40 typedef ccl_addr_space struct PhongRampBsdf {
41   SHADER_CLOSURE_BASE;
42 
43   float exponent;
44   float3 *colors;
45 } PhongRampBsdf;
46 
47 static_assert(sizeof(ShaderClosure) >= sizeof(PhongRampBsdf), "PhongRampBsdf is too large!");
48 
bsdf_phong_ramp_get_color(const float3 colors[8],float pos)49 ccl_device float3 bsdf_phong_ramp_get_color(const float3 colors[8], float pos)
50 {
51   int MAXCOLORS = 8;
52 
53   float npos = pos * (float)(MAXCOLORS - 1);
54   int ipos = float_to_int(npos);
55   if (ipos < 0)
56     return colors[0];
57   if (ipos >= (MAXCOLORS - 1))
58     return colors[MAXCOLORS - 1];
59   float offset = npos - (float)ipos;
60   return colors[ipos] * (1.0f - offset) + colors[ipos + 1] * offset;
61 }
62 
bsdf_phong_ramp_setup(PhongRampBsdf * bsdf)63 ccl_device int bsdf_phong_ramp_setup(PhongRampBsdf *bsdf)
64 {
65   bsdf->type = CLOSURE_BSDF_PHONG_RAMP_ID;
66   bsdf->exponent = max(bsdf->exponent, 0.0f);
67   return SD_BSDF | SD_BSDF_HAS_EVAL;
68 }
69 
bsdf_phong_ramp_eval_reflect(const ShaderClosure * sc,const float3 I,const float3 omega_in,float * pdf)70 ccl_device float3 bsdf_phong_ramp_eval_reflect(const ShaderClosure *sc,
71                                                const float3 I,
72                                                const float3 omega_in,
73                                                float *pdf)
74 {
75   const PhongRampBsdf *bsdf = (const PhongRampBsdf *)sc;
76   float m_exponent = bsdf->exponent;
77   float cosNI = dot(bsdf->N, omega_in);
78   float cosNO = dot(bsdf->N, I);
79 
80   if (cosNI > 0 && cosNO > 0) {
81     // reflect the view vector
82     float3 R = (2 * cosNO) * bsdf->N - I;
83     float cosRI = dot(R, omega_in);
84     if (cosRI > 0) {
85       float cosp = powf(cosRI, m_exponent);
86       float common = 0.5f * M_1_PI_F * cosp;
87       float out = cosNI * (m_exponent + 2) * common;
88       *pdf = (m_exponent + 1) * common;
89       return bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out;
90     }
91   }
92 
93   return make_float3(0.0f, 0.0f, 0.0f);
94 }
95 
bsdf_phong_ramp_eval_transmit(const ShaderClosure * sc,const float3 I,const float3 omega_in,float * pdf)96 ccl_device float3 bsdf_phong_ramp_eval_transmit(const ShaderClosure *sc,
97                                                 const float3 I,
98                                                 const float3 omega_in,
99                                                 float *pdf)
100 {
101   return make_float3(0.0f, 0.0f, 0.0f);
102 }
103 
bsdf_phong_ramp_sample(const ShaderClosure * sc,float3 Ng,float3 I,float3 dIdx,float3 dIdy,float randu,float randv,float3 * eval,float3 * omega_in,float3 * domega_in_dx,float3 * domega_in_dy,float * pdf)104 ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc,
105                                       float3 Ng,
106                                       float3 I,
107                                       float3 dIdx,
108                                       float3 dIdy,
109                                       float randu,
110                                       float randv,
111                                       float3 *eval,
112                                       float3 *omega_in,
113                                       float3 *domega_in_dx,
114                                       float3 *domega_in_dy,
115                                       float *pdf)
116 {
117   const PhongRampBsdf *bsdf = (const PhongRampBsdf *)sc;
118   float cosNO = dot(bsdf->N, I);
119   float m_exponent = bsdf->exponent;
120 
121   if (cosNO > 0) {
122     // reflect the view vector
123     float3 R = (2 * cosNO) * bsdf->N - I;
124 
125 #  ifdef __RAY_DIFFERENTIALS__
126     *domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
127     *domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
128 #  endif
129 
130     float3 T, B;
131     make_orthonormals(R, &T, &B);
132     float phi = M_2PI_F * randu;
133     float cosTheta = powf(randv, 1 / (m_exponent + 1));
134     float sinTheta2 = 1 - cosTheta * cosTheta;
135     float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0;
136     *omega_in = (cosf(phi) * sinTheta) * T + (sinf(phi) * sinTheta) * B + (cosTheta)*R;
137     if (dot(Ng, *omega_in) > 0.0f) {
138       // common terms for pdf and eval
139       float cosNI = dot(bsdf->N, *omega_in);
140       // make sure the direction we chose is still in the right hemisphere
141       if (cosNI > 0) {
142         float cosp = powf(cosTheta, m_exponent);
143         float common = 0.5f * M_1_PI_F * cosp;
144         *pdf = (m_exponent + 1) * common;
145         float out = cosNI * (m_exponent + 2) * common;
146         *eval = bsdf_phong_ramp_get_color(bsdf->colors, cosp) * out;
147       }
148     }
149   }
150   return LABEL_REFLECT | LABEL_GLOSSY;
151 }
152 
153 #endif /* __OSL__ */
154 
155 CCL_NAMESPACE_END
156 
157 #endif /* __BSDF_PHONG_RAMP_H__ */
158