2011-04-27 11:58:34 +00:00
|
|
|
/*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Copyright 2011-2013 Blender Foundation
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
2014-12-25 01:50:24 +00:00
|
|
|
* limitations under the License.
|
2011-04-27 11:58:34 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __UTIL_MATH_H__
|
|
|
|
#define __UTIL_MATH_H__
|
|
|
|
|
|
|
|
/* Math
|
|
|
|
*
|
|
|
|
* Basic math functions on scalar and vector types. This header is used by
|
|
|
|
* both the kernel code when compiled as C++, and other C++ non-kernel code. */
|
|
|
|
|
2017-01-20 10:55:48 +00:00
|
|
|
#ifndef __KERNEL_GPU__
|
|
|
|
# include <cmath>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
#ifndef __KERNEL_OPENCL__
|
2017-04-14 12:05:23 +00:00
|
|
|
# include <float.h>
|
|
|
|
# include <math.h>
|
|
|
|
# include <stdio.h>
|
|
|
|
#endif /* __KERNEL_OPENCL__ */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 18:39:14 +00:00
|
|
|
#include "util/util_types.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
2012-04-11 09:07:28 +00:00
|
|
|
/* Float Pi variations */
|
|
|
|
|
2013-05-12 14:13:29 +00:00
|
|
|
/* Division */
|
2011-09-02 00:10:03 +00:00
|
|
|
#ifndef M_PI_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_PI_F (3.1415926535897932f) /* pi */
|
2011-09-02 00:10:03 +00:00
|
|
|
#endif
|
|
|
|
#ifndef M_PI_2_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_PI_2_F (1.5707963267948966f) /* pi/2 */
|
2011-09-02 00:10:03 +00:00
|
|
|
#endif
|
|
|
|
#ifndef M_PI_4_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_PI_4_F (0.7853981633974830f) /* pi/4 */
|
2011-09-02 00:10:03 +00:00
|
|
|
#endif
|
|
|
|
#ifndef M_1_PI_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_1_PI_F (0.3183098861837067f) /* 1/pi */
|
2011-09-02 00:10:03 +00:00
|
|
|
#endif
|
|
|
|
#ifndef M_2_PI_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_2_PI_F (0.6366197723675813f) /* 2/pi */
|
2011-08-09 18:53:54 +00:00
|
|
|
#endif
|
2013-05-12 14:13:29 +00:00
|
|
|
|
|
|
|
/* Multiplication */
|
|
|
|
#ifndef M_2PI_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_2PI_F (6.2831853071795864f) /* 2*pi */
|
2013-05-12 14:13:29 +00:00
|
|
|
#endif
|
|
|
|
#ifndef M_4PI_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_4PI_F (12.566370614359172f) /* 4*pi */
|
2013-05-12 14:13:29 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Float sqrt variations */
|
2012-04-30 12:49:26 +00:00
|
|
|
#ifndef M_SQRT2_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_SQRT2_F (1.4142135623730950f) /* sqrt(2) */
|
2012-04-30 12:49:26 +00:00
|
|
|
#endif
|
2015-02-06 10:40:07 +00:00
|
|
|
#ifndef M_LN2_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_LN2_F (0.6931471805599453f) /* ln(2) */
|
2015-02-06 10:40:07 +00:00
|
|
|
#endif
|
|
|
|
#ifndef M_LN10_F
|
2017-04-14 12:05:23 +00:00
|
|
|
# define M_LN10_F (2.3025850929940457f) /* ln(10) */
|
2015-02-06 10:40:07 +00:00
|
|
|
#endif
|
2011-08-09 18:53:54 +00:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Scalar */
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2017-04-14 12:05:23 +00:00
|
|
|
# ifndef __KERNEL_OPENCL__
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float fmaxf(float a, float b)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return (a > b)? a: b;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float fminf(float a, float b)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return (a < b)? a: b;
|
|
|
|
}
|
2017-04-14 12:05:23 +00:00
|
|
|
# endif /* !__KERNEL_OPENCL__ */
|
|
|
|
#endif /* _WIN32 */
|
2012-04-11 09:07:28 +00:00
|
|
|
|
2011-04-27 17:23:37 +00:00
|
|
|
#ifndef __KERNEL_GPU__
|
2017-01-20 10:55:48 +00:00
|
|
|
using std::isfinite;
|
|
|
|
using std::isnan;
|
|
|
|
|
2016-04-15 13:29:12 +00:00
|
|
|
ccl_device_inline int abs(int x)
|
|
|
|
{
|
|
|
|
return (x > 0)? x: -x;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline int max(int a, int b)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return (a > b)? a: b;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline int min(int a, int b)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return (a < b)? a: b;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float max(float a, float b)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return (a > b)? a: b;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float min(float a, float b)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return (a < b)? a: b;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline double max(double a, double b)
|
2011-09-05 12:24:28 +00:00
|
|
|
{
|
|
|
|
return (a > b)? a: b;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline double min(double a, double b)
|
2011-09-05 12:24:28 +00:00
|
|
|
{
|
|
|
|
return (a < b)? a: b;
|
|
|
|
}
|
|
|
|
|
2014-12-16 15:27:44 +00:00
|
|
|
/* These 2 guys are templated for usage with registers data.
|
|
|
|
*
|
|
|
|
* NOTE: Since this is CPU-only functions it is ok to use references here.
|
|
|
|
* But for other devices we'll need to be careful about this.
|
|
|
|
*/
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
ccl_device_inline T min4(const T& a, const T& b, const T& c, const T& d)
|
|
|
|
{
|
|
|
|
return min(min(a,b),min(c,d));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
ccl_device_inline T max4(const T& a, const T& b, const T& c, const T& d)
|
|
|
|
{
|
|
|
|
return max(max(a,b),max(c,d));
|
|
|
|
}
|
2017-04-14 12:05:23 +00:00
|
|
|
#endif /* __KERNEL_GPU__ */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float min4(float a, float b, float c, float d)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2011-11-21 16:28:19 +00:00
|
|
|
return min(min(a, b), min(c, d));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float max4(float a, float b, float c, float d)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2011-11-21 16:28:19 +00:00
|
|
|
return max(max(a, b), max(c, d));
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
#ifndef __KERNEL_OPENCL__
|
|
|
|
/* Int/Float conversion */
|
|
|
|
|
|
|
|
ccl_device_inline int as_int(uint i)
|
|
|
|
{
|
|
|
|
union { uint ui; int i; } u;
|
|
|
|
u.ui = i;
|
|
|
|
return u.i;
|
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device_inline uint as_uint(int i)
|
|
|
|
{
|
|
|
|
union { uint ui; int i; } u;
|
|
|
|
u.i = i;
|
|
|
|
return u.ui;
|
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device_inline uint as_uint(float f)
|
|
|
|
{
|
|
|
|
union { uint i; float f; } u;
|
|
|
|
u.f = f;
|
|
|
|
return u.i;
|
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device_inline int __float_as_int(float f)
|
|
|
|
{
|
|
|
|
union { int i; float f; } u;
|
|
|
|
u.f = f;
|
|
|
|
return u.i;
|
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device_inline float __int_as_float(int i)
|
|
|
|
{
|
|
|
|
union { int i; float f; } u;
|
|
|
|
u.i = i;
|
|
|
|
return u.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device_inline uint __float_as_uint(float f)
|
|
|
|
{
|
|
|
|
union { uint i; float f; } u;
|
|
|
|
u.f = f;
|
|
|
|
return u.i;
|
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device_inline float __uint_as_float(uint i)
|
|
|
|
{
|
|
|
|
union { uint i; float f; } u;
|
|
|
|
u.i = i;
|
|
|
|
return u.f;
|
|
|
|
}
|
|
|
|
#endif /* __KERNEL_OPENCL__ */
|
|
|
|
|
|
|
|
/* Versions of functions which are safe for fast math. */
|
|
|
|
ccl_device_inline bool isnan_safe(float f)
|
|
|
|
{
|
|
|
|
unsigned int x = __float_as_uint(f);
|
|
|
|
return (x << 1) > 0xff000000u;
|
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device_inline bool isfinite_safe(float f)
|
|
|
|
{
|
|
|
|
/* By IEEE 754 rule, 2*Inf equals Inf */
|
|
|
|
unsigned int x = __float_as_uint(f);
|
|
|
|
return (f == f) && (x == 0 || (f != 2.0f*f)) && !((x << 1) > 0xff000000u);
|
|
|
|
}
|
|
|
|
|
|
|
|
ccl_device_inline float ensure_finite(float v)
|
|
|
|
{
|
|
|
|
return isfinite_safe(v)? v : 0.0f;
|
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
#ifndef __KERNEL_OPENCL__
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline int clamp(int a, int mn, int mx)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return min(max(a, mn), mx);
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float clamp(float a, float mn, float mx)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return min(max(a, mn), mx);
|
|
|
|
}
|
|
|
|
|
2016-07-16 23:42:28 +00:00
|
|
|
ccl_device_inline float mix(float a, float b, float t)
|
|
|
|
{
|
|
|
|
return a + t*(b - a);
|
|
|
|
}
|
2017-04-14 12:05:23 +00:00
|
|
|
#endif /* __KERNEL_OPENCL__ */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2015-04-27 19:13:03 +00:00
|
|
|
#ifndef __KERNEL_CUDA__
|
|
|
|
ccl_device_inline float saturate(float a)
|
|
|
|
{
|
|
|
|
return clamp(a, 0.0f, 1.0f);
|
|
|
|
}
|
2017-04-14 12:05:23 +00:00
|
|
|
#endif /* __KERNEL_CUDA__ */
|
2015-04-27 19:13:03 +00:00
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline int float_to_int(float f)
|
2013-06-07 16:06:17 +00:00
|
|
|
{
|
|
|
|
return (int)f;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline int floor_to_int(float f)
|
2013-06-07 16:06:17 +00:00
|
|
|
{
|
|
|
|
return float_to_int(floorf(f));
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline int ceil_to_int(float f)
|
2013-06-07 16:06:17 +00:00
|
|
|
{
|
|
|
|
return float_to_int(ceilf(f));
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float signf(float f)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
return (f < 0.0f)? -1.0f: 1.0f;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float nonzerof(float f, float eps)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2014-05-07 18:53:05 +00:00
|
|
|
if(fabsf(f) < eps)
|
2011-04-27 11:58:34 +00:00
|
|
|
return signf(f)*eps;
|
|
|
|
else
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float smoothstepf(float f)
|
2012-06-04 17:17:10 +00:00
|
|
|
{
|
|
|
|
float ff = f*f;
|
|
|
|
return (3.0f*ff - 2.0f*ff*f);
|
|
|
|
}
|
|
|
|
|
2016-07-16 23:42:28 +00:00
|
|
|
ccl_device_inline int mod(int x, int m)
|
|
|
|
{
|
|
|
|
return (x % m + m) % m;
|
|
|
|
}
|
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
ccl_device_inline float3 float2_to_float3(const float2 a)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2017-04-14 12:05:23 +00:00
|
|
|
return make_float3(a.x, a.y, 0.0f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
ccl_device_inline float3 float4_to_float3(const float4 a)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2017-04-14 12:05:23 +00:00
|
|
|
return make_float3(a.x, a.y, a.z);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
ccl_device_inline float4 float3_to_float4(const float3 a)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2017-04-14 12:05:23 +00:00
|
|
|
return make_float4(a.x, a.y, a.z, 1.0f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
CCL_NAMESPACE_END
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
#include "util/util_math_int2.h"
|
|
|
|
#include "util/util_math_int3.h"
|
|
|
|
#include "util/util_math_int4.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
#include "util/util_math_float2.h"
|
|
|
|
#include "util/util_math_float3.h"
|
|
|
|
#include "util/util_math_float4.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
CCL_NAMESPACE_BEGIN
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
#ifndef __KERNEL_OPENCL__
|
2017-04-14 12:05:23 +00:00
|
|
|
/* Interpolation */
|
2014-11-08 12:35:21 +00:00
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
template<class A, class B> A lerp(const A& a, const A& b, const B& t)
|
2016-08-09 10:20:08 +00:00
|
|
|
{
|
2017-04-14 12:05:23 +00:00
|
|
|
return (A)(a * ((B)1 - t) + b * t);
|
2016-08-09 10:20:08 +00:00
|
|
|
}
|
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
/* Triangle */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2017-04-14 12:05:23 +00:00
|
|
|
ccl_device_inline float triangle_area(const float3& v1,
|
|
|
|
const float3& v2,
|
|
|
|
const float3& v3)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2017-04-14 12:05:23 +00:00
|
|
|
return len(cross(v3 - v2, v1 - v2))*0.5f;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2017-04-14 12:05:23 +00:00
|
|
|
#endif /* __KERNEL_OPENCL__ */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2011-09-27 20:37:24 +00:00
|
|
|
/* Orthonormal vectors */
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline void make_orthonormals(const float3 N, float3 *a, float3 *b)
|
2011-09-27 20:37:24 +00:00
|
|
|
{
|
2013-08-18 14:15:57 +00:00
|
|
|
#if 0
|
|
|
|
if(fabsf(N.y) >= 0.999f) {
|
|
|
|
*a = make_float3(1, 0, 0);
|
|
|
|
*b = make_float3(0, 0, 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(fabsf(N.z) >= 0.999f) {
|
|
|
|
*a = make_float3(1, 0, 0);
|
|
|
|
*b = make_float3(0, 1, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-09-27 20:37:24 +00:00
|
|
|
if(N.x != N.y || N.x != N.z)
|
|
|
|
*a = make_float3(N.z-N.y, N.x-N.z, N.y-N.x); //(1,1,1)x N
|
|
|
|
else
|
|
|
|
*a = make_float3(N.z-N.y, N.x+N.z, -N.y-N.x); //(-1,1,1)x N
|
|
|
|
|
|
|
|
*a = normalize(*a);
|
|
|
|
*b = cross(N, *a);
|
|
|
|
}
|
|
|
|
|
2012-03-28 12:18:12 +00:00
|
|
|
/* Color division */
|
|
|
|
|
2014-03-29 12:03:50 +00:00
|
|
|
ccl_device_inline float3 safe_invert_color(float3 a)
|
|
|
|
{
|
|
|
|
float x, y, z;
|
|
|
|
|
|
|
|
x = (a.x != 0.0f)? 1.0f/a.x: 0.0f;
|
|
|
|
y = (a.y != 0.0f)? 1.0f/a.y: 0.0f;
|
|
|
|
z = (a.z != 0.0f)? 1.0f/a.z: 0.0f;
|
|
|
|
|
|
|
|
return make_float3(x, y, z);
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float3 safe_divide_color(float3 a, float3 b)
|
2012-03-28 12:18:12 +00:00
|
|
|
{
|
|
|
|
float x, y, z;
|
|
|
|
|
|
|
|
x = (b.x != 0.0f)? a.x/b.x: 0.0f;
|
|
|
|
y = (b.y != 0.0f)? a.y/b.y: 0.0f;
|
|
|
|
z = (b.z != 0.0f)? a.z/b.z: 0.0f;
|
|
|
|
|
|
|
|
return make_float3(x, y, z);
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float3 safe_divide_even_color(float3 a, float3 b)
|
2013-07-08 23:31:45 +00:00
|
|
|
{
|
|
|
|
float x, y, z;
|
|
|
|
|
|
|
|
x = (b.x != 0.0f)? a.x/b.x: 0.0f;
|
|
|
|
y = (b.y != 0.0f)? a.y/b.y: 0.0f;
|
|
|
|
z = (b.z != 0.0f)? a.z/b.z: 0.0f;
|
|
|
|
|
2017-02-28 00:33:57 +00:00
|
|
|
/* try to get gray even if b is zero */
|
2013-07-08 23:31:45 +00:00
|
|
|
if(b.x == 0.0f) {
|
|
|
|
if(b.y == 0.0f) {
|
|
|
|
x = z;
|
|
|
|
y = z;
|
|
|
|
}
|
|
|
|
else if(b.z == 0.0f) {
|
|
|
|
x = y;
|
|
|
|
z = y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
x = 0.5f*(y + z);
|
|
|
|
}
|
|
|
|
else if(b.y == 0.0f) {
|
|
|
|
if(b.z == 0.0f) {
|
|
|
|
y = x;
|
|
|
|
z = x;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
y = 0.5f*(x + z);
|
|
|
|
}
|
|
|
|
else if(b.z == 0.0f) {
|
|
|
|
z = 0.5f*(x + y);
|
|
|
|
}
|
|
|
|
|
|
|
|
return make_float3(x, y, z);
|
|
|
|
}
|
|
|
|
|
2012-11-04 22:31:32 +00:00
|
|
|
/* Rotation of point around axis and angle */
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float3 rotate_around_axis(float3 p, float3 axis, float angle)
|
2012-11-04 22:31:32 +00:00
|
|
|
{
|
|
|
|
float costheta = cosf(angle);
|
|
|
|
float sintheta = sinf(angle);
|
|
|
|
float3 r;
|
|
|
|
|
|
|
|
r.x = ((costheta + (1 - costheta) * axis.x * axis.x) * p.x) +
|
2017-04-14 12:05:23 +00:00
|
|
|
(((1 - costheta) * axis.x * axis.y - axis.z * sintheta) * p.y) +
|
|
|
|
(((1 - costheta) * axis.x * axis.z + axis.y * sintheta) * p.z);
|
2012-11-04 22:31:32 +00:00
|
|
|
|
|
|
|
r.y = (((1 - costheta) * axis.x * axis.y + axis.z * sintheta) * p.x) +
|
2017-04-14 12:05:23 +00:00
|
|
|
((costheta + (1 - costheta) * axis.y * axis.y) * p.y) +
|
|
|
|
(((1 - costheta) * axis.y * axis.z - axis.x * sintheta) * p.z);
|
2012-11-04 22:31:32 +00:00
|
|
|
|
|
|
|
r.z = (((1 - costheta) * axis.x * axis.z - axis.y * sintheta) * p.x) +
|
2017-04-14 12:05:23 +00:00
|
|
|
(((1 - costheta) * axis.y * axis.z + axis.x * sintheta) * p.y) +
|
|
|
|
((costheta + (1 - costheta) * axis.z * axis.z) * p.z);
|
2012-11-04 22:31:32 +00:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-12-19 21:17:16 +00:00
|
|
|
/* NaN-safe math ops */
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device_inline float safe_sqrtf(float f)
|
2013-08-18 14:15:57 +00:00
|
|
|
{
|
|
|
|
return sqrtf(max(f, 0.0f));
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device float safe_asinf(float a)
|
2012-12-19 21:17:16 +00:00
|
|
|
{
|
2014-01-14 18:55:02 +00:00
|
|
|
return asinf(clamp(a, -1.0f, 1.0f));
|
2012-12-19 21:17:16 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device float safe_acosf(float a)
|
2012-12-19 21:17:16 +00:00
|
|
|
{
|
2014-01-14 18:55:02 +00:00
|
|
|
return acosf(clamp(a, -1.0f, 1.0f));
|
2012-12-19 21:17:16 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device float compatible_powf(float x, float y)
|
2012-12-19 21:17:16 +00:00
|
|
|
{
|
2014-01-14 18:55:02 +00:00
|
|
|
#ifdef __KERNEL_GPU__
|
|
|
|
if(y == 0.0f) /* x^0 -> 1, including 0^0 */
|
|
|
|
return 1.0f;
|
|
|
|
|
2012-12-19 21:17:16 +00:00
|
|
|
/* GPU pow doesn't accept negative x, do manual checks here */
|
|
|
|
if(x < 0.0f) {
|
2013-05-16 17:20:56 +00:00
|
|
|
if(fmodf(-y, 2.0f) == 0.0f)
|
2012-12-19 21:17:16 +00:00
|
|
|
return powf(-x, y);
|
|
|
|
else
|
|
|
|
return -powf(-x, y);
|
|
|
|
}
|
|
|
|
else if(x == 0.0f)
|
|
|
|
return 0.0f;
|
2014-01-14 18:55:02 +00:00
|
|
|
#endif
|
2012-12-19 21:17:16 +00:00
|
|
|
return powf(x, y);
|
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device float safe_powf(float a, float b)
|
2012-12-19 21:17:16 +00:00
|
|
|
{
|
2014-05-04 17:49:22 +00:00
|
|
|
if(UNLIKELY(a < 0.0f && b != float_to_int(b)))
|
2012-12-19 21:17:16 +00:00
|
|
|
return 0.0f;
|
2014-01-14 18:55:02 +00:00
|
|
|
|
2012-12-19 21:17:16 +00:00
|
|
|
return compatible_powf(a, b);
|
|
|
|
}
|
|
|
|
|
2017-05-07 15:16:14 +00:00
|
|
|
ccl_device float safe_divide(float a, float b)
|
2012-12-19 21:17:16 +00:00
|
|
|
{
|
2017-05-07 15:16:14 +00:00
|
|
|
return (b != 0.0f)? a/b: 0.0f;
|
2012-12-19 21:17:16 +00:00
|
|
|
}
|
|
|
|
|
2017-05-07 15:16:14 +00:00
|
|
|
ccl_device float safe_logf(float a, float b)
|
2012-12-19 21:17:16 +00:00
|
|
|
{
|
2017-05-07 15:16:14 +00:00
|
|
|
if(UNLIKELY(a <= 0.0f || b <= 0.0f))
|
|
|
|
return 0.0f;
|
|
|
|
|
|
|
|
return safe_divide(logf(a),logf(b));
|
2012-12-19 21:17:16 +00:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:17:10 +00:00
|
|
|
ccl_device float safe_modulo(float a, float b)
|
2013-05-20 14:38:47 +00:00
|
|
|
{
|
|
|
|
return (b != 0.0f)? fmodf(a, b): 0.0f;
|
|
|
|
}
|
|
|
|
|
Cycles: Add multi-scattering, energy-conserving GGX as an option to the Glossy, Anisotropic and Glass BSDFs
This commit adds a new distribution to the Glossy, Anisotropic and Glass BSDFs that implements the
multiple-scattering microfacet model described in the paper "Multiple-Scattering Microfacet BSDFs with the Smith Model".
Essentially, the improvement is that unlike classical GGX, which only models single scattering and assumes
the contribution of multiple bounces to be zero, this new model performs a random walk on the microsurface until
the ray leaves it again, which ensures perfect energy conservation.
In practise, this means that the "darkening problem" - GGX materials becoming darker with increasing
roughness - is solved in a physically correct and efficient way.
The downside of this model is that it has no (known) analytic expression for evalation. However, it can be
evaluated stochastically, and although the correct PDF isn't known either, the properties of MIS and the
balance heuristic guarantee an unbiased result at the cost of slightly higher noise.
Reviewers: dingto, #cycles, brecht
Reviewed By: dingto, #cycles, brecht
Subscribers: bliblubli, ace_dragon, gregzaal, brecht, harvester, dingto, marcog, swerner, jtheninja, Blendify, nutel
Differential Revision: https://developer.blender.org/D2002
2016-06-23 20:56:43 +00:00
|
|
|
ccl_device_inline float beta(float x, float y)
|
|
|
|
{
|
|
|
|
#ifndef __KERNEL_OPENCL__
|
|
|
|
return expf(lgammaf(x) + lgammaf(y) - lgammaf(x+y));
|
|
|
|
#else
|
|
|
|
return expf(lgamma(x) + lgamma(y) - lgamma(x+y));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-03-23 11:55:51 +00:00
|
|
|
ccl_device_inline float xor_signmask(float x, int y)
|
|
|
|
{
|
|
|
|
return __int_as_float(__float_as_int(x) ^ y);
|
|
|
|
}
|
|
|
|
|
2014-07-29 10:07:05 +00:00
|
|
|
/* projections */
|
2015-02-19 07:52:48 +00:00
|
|
|
ccl_device_inline float2 map_to_tube(const float3 co)
|
2015-01-21 19:37:09 +00:00
|
|
|
{
|
2015-02-19 07:52:48 +00:00
|
|
|
float len, u, v;
|
|
|
|
len = sqrtf(co.x * co.x + co.y * co.y);
|
2015-03-27 19:15:15 +00:00
|
|
|
if(len > 0.0f) {
|
2015-02-19 07:52:48 +00:00
|
|
|
u = (1.0f - (atan2f(co.x / len, co.y / len) / M_PI_F)) * 0.5f;
|
2015-04-30 09:21:32 +00:00
|
|
|
v = (co.z + 1.0f) * 0.5f;
|
2015-01-21 19:37:09 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-02-19 07:52:48 +00:00
|
|
|
u = v = 0.0f;
|
2015-01-21 19:37:09 +00:00
|
|
|
}
|
2015-02-19 07:52:48 +00:00
|
|
|
return make_float2(u, v);
|
2015-01-21 19:37:09 +00:00
|
|
|
}
|
|
|
|
|
2015-02-19 07:52:48 +00:00
|
|
|
ccl_device_inline float2 map_to_sphere(const float3 co)
|
2014-07-29 10:07:05 +00:00
|
|
|
{
|
2015-02-19 07:52:48 +00:00
|
|
|
float l = len(co);
|
|
|
|
float u, v;
|
|
|
|
if(l > 0.0f) {
|
|
|
|
if(UNLIKELY(co.x == 0.0f && co.y == 0.0f)) {
|
|
|
|
u = 0.0f; /* othwise domain error */
|
2014-09-16 02:41:16 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-02-19 07:52:48 +00:00
|
|
|
u = (1.0f - atan2f(co.x, co.y) / M_PI_F) / 2.0f;
|
2014-09-16 02:41:16 +00:00
|
|
|
}
|
2015-02-19 07:52:48 +00:00
|
|
|
v = 1.0f - safe_acosf(co.z / l) / M_PI_F;
|
2014-07-29 10:07:05 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-02-19 07:52:48 +00:00
|
|
|
u = v = 0.0f;
|
2014-07-29 10:07:05 +00:00
|
|
|
}
|
2015-02-19 07:52:48 +00:00
|
|
|
return make_float2(u, v);
|
2014-07-29 10:07:05 +00:00
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|
|
|
|
|
|
|
|
#endif /* __UTIL_MATH_H__ */
|