Blender  V3.3
kernel/closure/volume.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #pragma once
5 
7 
8 /* VOLUME EXTINCTION */
9 
11 {
12  if (sd->flag & SD_EXTINCTION) {
13  sd->closure_transparent_extinction += weight;
14  }
15  else {
16  sd->flag |= SD_EXTINCTION;
17  sd->closure_transparent_extinction = weight;
18  }
19 }
20 
21 /* HENYEY-GREENSTEIN CLOSURE */
22 
23 typedef struct HenyeyGreensteinVolume {
25 
26  float g;
28 
29 static_assert(sizeof(ShaderClosure) >= sizeof(HenyeyGreensteinVolume),
30  "HenyeyGreensteinVolume is too large!");
31 
32 /* Given cosine between rays, return probability density that a photon bounces
33  * to that direction. The g parameter controls how different it is from the
34  * uniform sphere. g=0 uniform diffuse-like, g=1 close to sharp single ray. */
35 ccl_device float single_peaked_henyey_greenstein(float cos_theta, float g)
36 {
37  return ((1.0f - g * g) / safe_powf(1.0f + g * g - 2.0f * g * cos_theta, 1.5f)) *
38  (M_1_PI_F * 0.25f);
39 };
40 
42 {
44 
45  /* clamp anisotropy to avoid delta function */
46  volume->g = signf(volume->g) * min(fabsf(volume->g), 1.0f - 1e-3f);
47 
48  return SD_SCATTER;
49 }
50 
52  const float3 I,
53  float3 omega_in,
54  ccl_private float *pdf)
55 {
56  float g = svc->g;
57 
58  /* note that I points towards the viewer */
59  if (fabsf(g) < 1e-3f) {
60  *pdf = M_1_PI_F * 0.25f;
61  }
62  else {
63  float cos_theta = dot(-I, omega_in);
64  *pdf = single_peaked_henyey_greenstein(cos_theta, g);
65  }
66 
67  return make_float3(*pdf, *pdf, *pdf);
68 }
69 
71 henyey_greenstrein_sample(float3 D, float g, float randu, float randv, ccl_private float *pdf)
72 {
73  /* match pdf for small g */
74  float cos_theta;
75  bool isotropic = fabsf(g) < 1e-3f;
76 
77  if (isotropic) {
78  cos_theta = (1.0f - 2.0f * randu);
79  if (pdf) {
80  *pdf = M_1_PI_F * 0.25f;
81  }
82  }
83  else {
84  float k = (1.0f - g * g) / (1.0f - g + 2.0f * g * randu);
85  cos_theta = (1.0f + g * g - k * k) / (2.0f * g);
86  if (pdf) {
87  *pdf = single_peaked_henyey_greenstein(cos_theta, g);
88  }
89  }
90 
91  float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
92  float phi = M_2PI_F * randv;
93  float3 dir = make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cos_theta);
94 
95  float3 T, B;
96  make_orthonormals(D, &T, &B);
97  dir = dir.x * T + dir.y * B + dir.z * D;
98 
99  return dir;
100 }
101 
103  float3 I,
104  float3 dIdx,
105  float3 dIdy,
106  float randu,
107  float randv,
108  ccl_private float3 *eval,
109  ccl_private float3 *omega_in,
110  ccl_private float3 *domega_in_dx,
111  ccl_private float3 *domega_in_dy,
112  ccl_private float *pdf)
113 {
114  float g = svc->g;
115 
116  /* note that I points towards the viewer and so is used negated */
117  *omega_in = henyey_greenstrein_sample(-I, g, randu, randv, pdf);
118  *eval = make_float3(*pdf, *pdf, *pdf); /* perfect importance sampling */
119 
120 #ifdef __RAY_DIFFERENTIALS__
121  /* todo: implement ray differential estimation */
122  *domega_in_dx = make_float3(0.0f, 0.0f, 0.0f);
123  *domega_in_dy = make_float3(0.0f, 0.0f, 0.0f);
124 #endif
125 
126  return LABEL_VOLUME_SCATTER;
127 }
128 
129 /* VOLUME CLOSURE */
130 
132  ccl_private const ShaderVolumeClosure *svc,
133  float3 omega_in,
134  ccl_private float *pdf)
135 {
136  return volume_henyey_greenstein_eval_phase(svc, sd->I, omega_in, pdf);
137 }
138 
140  ccl_private const ShaderVolumeClosure *svc,
141  float randu,
142  float randv,
143  ccl_private float3 *eval,
144  ccl_private float3 *omega_in,
145  ccl_private differential3 *domega_in,
146  ccl_private float *pdf)
147 {
149  sd->I,
150  sd->dI.dx,
151  sd->dI.dy,
152  randu,
153  randv,
154  eval,
155  omega_in,
156  &domega_in->dx,
157  &domega_in->dy,
158  pdf);
159 }
160 
161 /* Volume sampling utilities. */
162 
163 /* todo: this value could be tweaked or turned into a probability to avoid
164  * unnecessary work in volumes and subsurface scattering. */
165 #define VOLUME_THROUGHPUT_EPSILON 1e-6f
166 
168 {
169  return exp(-sigma * t);
170 }
171 
172 ccl_device float volume_channel_get(float3 value, int channel)
173 {
174  return (channel == 0) ? value.x : ((channel == 1) ? value.y : value.z);
175 }
176 
178  float3 throughput,
179  float rand,
180  ccl_private float3 *pdf)
181 {
182  /* Sample color channel proportional to throughput and single scattering
183  * albedo, to significantly reduce noise with many bounce, following:
184  *
185  * "Practical and Controllable Subsurface Scattering for Production Path
186  * Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */
187  float3 weights = fabs(throughput * albedo);
188  float sum_weights = weights.x + weights.y + weights.z;
189 
190  if (sum_weights > 0.0f) {
191  *pdf = weights / sum_weights;
192  }
193  else {
194  *pdf = make_float3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f);
195  }
196 
197  if (rand < pdf->x) {
198  return 0;
199  }
200  else if (rand < pdf->x + pdf->y) {
201  return 1;
202  }
203  else {
204  return 2;
205  }
206 }
207 
MINLINE float signf(float f)
MINLINE float safe_sqrtf(float a)
MINLINE float safe_powf(float base, float exponent)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
#define sinf(x)
Definition: cuda/compat.h:102
#define cosf(x)
Definition: cuda/compat.h:101
#define ccl_device
Definition: cuda/compat.h:32
#define ccl_private
Definition: cuda/compat.h:48
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
ccl_device float3 volume_color_transmittance(float3 sigma, float t)
ccl_device int volume_phase_sample(ccl_private const ShaderData *sd, ccl_private const ShaderVolumeClosure *svc, float randu, float randv, ccl_private float3 *eval, ccl_private float3 *omega_in, ccl_private differential3 *domega_in, ccl_private float *pdf)
ccl_device int volume_henyey_greenstein_sample(ccl_private const ShaderVolumeClosure *svc, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, ccl_private float3 *eval, ccl_private float3 *omega_in, ccl_private float3 *domega_in_dx, ccl_private float3 *domega_in_dy, ccl_private float *pdf)
ccl_device int volume_henyey_greenstein_setup(ccl_private HenyeyGreensteinVolume *volume)
ccl_device float3 volume_phase_eval(ccl_private const ShaderData *sd, ccl_private const ShaderVolumeClosure *svc, float3 omega_in, ccl_private float *pdf)
struct HenyeyGreensteinVolume HenyeyGreensteinVolume
ccl_device float3 henyey_greenstrein_sample(float3 D, float g, float randu, float randv, ccl_private float *pdf)
CCL_NAMESPACE_BEGIN ccl_device void volume_extinction_setup(ccl_private ShaderData *sd, float3 weight)
ccl_device float single_peaked_henyey_greenstein(float cos_theta, float g)
ccl_device float volume_channel_get(float3 value, int channel)
ccl_device int volume_sample_channel(float3 albedo, float3 throughput, float rand, ccl_private float3 *pdf)
ccl_device float3 volume_henyey_greenstein_eval_phase(ccl_private const ShaderVolumeClosure *svc, const float3 I, float3 omega_in, ccl_private float *pdf)
@ CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID
@ SD_EXTINCTION
Definition: kernel/types.h:750
@ SD_SCATTER
Definition: kernel/types.h:752
ShaderData
Definition: kernel/types.h:925
@ LABEL_VOLUME_SCATTER
Definition: kernel/types.h:323
ShaderClosure
Definition: kernel/types.h:726
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
ccl_device_inline float3 exp(float3 v)
Definition: math_float3.h:392
#define T
#define B
#define fabsf(x)
Definition: metal/compat.h:219
#define make_float3(x, y, z)
Definition: metal/compat.h:204
T dot(const vec_base< T, Size > &a, const vec_base< T, Size > &b)
static const pxr::TfToken g("g", pxr::TfToken::Immortal)
#define I
#define min(a, b)
Definition: sort.c:35
float z
float y
float x
#define M_2PI_F
Definition: util/math.h:60
#define M_1_PI_F
Definition: util/math.h:43
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
Definition: util/math.h:566
BLI_INLINE float D(const float *data, const int res[3], int x, int y, int z)
Definition: voxel.c:13