2
* Adapted from Open Shading Language with this license:
4
* Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
7
* Modifications Copyright 2011, Blender Foundation.
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions are
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.
33
#ifndef __BSDF_WARD_H__
34
#define __BSDF_WARD_H__
40
__device int bsdf_ward_setup(ShaderClosure *sc)
45
float m_ax = clamp(ax, 1e-4f, 1.0f);
46
float m_ay = clamp(ay, 1e-4f, 1.0f);
51
sc->type = CLOSURE_BSDF_WARD_ID;
52
return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
55
__device void bsdf_ward_blur(ShaderClosure *sc, float roughness)
57
sc->data0 = fmaxf(roughness, sc->data0);
58
sc->data1 = fmaxf(roughness, sc->data1);
61
__device float3 bsdf_ward_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
63
float m_ax = sc->data0;
64
float m_ay = sc->data1;
68
float cosNO = dot(N, I);
69
float cosNI = dot(N, omega_in);
71
if(cosNI > 0.0f && cosNO > 0.0f) {
72
cosNO = max(cosNO, 1e-4f);
73
cosNI = max(cosNI, 1e-4f);
75
// get half vector and get x,y basis on the surface for anisotropy
76
float3 H = normalize(omega_in + I); // normalize needed for pdf
78
make_orthonormals_tangent(N, T, &X, &Y);
80
float dotx = dot(H, X) / m_ax;
81
float doty = dot(H, Y) / m_ay;
82
float dotn = dot(H, N);
83
float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
84
float denom = (4 * M_PI_F * m_ax * m_ay * sqrtf(cosNO * cosNI));
85
float exp_val = expf(-exp_arg);
86
float out = cosNI * exp_val / denom;
88
denom = 4 * M_PI_F * m_ax * m_ay * oh * dotn * dotn * dotn;
89
*pdf = exp_val / denom;
90
return make_float3 (out, out, out);
93
return make_float3 (0, 0, 0);
96
__device float3 bsdf_ward_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
98
return make_float3(0.0f, 0.0f, 0.0f);
101
__device int bsdf_ward_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)
103
float m_ax = sc->data0;
104
float m_ay = sc->data1;
108
float cosNO = dot(N, I);
110
// get x,y basis on the surface for anisotropy
112
make_orthonormals_tangent(N, T, &X, &Y);
113
// generate random angles for the half vector
114
// eq. 7 (taking care around discontinuities to keep
115
//ttoutput angle in the right quadrant)
116
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
117
//tttt and sin(atan(x)) == x/sqrt(1+x^2)
118
float alphaRatio = m_ay / m_ax;
119
float cosPhi, sinPhi;
121
float val = 4 * randu;
122
float tanPhi = alphaRatio * tanf(M_PI_2_F * val);
123
cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
124
sinPhi = tanPhi * cosPhi;
126
else if(randu < 0.5f) {
127
float val = 1 - 4 * (0.5f - randu);
128
float tanPhi = alphaRatio * tanf(M_PI_2_F * val);
129
// phi = M_PI_F - phi;
130
cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
131
sinPhi = -tanPhi * cosPhi;
133
else if(randu < 0.75f) {
134
float val = 4 * (randu - 0.5f);
135
float tanPhi = alphaRatio * tanf(M_PI_2_F * val);
136
//phi = M_PI_F + phi;
137
cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
138
sinPhi = tanPhi * cosPhi;
141
float val = 1 - 4 * (1 - randu);
142
float tanPhi = alphaRatio * tanf(M_PI_2_F * val);
143
// phi = 2 * M_PI_F - phi;
144
cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
145
sinPhi = -tanPhi * cosPhi;
148
// we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
149
//tttt and sin(atan(x)) == x/sqrt(1+x^2)
150
float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay);
151
float tanTheta2 = -logf(1 - randv) / thetaDenom;
152
float cosTheta = 1 / sqrtf(1 + tanTheta2);
153
float sinTheta = cosTheta * sqrtf(tanTheta2);
155
float3 h; // already normalized becaused expressed from spherical coordinates
156
h.x = sinTheta * cosPhi;
157
h.y = sinTheta * sinPhi;
159
// compute terms that are easier in local space
160
float dotx = h.x / m_ax;
161
float doty = h.y / m_ay;
163
// transform to world space
164
h = h.x * X + h.y * Y + h.z * N;
165
// generate the final sample
166
float oh = dot(h, I);
167
*omega_in = 2.0f * oh * h - I;
168
if(dot(Ng, *omega_in) > 0) {
169
float cosNI = dot(N, *omega_in);
171
cosNO = max(cosNO, 1e-4f);
172
cosNI = max(cosNI, 1e-4f);
175
float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
176
float denom = 4 * M_PI_F * m_ax * m_ay * oh * dotn * dotn * dotn;
177
*pdf = expf(-exp_arg) / denom;
178
// compiler will reuse expressions already computed
179
denom = (4 * M_PI_F * m_ax * m_ay * sqrtf(cosNO * cosNI));
180
float power = cosNI * expf(-exp_arg) / denom;
181
*eval = make_float3(power, power, power);
182
#ifdef __RAY_DIFFERENTIALS__
183
*domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx;
184
*domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy;
189
return LABEL_REFLECT|LABEL_GLOSSY;
194
#endif /* __BSDF_WARD_H__ */