/* * Parts 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. */ #pragma once CCL_NAMESPACE_BEGIN /* distribute uniform xy on [0,1] over unit disk [-1,1] */ ccl_device void to_unit_disk(ccl_private float *x, ccl_private float *y) { float phi = M_2PI_F * (*x); float r = sqrtf(*y); *x = r * cosf(phi); *y = r * sinf(phi); } /* return an orthogonal tangent and bitangent given a normal and tangent that * may not be exactly orthogonal */ ccl_device void make_orthonormals_tangent(const float3 N, const float3 T, ccl_private float3 *a, ccl_private float3 *b) { *b = normalize(cross(N, T)); *a = cross(*b, N); } /* sample direction with cosine weighted distributed in hemisphere */ ccl_device_inline void sample_cos_hemisphere( const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf) { to_unit_disk(&randu, &randv); float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f)); float3 T, B; make_orthonormals(N, &T, &B); *omega_in = randu * T + randv * B + costheta * N; *pdf = costheta * M_1_PI_F; } /* sample direction uniformly distributed in hemisphere */ ccl_device_inline void sample_uniform_hemisphere( const float3 N, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf) { float z = randu; float r = sqrtf(max(0.0f, 1.0f - z * z)); float phi = M_2PI_F * randv; float x = r * cosf(phi); float y = r * sinf(phi); float3 T, B; make_orthonormals(N, &T, &B); *omega_in = x * T + y * B + z * N; *pdf = 0.5f * M_1_PI_F; } /* sample direction uniformly distributed in cone */ ccl_device_inline void sample_uniform_cone(const float3 N, float angle, float randu, float randv, ccl_private float3 *omega_in, ccl_private float *pdf) { float zMin = cosf(angle); float z = zMin - zMin * randu + randu; float r = safe_sqrtf(1.0f - sqr(z)); float phi = M_2PI_F * randv; float x = r * cosf(phi); float y = r * sinf(phi); float3 T, B; make_orthonormals(N, &T, &B); *omega_in = x * T + y * B + z * N; *pdf = M_1_2PI_F / (1.0f - zMin); } ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle) { float zMin = cosf(angle); float z = dot(N, D); if (z > zMin) { return M_1_2PI_F / (1.0f - zMin); } return 0.0f; } /* sample uniform point on the surface of a sphere */ ccl_device float3 sample_uniform_sphere(float u1, float u2) { float z = 1.0f - 2.0f * u1; float r = sqrtf(fmaxf(0.0f, 1.0f - z * z)); float phi = M_2PI_F * u2; float x = r * cosf(phi); float y = r * sinf(phi); return make_float3(x, y, z); } /* distribute uniform xy on [0,1] over unit disk [-1,1], with concentric mapping * to better preserve stratification for some RNG sequences */ ccl_device float2 concentric_sample_disk(float u1, float u2) { float phi, r; float a = 2.0f * u1 - 1.0f; float b = 2.0f * u2 - 1.0f; if (a == 0.0f && b == 0.0f) { return zero_float2(); } else if (a * a > b * b) { r = a; phi = M_PI_4_F * (b / a); } else { r = b; phi = M_PI_2_F - M_PI_4_F * (a / b); } return make_float2(r * cosf(phi), r * sinf(phi)); } /* sample point in unit polygon with given number of corners and rotation */ ccl_device float2 regular_polygon_sample(float corners, float rotation, float u, float v) { /* sample corner number and reuse u */ float corner = floorf(u * corners); u = u * corners - corner; /* uniform sampled triangle weights */ u = sqrtf(u); v = v * u; u = 1.0f - u; /* point in triangle */ float angle = M_PI_F / corners; float2 p = make_float2((u + v) * cosf(angle), (u - v) * sinf(angle)); /* rotate */ rotation += corner * 2.0f * angle; float cr = cosf(rotation); float sr = sinf(rotation); return make_float2(cr * p.x - sr * p.y, sr * p.x + cr * p.y); } CCL_NAMESPACE_END